Beispiel #1
0
def data(sceneid, band, overview_level, nodata, simplify):
    """Create footprint from data."""
    meta = _landsat_parse_scene_id(sceneid)
    landsat_prefix = os.path.join(LANDSAT_BUCKET, meta["key"])
    s3_path = f"{landsat_prefix}_B{band}.TIF"

    # INFO: we set GDAL_DISABLE_READDIR_ON_OPEN=False to make sure we fetch the ovr
    with rasterio.Env(GDAL_DISABLE_READDIR_ON_OPEN=False):
        with rasterio.open(s3_path) as src:
            if overview_level == 0:
                decim = 1
            else:
                decim = src.overviews(1)[overview_level - 1]

            with WarpedVRT(src, nodata=nodata) as vrt:
                feat = list(dataset_features(vrt, bidx=1, sampling=decim, band=False))[
                    0
                ]

                if simplify:
                    g = shape(feat["geometry"])
                    feat["geometry"] = mapping(g.simplify(0.01))

                geom = {"type": "FeatureCollection", "features": [feat]}
                click.echo(json.dumps(geom))
def test_landsat_id_pre_valid():
    """Parse landsat valid pre-collection sceneid and return metadata."""
    scene = "LC80300342017083LGN00"
    expected_content = {
        "acquisitionJulianDay": "083",
        "acquisitionYear": "2017",
        "archiveVersion": "00",
        "date": "2017-03-24",
        "groundStationIdentifier": "LGN",
        "key": "L8/030/034/LC80300342017083LGN00/LC80300342017083LGN00",
        "path": "030",
        "row": "034",
        "satellite": "8",
        "scene": "LC80300342017083LGN00",
        "sensor": "C",
    }

    assert landsat8._landsat_parse_scene_id(scene) == expected_content
Beispiel #3
0
def landsat_get_ang(sceneid):
    """Get Landsat-8 MTL metadata

    Attributes
    ----------

    sceneid : str
        Landsat sceneid. For scenes after May 2017,
        sceneid have to be LANDSAT_PRODUCT_ID.

    Returns
    -------
    out : dict
        returns a JSON like object with the metadata.
    """

    scene_params = _landsat_parse_scene_id(sceneid)
    s3_key = scene_params["key"]
    meta_file = f"http://landsat-pds.s3.amazonaws.com/{s3_key}_ANG.txt"
    metadata = str(urlopen(meta_file).read().decode())
    return _parse_ang_txt(metadata)
def tilejson_handler(
    event: Dict,
    sceneid: str,
    tile_format: str = "png",
    tile_scale: int = 1,
    **kwargs: Any,
) -> Tuple[str, str, str]:
    """Handle /tilejson.json requests."""
    # HACK
    token = event["multiValueQueryStringParameters"].get("access_token")
    if token:
        kwargs.update(dict(access_token=token[0]))

    qs = urllib.parse.urlencode(list(kwargs.items()))
    tile_url = (
        f"{APP.host}/tiles/{sceneid}/{{z}}/{{x}}/{{y}}@{tile_scale}x.{tile_format}?{qs}"
    )

    scene_params = landsat8._landsat_parse_scene_id(sceneid)
    landsat_address = f"{LANDSAT_BUCKET}/{scene_params['key']}_BQA.TIF"
    with rasterio.open(landsat_address) as src_dst:
        bounds = warp.transform_bounds(src_dst.crs,
                                       "epsg:4326",
                                       *src_dst.bounds,
                                       densify_pts=21)
        minzoom, maxzoom = get_zooms(src_dst)
        center = [(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2,
                  minzoom]

    meta = dict(
        bounds=bounds,
        center=center,
        minzoom=minzoom,
        maxzoom=maxzoom,
        name=sceneid,
        tilejson="2.1.0",
        tiles=[tile_url],
    )
    return ("OK", "application/json", json.dumps(meta))
def test_landsat_id_c1_valid():
    """Parse landsat valid collection1 sceneid and return metadata."""
    scene = "LC08_L1TP_005004_20170410_20170414_01_T1"
    expected_content = {
        "acquisitionDay": "10",
        "acquisitionMonth": "04",
        "acquisitionYear": "2017",
        "collectionCategory": "T1",
        "collectionNumber": "01",
        "date": "2017-04-10",
        "key": "c1/L8/005/004/LC08_L1TP_005004_20170410_\
20170414_01_T1/LC08_L1TP_005004_20170410_20170414_01_T1",
        "path": "005",
        "processingCorrectionLevel": "L1TP",
        "processingDay": "14",
        "processingMonth": "04",
        "processingYear": "2017",
        "row": "004",
        "satellite": "08",
        "scene": "LC08_L1TP_005004_20170410_20170414_01_T1",
        "sensor": "C",
    }

    assert landsat8._landsat_parse_scene_id(scene) == expected_content
def test_landsat_id_c1_invalid():
    """Raises error on invalid collection1 sceneid."""
    scene = "LC08_005004_20170410_20170414_01_T1"
    with pytest.raises(InvalidLandsatSceneId):
        landsat8._landsat_parse_scene_id(scene)
def test_landsat_id_pre_invalid():
    """Raises error on invalid pre-collection."""
    scene = "L0300342017083LGN00"
    with pytest.raises(InvalidLandsatSceneId):
        landsat8._landsat_parse_scene_id(scene)
def landsat8_tile(sceneid,
                  tile_x,
                  tile_y,
                  tile_z,
                  bands=("4", "3", "2"),
                  tilesize=256,
                  pan=False,
                  percents="",
                  **kwargs):
    """
    Create mercator tile from Landsat-8 data.

    Attributes
    ----------
    sceneid : str
        Landsat sceneid. For scenes after May 2017,
        sceneid have to be LANDSAT_PRODUCT_ID.
    tile_x : int
        Mercator tile X index.
    tile_y : int
        Mercator tile Y index.
    tile_z : int
        Mercator tile ZOOM level.
    bands : tuple, str, optional (default: ("4", "3", "2"))
        Bands index for the RGB combination.
    tilesize : int, optional (default: 256)
        Output image size.
    pan : boolean, optional (default: False)
        If True, apply pan-sharpening.
    kwargs: dict, optional
        These will be passed to the 'rio_tiler.utils._tile_read' function.

    Returns
    -------
    data : numpy ndarray
    mask: numpy array

    """
    if not isinstance(bands, tuple):
        bands = tuple((bands, ))

    for band in bands:
        if band not in LANDSAT_BANDS:
            raise InvalidBandName(
                "{} is not a valid Landsat band name".format(band))

    scene_params = landsat8._landsat_parse_scene_id(sceneid)
    meta_data = landsat8._landsat_get_mtl(sceneid).get("L1_METADATA_FILE")
    landsat_address = "{}/{}".format(LANDSAT_BUCKET, scene_params["key"])

    wgs_bounds = toa_utils._get_bounds_from_metadata(
        meta_data["PRODUCT_METADATA"])

    addresses = ["{}_B{}.TIF".format(landsat_address, band) for band in bands]

    values = []
    percents = percents.split(',')
    i = 0
    for address in addresses:
        with rasterio.open(address) as src:
            if int(percents[i]) != 0 and int(percents[i + 1]) != 100:
                overviews = src.overviews(1)
                if len(overviews) > 0:
                    d = src.read(
                        out_shape=(1,
                                   int(src.height /
                                       overviews[len(overviews) - 1]),
                                   int(src.width /
                                       overviews[len(overviews) - 1])))
                else:
                    d = src.read()

                dflatten = numpy.array(d.flatten())
                p_start, p_end = numpy.percentile(dflatten[dflatten > 0],
                                                  (int(percents[i]),
                                                   (int(percents[i + 1]))))
                values.append([p_start, p_end])
            else:
                values.append([None, None])
            i += 2

    if not utils.tile_exists(wgs_bounds, tile_z, tile_x, tile_y):
        # raise TileOutsideBounds(
        #     "Tile {}/{}/{} is outside image bounds".format(tile_z, tile_x, tile_y)
        # )
        return None, None

    mercator_tile = mercantile.Tile(x=tile_x, y=tile_y, z=tile_z)
    tile_bounds = mercantile.xy_bounds(mercator_tile)

    def _tiler(band):
        address = "{}_B{}.TIF".format(landsat_address, band)
        if band == "QA":
            nodata = 1
        else:
            nodata = 0

        return utils.tile_read(address,
                               bounds=tile_bounds,
                               tilesize=tilesize,
                               nodata=nodata,
                               **kwargs)

    with futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor:
        data, masks = zip(*list(executor.map(_tiler, bands)))
        mask = numpy.all(masks, axis=0).astype(numpy.uint8) * 255

    new_data = list(data)
    has_modification = False
    for ds in range(0, len(new_data)):
        if values[ds][0] is not None and values[ds][1] is not None:
            has_modification = True
            new_data[ds] = rescale_intensity(new_data[ds],
                                             in_range=(values[ds][0],
                                                       values[ds][1]),
                                             out_range=(0, 255))
    if has_modification == True:
        data = numpy.array(new_data).astype(numpy.uint8)

    data = numpy.concatenate(data)

    if pan:
        pan_address = "{}_B8.TIF".format(landsat_address)
        matrix_pan, mask = utils.tile_read(pan_address,
                                           tile_bounds,
                                           tilesize,
                                           nodata=0)
        data = utils.pansharpening_brovey(data, matrix_pan, 0.2,
                                          matrix_pan.dtype)

    sun_elev = meta_data["IMAGE_ATTRIBUTES"]["SUN_ELEVATION"]

    for bdx, band in enumerate(bands):
        if band in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:  # OLI
            multi_reflect = meta_data["RADIOMETRIC_RESCALING"].get(
                "REFLECTANCE_MULT_BAND_{}".format(band))

            add_reflect = meta_data["RADIOMETRIC_RESCALING"].get(
                "REFLECTANCE_ADD_BAND_{}".format(band))

            data[bdx] = 10000 * reflectance.reflectance(
                data[bdx], multi_reflect, add_reflect, sun_elev)

        elif band in ["10", "11"]:  # TIRS
            multi_rad = meta_data["RADIOMETRIC_RESCALING"].get(
                "RADIANCE_MULT_BAND_{}".format(band))

            add_rad = meta_data["RADIOMETRIC_RESCALING"].get(
                "RADIANCE_ADD_BAND_{}".format(band))

            k1 = meta_data["TIRS_THERMAL_CONSTANTS"].get(
                "K1_CONSTANT_BAND_{}".format(band))

            k2 = meta_data["TIRS_THERMAL_CONSTANTS"].get(
                "K2_CONSTANT_BAND_{}".format(band))

            data[bdx] = brightness_temp.brightness_temp(
                data[bdx], multi_rad, add_rad, k1, k2)

    return data, mask