def __init__(self, uri):
        try:
            if uri.startswith("s3://"):
                url = urlparse(uri)
                obj = S3.get_object(Bucket=url.netloc, Key=url.path[1:])
                oin_meta = json.loads(obj["Body"].read().decode("utf-8"))
            elif uri.startswith(("http://", "https://")):
                oin_meta = requests.get(uri).json()
            else:
                raise NoCatalogAvailable()
        except Exception:
            raise NoCatalogAvailable()

        self._meta = oin_meta
        self._metadata_url = uri
        self._name = oin_meta.get("title")
        self._provider = oin_meta.get("provider")
        self._source = oin_meta.get("uuid")

        with get_source(self._source) as src:
            self._bounds = warp.transform_bounds(src.crs, WGS84_CRS,
                                                 *src.bounds)
            self._resolution = get_resolution_in_meters(
                Bounds(src.bounds, src.crs), (src.height, src.width))
            approximate_zoom = get_zoom(max(self._resolution), op=math.ceil)

            if src.meta["dtype"] != "uint8":
                global_min = src.get_tag_item("TIFFTAG_MINSAMPLEVALUE")
                global_max = src.get_tag_item("TIFFTAG_MAXSAMPLEVALUE")

                for band in range(0, src.count):
                    self._meta["values"] = self._meta.get("values", {})
                    self._meta["values"][band] = {}
                    min_val = src.get_tag_item("STATISTICS_MINIMUM",
                                               bidx=band + 1)
                    max_val = src.get_tag_item("STATISTICS_MAXIMUM",
                                               bidx=band + 1)
                    mean_val = src.get_tag_item("STATISTICS_MEAN",
                                                bidx=band + 1)

                    if min_val is not None:
                        self._meta["values"][band]["min"] = float(min_val)
                    elif global_min is not None:
                        self._meta["values"][band]["min"] = float(global_min)

                    if max_val is not None:
                        self._meta["values"][band]["max"] = float(max_val)
                    elif global_max is not None:
                        self._meta["values"][band]["max"] = float(global_max)

                    if mean_val is not None:
                        self._meta["values"][band]["mean"] = float(mean_val)

        self._center = [
            (self._bounds[0] + self.bounds[2]) / 2,
            (self._bounds[1] + self.bounds[3]) / 2,
            approximate_zoom - 3,
        ]
        self._maxzoom = approximate_zoom + 3
        self._minzoom = approximate_zoom - 10
Example #2
0
    def __init__(self, uri):
        rsp = requests.get(uri)

        if not rsp.ok:
            raise NoDataAvailable()

        oin_meta = rsp.json()
        self._meta = oin_meta
        self._metadata_url = uri
        self._name = oin_meta.get('title')
        self._provider = oin_meta.get('provider')
        self._source = oin_meta.get('uuid')

        with get_source(self._source) as src:
            self._bounds = warp.transform_bounds(src.crs, WGS84_CRS,
                                                 *src.bounds)
            self._resolution = get_resolution_in_meters(
                Bounds(src.bounds, src.crs), (src.height, src.width))
            approximate_zoom = get_zoom(max(self._resolution), op=math.ceil)

        self._center = [(self._bounds[0] + self.bounds[2]) / 2,
                        (self._bounds[1] + self.bounds[3]) / 2,
                        approximate_zoom - 3]
        self._maxzoom = approximate_zoom + 3
        self._minzoom = approximate_zoom - 10
Example #3
0
    def sources_for_tile(tile):
        """Render a tile's source footprints."""
        bounds = Bounds(mercantile.xy_bounds(tile), WEB_MERCATOR_CRS)
        shape = Affine.scale(scale) * (256, 256)
        resolution = get_resolution_in_meters(bounds, shape)

        # convert sources to a list to avoid passing the generator across thread boundaries
        return (tile, list(catalog.get_sources(bounds, resolution)))
Example #4
0
    def __init__(self, uri, rgb=None, nodata=None, linear_stretch=None, resample=None):
        self._uri = uri

        if rgb:
            self._rgb = rgb

        if nodata:
            self._nodata = nodata

        if linear_stretch:
            self._linear_stretch = linear_stretch

        try:
            # test whether provided resampling method is valid
            Resampling[resample]
            self._resample = resample
        except KeyError:
            self._resample = None

        self._meta = {}

        with get_source(self._uri) as src:
            self._bounds = warp.transform_bounds(src.crs, WGS84_CRS, *src.bounds)
            self._resolution = get_resolution_in_meters(
                Bounds(src.bounds, src.crs), (src.height, src.width)
            )
            approximate_zoom = get_zoom(max(self._resolution), op=math.ceil)

            global_min = src.get_tag_item("TIFFTAG_MINSAMPLEVALUE")
            global_max = src.get_tag_item("TIFFTAG_MAXSAMPLEVALUE")

            for band in range(0, src.count):
                self._meta["values"] = self._meta.get("values", {})
                self._meta["values"][band] = {}
                min_val = src.get_tag_item("STATISTICS_MINIMUM", bidx=band + 1)
                max_val = src.get_tag_item("STATISTICS_MAXIMUM", bidx=band + 1)
                mean_val = src.get_tag_item("STATISTICS_MEAN", bidx=band + 1)

                if min_val is not None:
                    self._meta["values"][band]["min"] = float(min_val)
                elif global_min is not None:
                    self._meta["values"][band]["min"] = float(global_min)

                if max_val is not None:
                    self._meta["values"][band]["max"] = float(max_val)
                elif global_max is not None:
                    self._meta["values"][band]["max"] = float(global_max)

                if mean_val is not None:
                    self._meta["values"][band]["mean"] = float(mean_val)

        self._center = [
            (self._bounds[0] + self.bounds[2]) / 2,
            (self._bounds[1] + self.bounds[3]) / 2,
            approximate_zoom - 3,
        ]
        self._maxzoom = approximate_zoom + 3
        self._minzoom = approximate_zoom - 10
Example #5
0
def upstream_sources_for_tile(tile, catalog, min_zoom=None, max_zoom=None):
    """Render a tile's source footprints."""
    bounds = Bounds(mercantile.xy_bounds(tile), WEB_MERCATOR_CRS)
    shape = (512, 512)
    resolution = get_resolution_in_meters(bounds, shape)

    return catalog.get_sources(
        bounds,
        resolution,
        min_zoom=min_zoom,
        max_zoom=max_zoom,
        include_geometries=True,
    )
Example #6
0
    def transform(self, pixels):
        data, (bounds, crs), _ = pixels
        (count, height, width) = data.shape

        if count != 1:
            raise Exception("Can't produce normals from multiple bands")

        (dx, dy) = get_resolution_in_meters(pixels.bounds, (height, width))
        data = apply_latitude_adjustments(pixels).data[0]

        ygrad, xgrad = np.gradient(data, 2)
        img = np.dstack(
            (-1.0 / dx * xgrad, 1.0 / dy * ygrad, np.ones(data.shape)))

        # first, we normalise to unit vectors. this puts each element of img
        # in the range (-1, 1). the "einsum" stuff is serious black magic, but
        # what it (should be) saying is "for each i,j in the rows and columns,
        # the output is the sum of img[i,j,k]*img[i,j,k]" - i.e: the square.
        norm = np.sqrt(np.einsum('ijk,ijk->ij', img, img))

        # the norm is now the "wrong shape" according to numpy, so we need to
        # copy the norm value out into RGB components.
        norm_copy = norm[:, :, np.newaxis]

        # dividing the img by norm_copy should give us RGB components with
        # values between -1 and 1, but we need values between 0 and 255 for
        # PNG channels. so we move and scale the values to fit in that range.
        scaled = (128.0 * (img / norm_copy + 1.0))

        # and finally clip it to (0, 255) just in case
        img = np.clip(scaled, 0.0, 255.0).astype(np.uint8)

        # apply the height mapping function to get the table index.
        func = np.vectorize(_height_mapping_func)
        hyps = func(data).astype(np.uint8)

        # turn masked values transparent
        if data.mask.any():
            hyps[data.mask] = 0

        # Create output as a 4-channel RGBA image, each (byte) channel
        # corresponds to x, y, z, h where x, y and z are the respective
        # components of the normal, and h is an index into a hypsometric tint
        # table (see HEIGHT_TABLE).
        return PixelCollection(np.dstack((img, hyps)), pixels.bounds), "RGBA"
Example #7
0
    def transform(self, pixels):
        data, (bounds, crs), _ = pixels
        (count, height, width) = data.shape

        if count != 1:
            raise Exception("Can't hillshade from multiple bands")

        (dx, dy) = get_resolution_in_meters(pixels.bounds, (height, width))
        zoom = get_zoom(max(dx, dy))
        # invert resolutions for hillshading purposes
        dy *= -1

        data = apply_latitude_adjustments(pixels).data

        resample_factor = RESAMPLING.get(zoom, 1.0)
        aff = transform.from_bounds(*bounds, width=width, height=height)

        if self.resample and resample_factor != 1.0:
            # resample data according to Tom Paterson's chart

            # create an empty target array that's the shape of the resampled
            # tile (e.g. 80% of 260x260px)
            resampled_height = int(round(height * resample_factor))
            resampled_width = int(round(width * resample_factor))
            resampled = np.empty(
                shape=(resampled_height, resampled_width), dtype=data.dtype)
            resampled_mask = np.empty(shape=(resampled.shape))

            newaff = transform.from_bounds(
                *bounds, width=resampled_width, height=resampled_height)

            # downsample using GDAL's reprojection functionality (which gives
            # us access to different resampling algorithms)
            warp.reproject(
                data,
                resampled,
                src_transform=aff,
                dst_transform=newaff,
                src_crs=crs,
                dst_crs=crs,
                resampling=Resampling.bilinear, )

            # reproject / resample the mask so that intermediate operations
            # can also use it
            if np.any(data.mask):
                warp.reproject(
                    data.mask.astype(np.uint8),
                    resampled_mask,
                    src_transform=aff,
                    dst_transform=newaff,
                    src_crs=crs,
                    dst_crs=crs,
                    resampling=Resampling.nearest, )

                resampled = np.ma.masked_array(resampled, mask=resampled_mask)
            else:
                resampled = np.ma.masked_array(resampled)

            hs = _hillshade(
                resampled,
                dx=dx,
                dy=dy,
                vert_exag=EXAGGERATION.get(zoom, 1.0), )

            if self.add_slopeshade:
                ss = slopeshade(
                    resampled,
                    dx=dx,
                    dy=dy,
                    vert_exag=EXAGGERATION.get(zoom, 1.0))

                hs *= ss

            # scale hillshade values (0.0-1.0) to integers (0-255)
            hs = (255.0 * hs).astype(np.uint8)

            # create an empty target array that's the shape of the target tile
            # + buffers (e.g. 260x260px)
            resampled_hs = np.empty(shape=data.shape, dtype=hs.dtype)

            # upsample (invert the previous reprojection)
            warp.reproject(
                hs.data,
                resampled_hs,
                src_transform=newaff,
                dst_transform=aff,
                src_crs=crs,
                dst_crs=crs,
                resampling=Resampling.bilinear, )

            hs = np.ma.masked_array(resampled_hs, mask=data.mask)
        else:
            hs = _hillshade(
                data[0],
                dx=dx,
                dy=dy,
                vert_exag=EXAGGERATION.get(zoom, 1.0), )

            if self.add_slopeshade:
                ss = slopeshade(
                    data[0],
                    dx=dx,
                    dy=dy,
                    vert_exag=EXAGGERATION.get(zoom, 1.0))

                # hs *= 0.8
                hs *= ss

            hs = np.ma.masked_array(hs[np.newaxis], mask=data.mask)

            # scale hillshade values (0.0-1.0) to integers (0-255)
            hs = (255.0 * hs).astype(np.uint8)

        hs.fill_value = 0

        return PixelCollection(hs, pixels.bounds), "raw"
Example #8
0
    def __init__(self, uri, rgb=None, nodata=None, linear_stretch=None, resample=None, 
        dst_max=None, dst_min=None, force_cast=None, to_vis=None):
        self._uri = uri
        self._rgb = rgb
        self._nodata = nodata
        self._linear_stretch = linear_stretch
        self._dst_min = dst_min
        self._dst_max = dst_max
        self._force_cast = force_cast
        self._to_vis = to_vis
        try:
            # test whether provided resampling method is valid
            Resampling[resample]
            self._resample = resample
        except KeyError:
            self._resample = None
        self._meta = {}
        self.src_meta = {}

        with get_source(self._uri) as src:
            self.src_meta = snake_case_to_camel_case_keys_of_dict(src.tags())
            self.src_meta["bandCount"] = src.count
            self._bounds = warp.transform_bounds(src.crs, WGS84_CRS, *src.bounds)
            self._resolution = get_resolution_in_meters(
                Bounds(src.bounds, src.crs), (src.height, src.width)
            )
            approximate_zoom = get_zoom(max(self._resolution), op=math.ceil)
            
            global_min = src.get_tag_item("TIFFTAG_MINSAMPLEVALUE")
            global_max = src.get_tag_item("TIFFTAG_MAXSAMPLEVALUE")

            band_order = src.get_tag_item("BAND_ORDER")
            if band_order is not None:
                band_order = band_order.split(',')
            if str(self._rgb).lower() == "metadata":
                if band_order is not None:
                    def get_band_from_band_order(band_order, band_name, fallback):
                        if band_name in band_order:
                            return str(band_order.index(band_name) + 1)
                        else:
                            return fallback
                    red_band = get_band_from_band_order(band_order, "RED", "1")
                    green_band = get_band_from_band_order(band_order, "GRE", "2")
                    blue_band = get_band_from_band_order(band_order, "BLU", "3")
                    self._rgb = ",".join([red_band, green_band, blue_band])
                else:
                    # Fallback
                    if src.count >= 3:
                        self._rgb = "1,2,3"
                    else:
                        self._rgb = "1,1,1"
            
            self.src_meta["bandMetadata"] = {}
            # FarmLens specific
            band_assignments = band_order
            if band_order is None:
                band_assignments = range(0, src.count)
            for band in xrange(0, src.count):
                self.src_meta["bandMetadata"][band_assignments[band]] = snake_case_to_camel_case_keys_of_dict(src.tags(bidx=band+1))
                self._meta["values"] = self._meta.get("values", {})
                self._meta["values"][band] = {}
                min_val = src.get_tag_item("STATISTICS_MINIMUM", bidx=band + 1)
                max_val = src.get_tag_item("STATISTICS_MAXIMUM", bidx=band + 1)
                mean_val = src.get_tag_item("STATISTICS_MEAN", bidx=band + 1)
                stddev_val = src.get_tag_item("STATISTICS_STDDEV", bidx=band + 1)
                
                if min_val is not None:
                    self._meta["values"][band]["min"] = float(min_val)
                elif global_min is not None:
                    self._meta["values"][band]["min"] = float(global_min)

                if max_val is not None:
                    self._meta["values"][band]["max"] = float(max_val)
                elif global_max is not None:
                    self._meta["values"][band]["max"] = float(global_max)

                if mean_val is not None:
                    self._meta["values"][band]["mean"] = float(mean_val)

                if stddev_val is not None:
                    self._meta["values"][band]["stddev"] = float(stddev_val)

        self._center = [
            (self._bounds[0] + self.bounds[2]) / 2,
            (self._bounds[1] + self.bounds[3]) / 2,
            approximate_zoom - 3,
        ]
        self._maxzoom = approximate_zoom + 3
        self._minzoom = approximate_zoom - 10