Exemple #1
0
def test_expression_missing():
    """Should raise an exception on missing expression."""
    tile_z = 19
    tile_x = 109554
    tile_y = 200458
    prefix = os.path.join(os.path.dirname(__file__), "fixtures")
    sceneid = "{}/my-bucket/hro_sources/colorado/201404_13SED190110_201404_0x1500m_CL_1.tif".format(
        prefix)
    with pytest.raises(Exception):
        utils.expression(sceneid, tile_x, tile_y, tile_z, tilesize=512)
Exemple #2
0
def tile(
    scene: str,
    z: int,
    x: int,
    y: int,
    scale: int = 1,
    ext: str = "png",
    bands: str = None,
    percents: str = "",
    expr: str = None,
    rescale: str = None,
    color_formula: str = None,
    color_map: str = None,
) -> Tuple[str, str, BinaryIO]:
    """Handle tile requests."""
    driver = "jpeg" if ext == "jpg" else ext

    if bands and expr:
        raise CbersTilerError("Cannot pass bands and expression")

    tilesize = scale * 256

    if expr is not None:
        tile, mask = expression(scene, x, y, z, expr=expr, tilesize=tilesize)
    elif bands is not None:
        tile, mask = cbers_tile(scene,
                                x,
                                y,
                                z,
                                bands=tuple(bands.split(",")),
                                tilesize=tilesize,
                                percents=percents)
    else:
        raise CbersTilerError("No bands nor expression given")

    if tile is None or mask is None:
        return (
            "OK",
            f"image/png",
            b'',
        )

    rtile, rmask = _postprocess(tile,
                                mask,
                                rescale=None,
                                color_formula=color_formula)

    if color_map:
        color_map = get_colormap(color_map, format="gdal")

    options = img_profiles.get(driver, {})
    return (
        "OK",
        f"image/{ext}",
        array_to_image(rtile,
                       rmask,
                       img_format=driver,
                       color_map=color_map,
                       **options),
    )
Exemple #3
0
def ratio(scene, tile_z, tile_x, tile_y, tileformat):
    """Handle processing requests
    """
    if tileformat == 'jpg':
        tileformat = 'jpeg'

    query_args = APP.current_request.query_params
    query_args = query_args if isinstance(query_args, dict) else {}

    ratio_value = query_args['ratio']
    range_value = query_args.get('range', [-1, 1])

    tilesize = query_args.get('tile', 256)
    tilesize = int(tilesize) if isinstance(tilesize, str) else tilesize

    tile, mask = expression(scene,
                            tile_x,
                            tile_y,
                            tile_z,
                            ratio_value,
                            tilesize=tilesize)
    if len(tile.shape) == 2:
        tile = np.expand_dims(tile, axis=0)

    rtile = np.where(
        mask, linear_rescale(tile, in_range=range_value, out_range=[0, 255]),
        0).astype(np.uint8)
    img = array_to_img(rtile,
                       color_map=get_colormap(name='cfastie'),
                       mask=mask)
    str_img = b64_encode_img(img, tileformat)
    return ('OK', f'image/{tileformat}', str_img)
Exemple #4
0
def test_expression_main_ratio():
    """Should work as expected."""
    expr = "(b3 - b2) / (b3 + b2)"
    tile_z = 19
    tile_x = 109554
    tile_y = 200458

    prefix = os.path.join(os.path.dirname(__file__), "fixtures")
    sceneid = "{}/my-bucket/hro_sources/colorado/201404_13SED190110_201404_0x1500m_CL_1.tif".format(
        prefix)
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (1, 256, 256)
    mask.shape == (256, 256)

    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr=expr)
    data.shape == (1, 256, 256)
    mask.shape == (256, 256)
Exemple #5
0
def tile(
    scene,
    z,
    x,
    y,
    scale=1,
    ext="png",
    bands=None,
    expr=None,
    rescale=None,
    color_formula=None,
    color_map=None,
):
    """Handle tile requests."""
    if ext == "jpg":
        driver = "jpeg"
    elif ext == "jp2":
        driver = "JP2OpenJPEG"
    else:
        driver = ext

    if bands and expr:
        raise CbersTilerError("Cannot pass bands and expression")
    if not bands and not expr:
        raise CbersTilerError("Need bands or expression")

    if bands:
        bands = tuple(bands.split(","))

    tilesize = scale * 256

    if expr is not None:
        tile, mask = expression(scene, x, y, z, expr, tilesize=tilesize)
    elif bands is not None:
        tile, mask = cbers.tile(scene, x, y, z, bands=bands, tilesize=tilesize)

    rtile, rmask = _postprocess(tile,
                                mask,
                                tilesize,
                                rescale=rescale,
                                color_formula=color_formula)

    if color_map:
        color_map = get_colormap(color_map, format="gdal")

    options = img_profiles.get(driver, {})
    return (
        "OK",
        f"image/{ext}",
        array_to_image(rtile,
                       rmask,
                       img_format=driver,
                       color_map=color_map,
                       **options),
    )
def tile(
    z: int,
    x: int,
    y: int,
    scale: int = 1,
    ext: str = None,
    url: str = None,
    indexes: Union[str, Tuple[int]] = None,
    expr: str = None,
    nodata: Union[str, int, float] = None,
    rescale: str = None,
    color_formula: str = None,
    color_map: str = None,
) -> Tuple[str, str, BinaryIO]:
    """Handle tile requests."""
    driver = "jpeg" if ext == "jpg" else ext

    if indexes and expr:
        raise TilerError("Cannot pass indexes and expression")

    if not url:
        raise TilerError("Missing 'url' parameter")

    if isinstance(indexes, str):
        indexes = tuple(int(s) for s in re.findall(r"\d+", indexes))

    if nodata is not None:
        nodata = numpy.nan if nodata == "nan" else float(nodata)

    tilesize = scale * 256

    if expr is not None:
        tile, mask = expression(
            url, x, y, z, expr=expr, tilesize=tilesize, nodata=nodata
        )
    else:
        tile, mask = main.tile(
            url, x, y, z, indexes=indexes, tilesize=tilesize, nodata=nodata
        )

    rtile, rmask = _postprocess(
        tile, mask, rescale=rescale, color_formula=color_formula
    )

    if color_map:
        color_map = get_colormap(color_map, format="gdal")

    options = img_profiles.get(driver, {})
    return (
        "OK",
        f"image/{ext}",
        array_to_image(rtile, rmask, img_format=driver, color_map=color_map, **options),
    )
Exemple #7
0
def test_expression_main_kwargs():
    """
    Should work as expected
    """

    expr = '(b4 - b3) / (b4 + b3)'
    tile_z = 19
    tile_x = 109554
    tile_y = 200458

    prefix = os.path.join(os.path.dirname(__file__), 'fixtures')
    sceneid = '{}/my-bucket/hro_sources/colorado/201404_13SED190110_201404_0x1500m_CL_1_alpha.tif'.format(prefix)
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr, tilesize=512)
    data.shape == (1, 512, 512)
    mask.shape == (512, 512)
Exemple #8
0
def test_expression_main_rgb():
    """
    Should work as expected
    """

    expr = 'b1*0.8, b2*1.1, b3*0.8'
    tile_z = 19
    tile_x = 109554
    tile_y = 200458

    prefix = os.path.join(os.path.dirname(__file__), 'fixtures')
    sceneid = '{}/my-bucket/hro_sources/colorado/201404_13SED190110_201404_0x1500m_CL_1.tif'.format(prefix)
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (3, 256, 256)
    mask.shape == (256, 256)
Exemple #9
0
def test_expression_cbers_rgb(cbers_tile):
    """Should read tile from CBERS data."""
    cbers_tile.return_value = [
        np.random.randint(0, 255, size=(3, 256, 256), dtype=np.uint8),
        np.random.randint(0, 1, size=(256, 256), dtype=np.uint8) * 255,
    ]

    expr = "b8*0.8, b7*1.1, b6*0.8"
    tile_z = 10
    tile_x = 664
    tile_y = 495

    sceneid = "CBERS_4_MUX_20171121_057_094_L2"
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (3, 512, 512)
    mask.shape == (512, 512)
    assert len(cbers_tile.call_args[1].get("bands")) == 3
Exemple #10
0
def test_expression_landsat_rgb(landsat_tile):
    """Should work as expected."""
    landsat_tile.return_value = [
        np.random.randint(0, 255, size=(3, 256, 256), dtype=np.uint8),
        np.random.randint(0, 1, size=(256, 256), dtype=np.uint8) * 255,
    ]

    expr = "b5*0.8, b4*1.1, b3*0.8"
    tile_z = 8
    tile_x = 71
    tile_y = 102

    sceneid = "LC08_L1TP_016037_20170813_20170814_01_RT"
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (3, 512, 512)
    mask.shape == (512, 512)
    assert len(landsat_tile.call_args[1].get("bands")) == 3
Exemple #11
0
def test_expression_ndvi(landsat_tile):
    """Should work as expected"""
    landsat_tile.return_value = [
        np.random.randint(0, 255, size=(2, 256, 256), dtype=np.uint8),
        np.random.randint(0, 1, size=(256, 256), dtype=np.uint8) * 255,
    ]

    expr = "(b5 - b4) / (b5 + b4)"

    tile_z = 8
    tile_x = 71
    tile_y = 102

    sceneid = "LC08_L1TP_016037_20170813_20170814_01_RT"
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (1, 256, 256)
    mask.shape == (256, 256)
    assert len(landsat_tile.call_args[1].get("bands")) == 2
Exemple #12
0
def test_expression_sentinel2(sentinel2):
    """Should work as expected."""
    sentinel2.return_value = [
        np.random.randint(0, 255, size=(2, 256, 256), dtype=np.uint8),
        np.random.randint(0, 1, size=(256, 256), dtype=np.uint8) * 255,
    ]

    expr = "(b8A - b12) / (b8A + b12)"

    tile_z = 8
    tile_x = 71
    tile_y = 102

    sceneid = "S2A_tile_20170323_17SNC_0"
    data, mask = utils.expression(sceneid, tile_x, tile_y, tile_z, expr)
    data.shape == (1, 256, 256)
    mask.shape == (256, 256)
    assert sorted(list(sentinel2.call_args[1].get("bands"))) == ["12", "8A"]
Exemple #13
0
def tile_handler(
    z: int,
    x: int,
    y: int,
    scale: int = 1,
    ext: str = None,
    url: str = None,
    indexes: Union[str, Tuple[int]] = None,
    expr: str = None,
    nodata: Union[str, int, float] = None,
    rescale: str = None,
    color_formula: str = None,
    color_map: str = None,
) -> Tuple[str, str, BinaryIO]:
    """Handle /tiles requests."""
    if indexes and expr:
        raise TilerError("Cannot pass indexes and expression")

    if not url:
        raise TilerError("Missing 'url' parameter")

    if isinstance(indexes, str):
        indexes = tuple(int(s) for s in re.findall(r"\d+", indexes))

    if nodata is not None:
        nodata = numpy.nan if nodata == "nan" else float(nodata)

    tilesize = scale * 256
    if expr is not None:
        tile, mask = expression(
            url, x, y, z, expr=expr, tilesize=tilesize, nodata=nodata
        )
    else:
        tile, mask = cogTiler.tile(
            url, x, y, z, indexes=indexes, tilesize=tilesize, nodata=nodata
        )

    if not ext:
        ext = "jpg" if mask.all() else "png"

    rtile, rmask = _postprocess(
        tile, mask, rescale=rescale, color_formula=color_formula
    )

    if color_map:
        color_map = get_colormap(color_map, format="gdal")

    if ext == "jpg":
        driver = "jpeg"
    elif ext == "tif":
        driver = "GTiff"
    else:
        driver = ext

    options = img_profiles.get(driver, {})
    if driver == "GTiff":
        mercator_tile = mercantile.Tile(x=x, y=y, z=z)
        bounds = mercantile.xy_bounds(mercator_tile)
        w, s, e, n = bounds
        dst_transform = from_bounds(w, s, e, n, rtile.shape[1], rtile.shape[2])
        options = dict(
            dtype=rtile.dtype, crs={"init": "EPSG:3857"}, transform=dst_transform
        )

    return (
        "OK",
        f"image/{ext}",
        array_to_image(rtile, rmask, img_format=driver, color_map=color_map, **options),
    )
Exemple #14
0
    def get(self,
            request,
            pk=None,
            project_pk=None,
            tile_type="",
            z="",
            x="",
            y="",
            scale=1):
        """
        Get a tile image
        """
        task = self.get_and_check_task(request, pk)

        z = int(z)
        x = int(x)
        y = int(y)

        scale = int(scale)
        ext = "png"
        driver = "jpeg" if ext == "jpg" else ext

        indexes = None
        nodata = None

        formula = self.request.query_params.get('formula')
        bands = self.request.query_params.get('bands')
        rescale = self.request.query_params.get('rescale')
        color_map = self.request.query_params.get('color_map')
        hillshade = self.request.query_params.get('hillshade')

        if formula == '': formula = None
        if bands == '': bands = None
        if rescale == '': rescale = None
        if color_map == '': color_map = None
        if hillshade == '' or hillshade == '0': hillshade = None

        try:
            expr, _ = lookup_formula(formula, bands)
        except ValueError as e:
            raise exceptions.ValidationError(str(e))

        if tile_type in ['dsm', 'dtm'] and rescale is None:
            rescale = "0,1000"

        if tile_type in ['dsm', 'dtm'] and color_map is None:
            color_map = "gray"

        if tile_type == 'orthophoto' and formula is not None:
            if color_map is None:
                color_map = "gray"
            if rescale is None:
                rescale = "-1,1"

        if nodata is not None:
            nodata = np.nan if nodata == "nan" else float(nodata)
        tilesize = scale * 256

        url = get_raster_path(task, tile_type)

        if not os.path.isfile(url):
            raise exceptions.NotFound()

        with rasterio.open(url) as src:
            minzoom, maxzoom = get_zoom_safe(src)
            has_alpha = has_alpha_band(src)
            if z < minzoom - ZOOM_EXTRA_LEVELS or z > maxzoom + ZOOM_EXTRA_LEVELS:
                raise exceptions.NotFound()

            # Handle N-bands datasets for orthophotos (not plant health)
            if tile_type == 'orthophoto' and expr is None:
                ci = src.colorinterp

                # More than 4 bands?
                if len(ci) > 4:
                    # Try to find RGBA band order
                    if ColorInterp.red in ci and \
                        ColorInterp.green in ci and \
                        ColorInterp.blue in ci:
                        indexes = (
                            ci.index(ColorInterp.red) + 1,
                            ci.index(ColorInterp.green) + 1,
                            ci.index(ColorInterp.blue) + 1,
                        )
                    else:
                        # Fallback to first three
                        indexes = (
                            1,
                            2,
                            3,
                        )

                elif has_alpha:
                    indexes = non_alpha_indexes(src)

        resampling = "nearest"
        padding = 0
        if tile_type in ["dsm", "dtm"]:
            resampling = "bilinear"
            padding = 16

        try:
            if expr is not None:
                tile, mask = expression(url,
                                        x,
                                        y,
                                        z,
                                        expr=expr,
                                        tilesize=tilesize,
                                        nodata=nodata,
                                        tile_edge_padding=padding,
                                        resampling_method=resampling)
            else:
                tile, mask = main.tile(url,
                                       x,
                                       y,
                                       z,
                                       indexes=indexes,
                                       tilesize=tilesize,
                                       nodata=nodata,
                                       tile_edge_padding=padding,
                                       resampling_method=resampling)
        except TileOutsideBounds:
            raise exceptions.NotFound("Outside of bounds")

        if color_map:
            try:
                color_map = get_colormap(color_map, format="gdal")
            except FileNotFoundError:
                raise exceptions.ValidationError("Not a valid color_map value")

        intensity = None

        if hillshade is not None:
            try:
                hillshade = float(hillshade)
                if hillshade <= 0:
                    hillshade = 1.0
            except ValueError:
                raise exceptions.ValidationError("Invalid hillshade value")

            if tile.shape[0] != 1:
                raise exceptions.ValidationError(
                    "Cannot compute hillshade of non-elevation raster (multiple bands found)"
                )

            delta_scale = (maxzoom + ZOOM_EXTRA_LEVELS + 1 - z) * 4
            dx = src.meta["transform"][0] * delta_scale
            dy = -src.meta["transform"][4] * delta_scale

            ls = LightSource(azdeg=315, altdeg=45)

            # Hillshading is not a local tile operation and
            # requires neighbor tiles to be rendered seamlessly
            elevation = get_elevation_tiles(tile[0], url, x, y, z, tilesize,
                                            nodata, resampling, padding)
            intensity = ls.hillshade(elevation,
                                     dx=dx,
                                     dy=dy,
                                     vert_exag=hillshade)
            intensity = intensity[tilesize:tilesize * 2, tilesize:tilesize * 2]

        rgb, rmask = rescale_tile(tile, mask, rescale=rescale)
        rgb = apply_colormap(rgb, color_map)

        if intensity is not None:
            # Quick check
            if rgb.shape[0] != 3:
                raise exceptions.ValidationError(
                    "Cannot process tile: intensity image provided, but no RGB data was computed."
                )

            intensity = intensity * 255.0
            rgb = hsv_blend(rgb, intensity)

        options = img_profiles.get(driver, {})
        return HttpResponse(array_to_image(rgb,
                                           rmask,
                                           img_format=driver,
                                           **options),
                            content_type="image/{}".format(ext))
Exemple #15
0
def tile(
    z,
    x,
    y,
    scale=1,
    ext="png",
    url=None,
    indexes=None,
    expr=None,
    nodata=None,
    rescale=None,
    color_formula=None,
    color_map=None,
    dem=None,
):
    """Handle tile requests."""
    if ext == "jpg":
        driver = "jpeg"
    elif ext == "jp2":
        driver = "JP2OpenJPEG"
    else:
        driver = ext

    if indexes and expr:
        raise TilerError("Cannot pass indexes and expression")
    if not url:
        raise TilerError("Missing 'url' parameter")

    if indexes:
        indexes = tuple(int(s) for s in re.findall(r"\d+", indexes))

    tilesize = scale * 256

    if nodata is not None:
        nodata = numpy.nan if nodata == "nan" else float(nodata)

    if expr is not None:
        tile, mask = expression(url, x, y, z, expr, tilesize=tilesize)
    else:
        tile, mask = main.tile(url,
                               x,
                               y,
                               z,
                               indexes=indexes,
                               tilesize=tilesize)

    if dem:
        if dem == "mapbox":
            tile = encoders.data_to_rgb(tile, -10000, 1)
        elif dem == "mapzen":
            tile = mapzen_elevation_rgb.data_to_rgb(tile)
        else:
            return ("NOK", "text/plain", 'Invalid "dem" mode')
    else:
        rtile, rmask = _postprocess(tile,
                                    mask,
                                    tilesize,
                                    rescale=rescale,
                                    color_formula=color_formula)

        if color_map:
            color_map = get_colormap(color_map, format="gdal")

    options = img_profiles.get(driver, {})
    return (
        "OK",
        f"image/{ext}",
        array_to_image(rtile,
                       rmask,
                       img_format=driver,
                       color_map=color_map,
                       **options),
    )
Exemple #16
0
    def get(self,
            request,
            pk=None,
            project_pk=None,
            tile_type="",
            z="",
            x="",
            y="",
            scale=1):
        """
        Get a tile image
        """
        task = self.get_and_check_task(request, pk)

        z = int(z)
        x = int(x)
        y = int(y)

        if x == 0 and y == 0 and z == 0:
            raise exceptions.NotFound()

        scale = int(scale)
        ext = "png"
        driver = "jpeg" if ext == "jpg" else ext

        indexes = None
        nodata = None

        formula = self.request.query_params.get('formula')
        bands = self.request.query_params.get('bands')
        rescale = self.request.query_params.get('rescale')
        color_map = self.request.query_params.get('color_map')
        hillshade = self.request.query_params.get('hillshade')

        if formula == '': formula = None
        if bands == '': bands = None
        if rescale == '': rescale = None
        if color_map == '': color_map = None
        if hillshade == '' or hillshade == '0': hillshade = None

        try:
            expr, _ = lookup_formula(formula, bands)
        except ValueError as e:
            raise exceptions.ValidationError(str(e))

        if tile_type in ['dsm', 'dtm'] and rescale is None:
            rescale = "0,1000"

        if tile_type in ['dsm', 'dtm'] and color_map is None:
            color_map = "gray"

        if tile_type == 'orthophoto' and formula is not None:
            if color_map is None:
                color_map = "gray"
            if rescale is None:
                rescale = "-1,1"

        if nodata is not None:
            nodata = np.nan if nodata == "nan" else float(nodata)
        tilesize = scale * 256

        url = get_raster_path(task, tile_type)
        if not os.path.isfile(url):
            raise exceptions.NotFound()

        try:
            if expr is not None:
                tile, mask = expression(url,
                                        x,
                                        y,
                                        z,
                                        expr=expr,
                                        tilesize=tilesize,
                                        nodata=nodata)
            else:
                tile, mask = main.tile(url,
                                       x,
                                       y,
                                       z,
                                       indexes=indexes,
                                       tilesize=tilesize,
                                       nodata=nodata)
        except TileOutsideBounds:
            raise exceptions.NotFound("Outside of bounds")

        # Use alpha channel for transparency, don't use the mask if one is provided (redundant)
        if tile.shape[0] == 4:
            mask = None

        if color_map:
            try:
                color_map = get_colormap(color_map, format="gdal")
            except FileNotFoundError:
                raise exceptions.ValidationError("Not a valid color_map value")

        intensity = None

        if hillshade is not None:
            try:
                hillshade = float(hillshade)
                if hillshade <= 0:
                    hillshade = 1.0
                print(hillshade)
            except ValueError:
                raise exceptions.ValidationError("Invalid hillshade value")

            if tile.shape[0] != 1:
                raise exceptions.ValidationError(
                    "Cannot compute hillshade of non-elevation raster (multiple bands found)"
                )

            with rasterio.open(url) as src:
                minzoom, maxzoom = get_zooms(src)
                z_value = min(maxzoom, max(z, minzoom))
                delta_scale = (maxzoom + 1 - z_value) * 4
                dx = src.meta["transform"][0] * delta_scale
                dy = -src.meta["transform"][4] * delta_scale

            ls = LightSource(azdeg=315, altdeg=45)

            # Hillshading is not a local tile operation and
            # requires neighbor tiles to be rendered seamlessly
            elevation = get_elevation_tiles(tile[0], url, x, y, z, tilesize,
                                            nodata)
            intensity = ls.hillshade(elevation,
                                     dx=dx,
                                     dy=dy,
                                     vert_exag=hillshade)
            intensity = intensity[tilesize:tilesize * 2, tilesize:tilesize * 2]

        rgb, rmask = rescale_tile(tile, mask, rescale=rescale)
        rgb = apply_colormap(rgb, color_map)

        if intensity is not None:
            # Quick check
            if rgb.shape[0] != 3:
                raise exceptions.ValidationError(
                    "Cannot process tile: intensity image provided, but no RGB data was computed."
                )

            intensity = intensity * 255.0
            rgb = hsv_blend(rgb, intensity)

        options = img_profiles.get(driver, {})
        return HttpResponse(array_to_image(rgb,
                                           rmask,
                                           img_format=driver,
                                           **options),
                            content_type="image/{}".format(ext))