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
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
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)))
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
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, )
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"
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"
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