Module eoreader.products.optical.l7_product
Landsat-7 products
Expand source code
# -*- coding: utf-8 -*-
# Copyright 2021, SERTIT-ICube - France, https://sertit.unistra.fr/
# This file is part of eoreader project
# https://github.com/sertit/eoreader
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""" Landsat-7 products """
import logging
import geopandas as gpd
from eoreader.products.optical.landsat_product import LandsatProduct
from eoreader.utils import EOREADER_NAME
from sertit import rasters
LOGGER = logging.getLogger(EOREADER_NAME)
class L7Product(LandsatProduct):
"""Class of Landsat-7 Products"""
def _set_resolution(self) -> float:
"""
Set product default resolution (in meters)
"""
# DO NOT TAKE INTO ACCOUNT PAN AND TIRS RES
return 30.0
def _set_product_type(self) -> None:
"""Get products type"""
self._set_etm_product_type()
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.
```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)
Classes
class L7Product (product_path, archive_path=None, output_path=None)-
Class of Landsat-7 Products
Expand source code
class L7Product(LandsatProduct): """Class of Landsat-7 Products""" def _set_resolution(self) -> float: """ Set product default resolution (in meters) """ # DO NOT TAKE INTO ACCOUNT PAN AND TIRS RES return 30.0 def _set_product_type(self) -> None: """Get products type""" self._set_etm_product_type() 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. ```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)Ancestors
Instance variables
var output-
Inherited from:
LandsatProduct.outputOutput directory of the product, to write orthorectified data for example.
var name-
Inherited from:
LandsatProduct.nameProduct name (its filename without any extension).
var split_name-
Inherited from:
LandsatProduct.split_nameSplit name, to retrieve every information from its filename (dates, tile, product type…).
var archive_path-
Inherited from:
LandsatProduct.archive_pathArchive path, same as the product path if not specified. Useful when you want to know where both the extracted and archived version of your product …
var path-
Inherited from:
LandsatProduct.pathUsable path to the product, either extracted or archived path, according to the satellite.
var is_archived-
Inherited from:
LandsatProduct.is_archivedIs the archived product is processed (a products is considered as archived if its products path is a directory).
var needs_extraction-
Inherited from:
LandsatProduct.needs_extractionDoes this products needs to be extracted to be processed ? (
Trueby default). var date-
Inherited from:
LandsatProduct.dateAcquisition date.
var datetime-
Inherited from:
LandsatProduct.datetimeAcquisition datetime.
var tile_name-
Inherited from:
LandsatProduct.tile_nameTile if possible (for data that can be piled, for example S2 and Landsats).
var sensor_type-
Inherited from:
LandsatProduct.sensor_typeSensor type, SAR or optical.
var product_type-
Inherited from:
LandsatProduct.product_typeProduct type, satellite-related field, such as L1C or L2A for Sentinel-2 data.
var band_names-
Inherited from:
LandsatProduct.band_namesBand mapping between band wrapping names such as
GREENand band real number such as03for Sentinel-2. var is_reference-
Inherited from:
LandsatProduct.is_referenceIf the product is a reference, used for algorithms that need pre and post data, such as fire detection.
var corresponding_ref-
Inherited from:
LandsatProduct.corresponding_refThe corresponding reference products to the current one (if the product is not a reference but has a reference data corresponding to it). A list …
var nodata-
Inherited from:
LandsatProduct.nodataProduct nodata, set to 0 by default. Please do not touch this or all index will fail.
var platform-
Inherited from:
LandsatProduct.platformProduct platform, such as Sentinel-2
var resolution-
Inherited from:
LandsatProduct.resolutionDefault resolution in meters of the current product. For SAR product, we use Ground Range resolution as we will automatically orthorectify the tiles.
var condensed_name-
Inherited from:
LandsatProduct.condensed_nameCondensed name, the filename with only useful data to keep the name unique (ie.
20191215T110441_S2_30TXP_L2A_122756). Used to shorten names and paths. var sat_id-
Inherited from:
LandsatProduct.sat_idSatellite ID, i.e.
S2for Sentinel-2
Methods
def footprint(
self)
-
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.
>>> 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
Expand source code
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. ```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) def get_datetime(
self,
as_datetime=False)-
Inherited from:
LandsatProduct.get_datetimeGet the product's acquisition datetime, with format
YYYYMMDDTHHMMSS<->%Y%m%dT%H%M%S… def get_band_paths(
self,
band_list,
resolution=None)-
Inherited from:
LandsatProduct.get_band_pathsReturn the paths of required bands …
def read_mtd(
self,
force_pd=False)-
Inherited from:
LandsatProduct.read_mtdRead Landsat metadata as: …
def get_mean_sun_angles(
self)
-
Inherited from:
LandsatProduct.get_mean_sun_anglesGet Mean Sun angles (Azimuth and Zenith angles) …
def get_default_band(
self)
-
Inherited from:
LandsatProduct.get_default_bandGet default band:
GREENfor optical data as every optical satellite has a GREEN band … def get_default_band_path(
self)
-
Inherited from:
LandsatProduct.get_default_band_pathGet default band (
GREENfor optical data) path … def crs(
self)
-
Inherited from:
LandsatProduct.crsGet UTM projection of the tile …
def extent(
self)
-
Inherited from:
LandsatProduct.extentGet UTM extent of the tile …
def get_existing_bands(
self)
-
Inherited from:
LandsatProduct.get_existing_bandsReturn the existing band paths …
def get_existing_band_paths(
self)
-
Inherited from:
LandsatProduct.get_existing_band_pathsReturn the existing band paths …
def get_date(
self,
as_date=False)-
Inherited from:
LandsatProduct.get_dateGet the product's acquisition date …
def load(
self,
bands,
resolution=None,
size=None)-
Inherited from:
LandsatProduct.loadOpen the bands and compute the wanted index …
def has_band(
self,
band)-
Inherited from:
LandsatProduct.has_bandDoes this products has the specified band ? …
def stack(
self,
bands,
resolution=None,
stack_path=None,
save_as_int=False)-
Inherited from:
LandsatProduct.stackStack bands and index of a products …