Skip to content

Commit

Permalink
SLC -> GRD
Browse files Browse the repository at this point in the history
  • Loading branch information
adamjstewart committed Dec 6, 2022
1 parent 215c6f3 commit e4a42e9
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 31 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
27 changes: 13 additions & 14 deletions tests/data/sentinel1/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import numpy as np
import rasterio
from rasterio import Affine
from rasterio.crs import CRS

SIZE = 36

Expand All @@ -17,27 +18,25 @@
FILENAME_HIERARCHY = Union[Dict[str, "FILENAME_HIERARCHY"], List[str]]

filenames: FILENAME_HIERARCHY = {
# Copernicus Open Access Hub
"S1A_IW_SLC__1SDV_20221006T133300_20221006T133327_045322_056B2B_84A7.SAFE": {
"measurement": [
"s1a-iw1-slc-vh-20221006t133301-20221006t133327-045322-056b2b-001.tiff",
"s1a-iw1-slc-vv-20221006t133301-20221006t133327-045322-056b2b-004.tiff",
"s1a-iw2-slc-vh-20221006t133300-20221006t133325-045322-056b2b-002.tiff",
"s1a-iw2-slc-vv-20221006t133300-20221006t133325-045322-056b2b-005.tiff",
"s1a-iw3-slc-vh-20221006t133301-20221006t133326-045322-056b2b-003.tiff",
"s1a-iw3-slc-vv-20221006t133301-20221006t133326-045322-056b2b-006.tiff",
]
}
# ASF DAAC
"S1A_IW_20221204T161641_DVR_RTC30_G_gpuned_1AE1": [
"S1A_IW_20221204T161641_DVR_RTC30_G_gpuned_1AE1_VH.tif",
"S1A_IW_20221204T161641_DVR_RTC30_G_gpuned_1AE1_VV.tif",
],
"S1B_IW_20161021T042948_DHP_RTC30_G_gpuned_A784": [
"S1B_IW_20161021T042948_DHP_RTC30_G_gpuned_A784_HH.tif",
"S1B_IW_20161021T042948_DHP_RTC30_G_gpuned_A784_HV.tif",
],
}


def create_file(path: str) -> None:
profile = {}
profile["driver"] = "GTiff"
profile["dtype"] = "complex64"
profile["dtype"] = "float32"
profile["count"] = 1
profile["crs"] = None
profile["transform"] = Affine.identity()
profile["crs"] = CRS.from_epsg(32605)
profile["transform"] = Affine(30.0, 0.0, 79860.0, 0.0, -30.0, 2298240.0)
profile["height"] = SIZE
profile["width"] = SIZE

Expand Down
13 changes: 10 additions & 3 deletions tests/datasets/test_sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pytest
import torch
import torch.nn as nn
from _pytest.fixtures import SubRequest
from rasterio.crs import CRS

from torchgeo.datasets import (
Expand All @@ -20,11 +21,12 @@


class TestSentinel1:
@pytest.fixture
def dataset(self) -> Sentinel1:
@pytest.fixture(params=[("VV", "VH"), ("HH", "HV")])
def dataset(self, request: SubRequest) -> Sentinel1:
root = os.path.join("tests", "data", "sentinel1")
bands = request.param
transforms = nn.Identity()
return Sentinel1(root, transforms=transforms)
return Sentinel1(root, bands=bands, transforms=transforms)

def test_separate_files(self, dataset: Sentinel1) -> None:
assert dataset.index.count(dataset.index.bounds) == 1
Expand All @@ -43,6 +45,11 @@ def test_or(self, dataset: Sentinel1) -> None:
ds = dataset | dataset
assert isinstance(ds, UnionDataset)

def test_plot(self, dataset: Sentinel2) -> None:
x = dataset[dataset.bounds]
dataset.plot(x, suptitle="Test")
plt.close()

def test_no_data(self, tmp_path: Path) -> None:
with pytest.raises(FileNotFoundError, match="No Sentinel1 data was found in "):
Sentinel1(str(tmp_path))
Expand Down
136 changes: 122 additions & 14 deletions torchgeo/datasets/sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,103 @@ class Sentinel1(Sentinel):
constellation of two polar-orbiting satellites, operating day and night
performing C-band synthetic aperture radar imaging, enabling them to
acquire imagery regardless of the weather.
Data can be downloaded from:
* `Copernicus Open Access Hub
<https://scihub.copernicus.eu/>`_
* `Alaska Satellite Facility (ASF) Distributed Active Archive Center (DAAC)
<https://asf.alaska.edu/>`_
* `Microsoft's Planetary Computer
<https://planetarycomputer.microsoft.com/dataset/sentinel-1-rtc>`_
Product Types:
* `Level-0
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/product-types-processing-levels/level-0>`_:
Raw (RAW)
* `Level-1
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/product-types-processing-levels/level-1>`_:
Single Look Complex (SLC)
* `Level-1
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/product-types-processing-levels/level-1>`_:
Ground Range Detected (GRD)
* `Level-2
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/product-types-processing-levels/level-2>`_:
Ocean (OCN)
Polarizations:
* HH: horizontal transmit, horizontal receive
* HV: horizontal transmit, vertical receive
* VV: vertical transmit, vertical receive
* VH: vertical transmit, horizontal receive
Acquisition Modes:
* `Stripmap (SM)
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/acquisition-modes/stripmap>`_
* `Interferometric Wide (IW) swath
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/acquisition-modes/interferometric-wide-swath>`_
* `Extra Wide (EW) swatch
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/acquisition-modes/extra-wide-swath>`_
* `Wave (WV)
<https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/acquisition-modes/wave>`_
At the moment, this dataset only supports the GRD product type. Data must be
radiometrically terrain corrected (RTC). This can be done manually using a DEM, or
you can download an On Demand RTC product from ASF DAAC.
"""

# SAFE format
# https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/naming-conventions
# https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/document-library/-/asset_publisher/1dO7RF5fJMbd/content/sentinel-1-product-specification
filename_glob = "s1*{}.*"

# ASF DAAC GRD RTC uses a different naming scheme (README.md.txt in download):
#
# S1x_yy_aaaaaaaaTbbbbbb_ppo_RTCzz_u_defklm_ssss
#
# x: Sentinel-1 Mission (A or B)
# yy: Beam Mode
# aaaaaaaa: Start Date of Acquisition (YYYYMMDD)
# bbbbbb: Start Time of Acquisition (HHMMSS)
# pp: Polarization: Dual-pol (D) vs. Single-pol (S),
# primary polarization (H vs. V)
# o: Orbit Type: Precise (P), Restituted (R), or Original Predicted (O)
# zz: Terrain Correction Pixel Spacing
# u: Software Package Used: GAMMA (G)
# d: Gamma-0 (g) or Sigma-0 (s) Output
# e: Power (p) or Decibel (d) or Amplitude (a) Output
# f: Unmasked (u) or Water Masked (w)
# k: Not Filtered (n) or Filtered (f)
# l: Entire Area (e) or Clipped Area (c)
# m: Dead Reckoning (d) or DEM Matching (m)
# ssss: Product ID
filename_glob = "S1*{}.*"
filename_regex = r"""
^(?P<mission>s1[ab])
-(?P<swath>[a-z0-9]{3})
-(?P<product>slc|grd|ocn)
-(?P<polarization>[vh]{2})
-(?P<start_date>\d{8}t\d{6})
-(?P<stop_date>\d{8}t\d{6})
-(?P<orbit>\d{6})
-(?P<take>[0-9a-f]{6})
-(?P<band>00[1-6])
^S1(?P<mission>[AB])
_(?P<mode>SM|IW|EW|WV)
_(?P<date>\d{8}T\d{6})
_(?P<polarization>[DS][HV])
(?P<orbit>[PRO])
_RTC(?P<spacing>\d{2})
_(?P<package>G)
_(?P<output1>[gs])
(?P<output2>[pda])
(?P<mask>[uw])
(?P<filter>[nf])
(?P<area>[ec])
(?P<matching>[dm])
_(?P<product>[0-9A-Z]{4})
_(?P<band>[VH]{2})
\.
"""
date_format = "%Y%m%dt%H%M%S"
all_bands = ["001", "002", "003", "004", "005", "006"]
date_format = "%Y%m%dT%H%M%S"
all_bands = ["HH", "HV", "VV", "VH"]
separate_files = True

def __init__(
self,
root: str = "data",
crs: Optional[CRS] = None,
res: float = 10,
bands: Optional[Sequence[str]] = None,
bands: Sequence[str] = ["VV", "VH"],
transforms: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None,
cache: bool = True,
) -> None:
Expand All @@ -77,13 +147,51 @@ def __init__(
cache: if True, cache file handle to speed up repeated sampling
Raises:
AssertionError: if ``bands`` is invalid
FileNotFoundError: if no files are found in ``root``
"""
bands = bands or self.all_bands
# Sentinel-1 uses dual polarization, it can only transmit either
# horizontal or vertical at a single time
assert list(bands) == ["HH", "HV"] or list(bands) == ["VV", "VH"]

self.filename_glob = self.filename_glob.format(bands[0])

super().__init__(root, crs, res, bands, transforms, cache)

def plot(
self,
sample: Dict[str, Any],
show_titles: bool = True,
suptitle: Optional[str] = None,
) -> plt.Figure:
"""Plot a sample from the dataset.
Args:
sample: a sample returned by :meth:`RasterDataset.__getitem__`
show_titles: flag indicating whether to show titles above each panel
suptitle: optional string to use as a suptitle
Returns:
a matplotlib Figure with the rendered sample
"""
hh_vv = sample["image"][0]
hv_vh = sample["image"][1]

image = torch.stack((hh_vv, hv_vh, hh_vv / hv_vh), dim=-1)

fig, ax = plt.subplots(1, 1, figsize=(4, 4))

ax.imshow(image)
ax.axis("off")

if show_titles:
ax.set_title("Image")

if suptitle is not None:
plt.suptitle(suptitle)

return fig


class Sentinel2(Sentinel):
"""Sentinel-2 dataset.
Expand Down

0 comments on commit e4a42e9

Please sign in to comment.