question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Sentinel2 Class not behaving as expected

See original GitHub issue

Hello!

I am working with the Sentinel2 class. I have updated the class to deal with a different data format when downloaded from google cloud. (.SAFE data format, with Geo-JPEG2000 for the bands)

when trying to plot the individual bands, they are all coming out as identical, I am trying to get the individual bands to use in NDVI indice

class Sentinel(RasterDataset):
    """Abstract base class for all Sentinel datasets.

    `Sentinel <https://sentinel.esa.int/web/sentinel/home>`_ is a family of
    satellites launched by the `European Space Agency (ESA) <https://www.esa.int/>`_
    under the `Copernicus Programme <https://www.copernicus.eu/en>`_.

    If you use this dataset in your research, please cite it using the following format:

    * https://asf.alaska.edu/data-sets/sar-data-sets/sentinel-1/sentinel-1-how-to-cite/
    """


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

    The `Copernicus Sentinel-2 mission
    <https://sentinel.esa.int/web/sentinel/missions/sentinel-2>`_ comprises a
    constellation of two polar-orbiting satellites placed in the same sun-synchronous
    orbit, phased at 180° to each other. It aims at monitoring variability in land
    surface conditions, and its wide swath width (290 km) and high revisit time (10 days
    at the equator with one satellite, and 5 days with 2 satellites under cloud-free
    conditions which results in 2-3 days at mid-latitudes) will support monitoring of
    Earth's surface changes.
    """

    # TODO: files downloaded from USGS Earth Explorer seem to have a different
    # filename format than the official documentation
    # https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-2-msi/naming-convention
    # https://sentinel.esa.int/documents/247904/685211/Sentinel-2-MSI-L2A-Product-Format-Specifications.pdf
    filename_glob = "T*.jp2"
    # filename_regex = r"""
    #     ^T(?P<tile>\d{2}[A-Z]{3})
    #     _(?P<date>\d{8}T\d{6})
    #     _(?P<band>B[018][\dA])
    #     _(?P<resolution>\d{2}m)
    #     \..*$
    # """
    date_format = "%Y%m%dT%H%M%S"

    # https://gisgeography.com/sentinel-2-bands-combinations/
    all_bands = [
        "B01",
        "B02",
        "B03",
        "B04",
        "B05",
        "B06",
        "B07",
        "B08",
        "B8A",
        "B09",
        "B10",
        "B11",
        "B12",
    ]
    RGB_BANDS = ["B04", "B03", "B02"]

    separate_files = True
    def __init__(
        self,
        root: str = "data",
        crs: Optional[CRS] = None,
        res: Optional[float] = None,
        bands: Sequence[str] = [],
        transforms: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None,
        cache: bool = True,
    ) -> None:
        """Initialize a new Dataset instance.

        Args:
            root: root directory where dataset can be found
            crs: :term:`coordinate reference system (CRS)` to warp to
                (defaults to the CRS of the first file found)
            res: resolution of the dataset in units of CRS
                (defaults to the resolution of the first file found)
            bands: bands to return (defaults to all bands)
            transforms: a function/transform that takes an input sample
                and returns a transformed version
            cache: if True, cache file handle to speed up repeated sampling

        Raises:
            FileNotFoundError: if no files are found in ``root``
        """
        self.bands = bands if bands else self.all_bands

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


    def plot(  # type: ignore[override]
        self,
        sample: Dict[str, Tensor],
        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

            Raises:
                ValueError: if the RGB bands are not included in ``self.bands``

            .. versionadded:: 0.3
            """
            rgb_indices = []
            for band in self.RGB_BANDS:
                if band in self.bands:
                    rgb_indices.append(self.bands.index(band))
                else:
                    raise ValueError("Dataset doesn't contain some of the RGB bands")

            image = sample["image"][rgb_indices].permute(1, 2, 0)
            image = torch.clamp(image / 3000, min=0, max=1)  # type: ignore[attr-defined]

            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

I have two folders with jp2 band data

#path contains four .jp2 files for the four bands, path8 only contains band8
path = '/Users/gracecolverd/Documents/Fire_Proj/sentinel2/S2A_MSIL1C_20160911T092032_N0204_R093_T35UNU_20160911T092026.SAFE/GRANULE/L1C_T35UNU_A006382_20160911T092026/IMG_DATA'
path8 = '/Users/gracecolverd/Documents/Fire_Proj/sentinel2/S2A_MSIL1C_20160911T092032_N0204_R093_T35UNU_20160911T092026.SAFE/GRANULE/L1C_T35UNU_A006382_20160911T092026/IMG_DATA/b8'

when I try to look at individual bands they are all coming back the same

ds = Sentinel2(path, bands=['B02', 'B03' , 'B04', 'B08'])

sampler = RandomGeoSampler(ds, size=1024, length=1)
dl = DataLoader(ds, sampler=sampler, collate_fn=stack_samples)

fig, ax = plt.subplots(3, figsize = (10,10) )

for sample in dl:
      print('count')
      image = sample['image']
      print(image.shape)
      image = torch.squeeze(image)
      print(image)
      ax[0].imshow(image[0])
      ax[1].imshow(image[1])
      ax[2].imshow(image[2])

The image is tensor 4 deep as expected with the four bands, but all the tensors are the same

torch.Size([1, 4, 102, 102])
tensor([[[2473, 2428, 2356,  ..., 2941, 2987, 2998],
         [2337, 2431, 2436,  ..., 2873, 2901, 2962],
         [2364, 2485, 2395,  ..., 2831, 2910, 2945],
         ...,
         [2353, 2389, 2388,  ..., 2799, 2784, 2449],
         [2582, 2600, 2580,  ..., 2687, 2499, 1956],
         [2795, 2802, 2711,  ..., 2195, 1849, 1642]],

        [[2473, 2428, 2356,  ..., 2941, 2987, 2998],
         [2337, 2431, 2436,  ..., 2873, 2901, 2962],
         [2364, 2485, 2395,  ..., 2831, 2910, 2945],
         ...,
         [2353, 2389, 2388,  ..., 2799, 2784, 2449],
         [2582, 2600, 2580,  ..., 2687, 2499, 1956],
         [2795, 2802, 2711,  ..., 2195, 1849, 1642]],

        [[2473, 2428, 2356,  ..., 2941, 2987, 2998],
         [2337, 2431, 2436,  ..., 2873, 2901, 2962],
         [2364, 2485, 2395,  ..., 2831, 2910, 2945],
         ...,
         [2353, 2389, 2388,  ..., 2799, 2784, 2449],
         [2582, 2600, 2580,  ..., 2687, 2499, 1956],
         [2795, 2802, 2711,  ..., 2195, 1849, 1642]],

        [[2473, 2428, 2356,  ..., 2941, 2987, 2998],
         [2337, 2431, 2436,  ..., 2873, 2901, 2962],
         [2364, 2485, 2395,  ..., 2831, 2910, 2945],
         ...,
         [2353, 2389, 2388,  ..., 2799, 2784, 2449],
         [2582, 2600, 2580,  ..., 2687, 2499, 1956],
         [2795, 2802, 2711,  ..., 2195, 1849, 1642]]], dtype=torch.int32)

The image that is returned is New Note

I can’t attach the JP2 files but the files I used were B2, B3, B4, B8 from

S2A_MSIL1C_20160911T092032_N0204_R093_T35UNU_20160911T092026.SAFE

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8

github_iconTop GitHub Comments

1reaction
graceebc9commented, Mar 10, 2022

thanks! confirmed that the bands work in the order as expected -the issue was normalising. thanks also for the insights re. the indices - we’ve taken those onbord

1reaction
graceebc9commented, Mar 2, 2022

Thanks Adam!

all of the files are in the same directory - the filename_glob : filename_glob = “T*.jp2” catches them all

Today at 1555

Read more comments on GitHub >

github_iconTop Results From Across the Web

Read Sentinel-2 bands into R retrieves high values
I was wondering if SNAP is doing some conversion that I am not aware of to show values that range from 0 to...
Read more >
Sentinel-2 Products Specification Document
Section 2.8: clarified Level-2A product generation as required by PDR-RID-. 467/BK-02. Section 1.3: updated clarifying the list of the ...
Read more >
Copernicus Sentinel-2A Calibration and Products Validation ...
Of course, saturated pixels are detected before NUC computation and, for such pixels, the function is not applied. NUC function as well as...
Read more >
The Harmonized Landsat and Sentinel-2 surface reflectance ...
Sentinel -2 cloud mask is not optimal and is the main HLS v1.3 known issue. ... than can be obtained from a single...
Read more >
Sentinel-2 Cloud Masking with s2cloudless - Google Developers
Define collection filter and cloud mask parameters; Build a Sentinel-2 ... Tutorials contributed by the Earth Engine developer community are not part of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found