コード例 #1
0
    def _read_band(
        self,
        path: str,
        band: BandNames = None,
        resolution: Union[tuple, list, float] = None,
        size: Union[list, tuple] = None,
    ) -> XDS_TYPE:
        """
        Read band from disk.

        .. WARNING::
            Invalid pixels are not managed here

        Args:
            path (str): Band path
            band (BandNames): Band to read
            resolution (Union[tuple, list, float]): Resolution of the wanted band, in dataset resolution unit (X, Y)
            size (Union[tuple, list]): Size of the array (width, height). Not used if resolution is provided.
        Returns:
            XDS_TYPE: Band xarray

        """
        # Read band
        band_xda = rasters.read(path,
                                resolution=resolution,
                                size=size,
                                resampling=Resampling.bilinear)

        # Compute the correct radiometry of the band
        original_dtype = band_xda.encoding.get("dtype", band_xda.dtype)
        if original_dtype == "uint16":
            band_xda /= 10000.0

        return band_xda
コード例 #2
0
    def _preprocess_s3(self, resolution: float = None):
        """
        pre-process S3 bands (orthorectify...)

        Args:
            resolution (float): Resolution

        Returns:
            dict: Dictionary containing {band: path}
        """

        band_paths = {}

        # DIM in tmp files
        with tempfile.TemporaryDirectory() as tmp_dir:
            # out_dim = os.path.join(self.output, self.condensed_name + ".dim")  # DEBUG OPTION
            out_dim = os.path.join(tmp_dir, self.condensed_name + ".dim")

            # Run GPT graph
            processed_bands = self._run_s3_gpt_cli(out_dim, resolution)

            # Save all processed bands and quality flags into GeoTIFFs
            for snap_band_name in processed_bands:
                # Get standard band names
                band_name = self._get_band_filename(snap_band_name)

                # Remove tif if already existing
                # (if we are here, sth has failed when creating them, so delete them all)
                out_tif = os.path.join(self.output, band_name + ".tif")
                if os.path.isfile(out_tif):
                    files.remove(out_tif)

                # Convert to geotiffs and set no data with only keeping the first band
                arr = rasters.read(
                    rasters.get_dim_img_path(out_dim, snap_band_name))
                arr = arr.where(arr != self._snap_no_data, np.nan)
                rasters.write(arr, out_tif, dtype=np.float32)

        # Get the wanted bands (not the quality flags here !)
        for band in processed_bands:
            filename = self._get_band_filename(band)
            if "exception" not in filename:
                out_tif = os.path.join(self.output, filename + ".tif")
                if not os.path.isfile(out_tif):
                    raise FileNotFoundError(
                        f"Error when processing S3 bands with SNAP. Couldn't find {out_tif}"
                    )

                # Quality flags will crash here
                try:
                    band_paths[self._get_band_from_filename(
                        filename)] = out_tif
                except ValueError:
                    pass

        return band_paths
コード例 #3
0
    def footprint(self) -> gpd.GeoDataFrame:
        """
        Get real footprint of the products (without nodata, in french == emprise utile)

        .. WARNING::
            As Landsat 7 is broken (with nodata stripes all over the bands),
            the footprint is not easily computed and may take some time to be delivered.

        .. code-block:: python

            >>> from eoreader.reader import Reader
            >>> path = r"LC08_L1GT_023030_20200518_20200527_01_T2"
            >>> prod = Reader().open(path)
            >>> prod.footprint()
               index                                           geometry
            0      0  POLYGON ((366165.000 4899735.000, 366165.000 4...

        Overload of the generic function because landsat nodata seems to be different in QA than in regular bands.
        Indeed, nodata pixels vary according to the band sensor footprint,
        whereas QA nodata is where at least one band has nodata.

        We chose to keep QA nodata values for the footprint in order to show where all bands are valid.

        **TL;DR: We use the QA nodata value to determine the product's footprint**.

        Returns:
            gpd.GeoDataFrame: Footprint as a GeoDataFrame
        """
        LOGGER.warning(
            "Due to the Landsat-7 gaps, this function returns a rounded footprint on the corners. "
            "Sorry for the inconvenience.")

        # Read the file with a very low resolution -> use raster_rio that is faster !
        gap_msk = rasters.read(
            self._get_path(self._nodata_band_id),
            resolution=self.resolution * 50,
            masked=False,
        )

        # Vectorize the nodata band
        # Take the convex hull to discard the stripes of L7 to simplify the geometries
        footprint = rasters.vectorize(gap_msk,
                                      values=1,
                                      keep_values=False,
                                      dissolve=True)

        # Needs a dataframe to be dissolved
        footprint = footprint.convex_hull

        return gpd.GeoDataFrame(geometry=footprint.geometry, crs=footprint.crs)
コード例 #4
0
    def _read_band(
        self,
        path: str,
        resolution: Union[tuple, list, float] = None,
        size: Union[list, tuple] = None,
    ) -> XDS_TYPE:
        """
        Read band from a dataset.

        .. WARNING::
            Invalid pixels are not managed here !

        Args:
            path (str): Band path
            resolution (Union[tuple, list, float]): Resolution of the wanted band, in dataset resolution unit (X, Y)
            size (Union[tuple, list]): Size of the array (width, height). Not used if resolution is provided.
        Returns:
            XDS_TYPE: Radiometrically coherent band, saved as float 32 and its metadata

        """
        # Get band name: the last number of the filename:
        # ie: 'LC08_L1TP_200030_20191218_20191226_01_T1_B1'
        if self.is_archived:
            filename = files.get_filename(path.split("!")[-1])
        else:
            filename = files.get_filename(path)

        band_name = filename[-1]
        if self._quality_id in filename or self._nodata_band_id in filename:
            band = rasters.read(
                path,
                resolution=resolution,
                size=size,
                resampling=Resampling.nearest,  # NEAREST TO KEEP THE FLAGS
                masked=False,
            ).astype(np.uint16)
        else:
            # Read band (call superclass generic method)
            band = rasters.read(path,
                                resolution=resolution,
                                size=size,
                                resampling=Resampling.bilinear).astype(
                                    np.float32)

            # Open mtd
            mtd_data = self.read_mtd(force_pd=True)

            # Get band nb and corresponding coeff
            c_mul_str = "REFLECTANCE_MULT_BAND_" + band_name
            c_add_str = "REFLECTANCE_ADD_BAND_" + band_name

            # Get coeffs to convert DN to reflectance
            c_mul = mtd_data[c_mul_str].value
            c_add = mtd_data[c_add_str].value

            # Manage NULL values
            try:
                c_mul = float(c_mul)
            except ValueError:
                c_mul = 1
            try:
                c_add = float(c_add)
            except ValueError:
                c_add = 0

            # Compute the correct radiometry of the band and set no data to 0
            band = c_mul * band + c_add  # Already in float

        return band