Example #1
0
    def _reproject(self, eopatch, src_raster):
        """
        Reprojects the raster data from Geopedia's CRS (POP_WEB) to EOPatch's CRS.
        """
        height, width = src_raster.shape

        dst_raster = np.ones((height, width), dtype=self.raster_dtype)

        src_bbox = transform_bbox(eopatch.bbox, CRS.POP_WEB)
        src_transform = transform.from_bounds(*src_bbox,
                                              width=width,
                                              height=height)

        dst_bbox = eopatch.bbox
        dst_transform = transform.from_bounds(*dst_bbox,
                                              width=width,
                                              height=height)

        warp.reproject(src_raster,
                       dst_raster,
                       src_transform=src_transform,
                       src_crs={'init': CRS.ogc_string(CRS.POP_WEB)},
                       src_nodata=0,
                       dst_transform=dst_transform,
                       dst_crs={'init': CRS.ogc_string(eopatch.bbox.crs)},
                       dst_nodata=self.no_data_val)

        return dst_raster
Example #2
0
def get_vrt_transform(
    src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT],
    bounds: Tuple[float, float, float, float],
    height: Optional[int] = None,
    width: Optional[int] = None,
    dst_crs: CRS = constants.WEB_MERCATOR_CRS,
) -> Tuple[Affine, int, int]:
    """
    Calculate VRT transform.

    Attributes
    ----------
    src_dst : rasterio.io.DatasetReader
        Rasterio io.DatasetReader object
    bounds : list
        Bounds (left, bottom, right, top) in target crs ("dst_crs").
    height : int, optional
        Desired output height of the array for the bounds.
    width : int, optional
        Desired output width of the array for the bounds.
    dst_crs: CRS or str, optional
        Target coordinate reference system (default "epsg:3857").

    Returns
    -------
    vrt_transform: Affine
        Output affine transformation matrix
    vrt_width, vrt_height: int
        Output dimensions

    """
    dst_transform, _, _ = calculate_default_transform(
        src_dst.crs, dst_crs, src_dst.width, src_dst.height, *src_dst.bounds
    )
    w, s, e, n = bounds

    if not height or not width:
        vrt_width = math.ceil((e - w) / dst_transform.a)
        vrt_height = math.ceil((s - n) / dst_transform.e)
        vrt_transform = from_bounds(w, s, e, n, vrt_width, vrt_height)
        return vrt_transform, vrt_width, vrt_height

    tile_transform = from_bounds(w, s, e, n, width, height)
    w_res = (
        tile_transform.a
        if abs(tile_transform.a) < abs(dst_transform.a)
        else dst_transform.a
    )
    h_res = (
        tile_transform.e
        if abs(tile_transform.e) < abs(dst_transform.e)
        else dst_transform.e
    )

    vrt_width = math.ceil((e - w) / w_res)
    vrt_height = math.ceil((s - n) / h_res)
    vrt_transform = from_bounds(w, s, e, n, vrt_width, vrt_height)

    return vrt_transform, vrt_width, vrt_height
Example #3
0
    def test_arr(self):
        img_first = Image(TEST_FILE, dimorder="first")
        img_first.mask(box(11.9027457562112939, 51.4664152338322580, 11.9477435281016131, 51.5009522690838750,))
        self.assertEqual(img_first.arr.shape, (1, 385, 502))
        self.assertEqual(
            str(img_first.dataset.transform),
            str(
                from_bounds(
                    11.9027457562112939,
                    51.4664152338322580,
                    11.9477435281016131,
                    51.5009522690838750,
                    img_first.arr.shape[2],
                    img_first.arr.shape[1],
                )
            ),
        )
        img_first.close()

        img_last = Image(TEST_FILE, dimorder="last")
        img_last.mask(box(11.9027457562112939, 51.4664152338322580, 11.9477435281016131, 51.5009522690838750,))
        self.assertEqual(img_last.arr.shape, (385, 502, 1))
        self.assertEqual(
            str(img_last.dataset.transform),
            str(
                from_bounds(
                    11.9027457562112939,
                    51.4664152338322580,
                    11.9477435281016131,
                    51.5009522690838750,
                    img_last.arr.shape[1],
                    img_last.arr.shape[0],
                )
            ),
        )
        img_last.close()

        img_first = Image(
            np.ones((1, 385, 502)), dimorder="first", crs=self.img.dataset.crs, transform=self.img.dataset.transform
        )
        self.assertEqual(img_first.arr.shape, (1, 385, 502))
        img_first.close()

        img_last = Image(
            np.ones((385, 502, 1)), dimorder="last", crs=self.img.dataset.crs, transform=self.img.dataset.transform
        )
        self.assertEqual(img_last.arr.shape, (385, 502, 1))
        img_last.close()
Example #4
0
def get_vrt_transform(
    src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT],
    bounds: Tuple[float, float, float, float],
    height: Optional[int] = None,
    width: Optional[int] = None,
    dst_crs: CRS = WEB_MERCATOR_CRS,
) -> Tuple[Affine, int, int]:
    """Calculate VRT transform.

    Args:
        src_dst (rasterio.io.DatasetReader or rasterio.io.DatasetWriter or rasterio.vrt.WarpedVRT): Rasterio dataset.
        bounds (tuple): Bounding box coordinates in target crs (**dst_crs**).
        height (int, optional): Desired output height of the array for the input bounds.
        width (int, optional): Desired output width of the array for the input bounds.
        dst_crs (rasterio.crs.CRS, optional): Target Coordinate Reference System. Defaults to `epsg:3857`.

    Returns:
        tuple: VRT transform (affine.Affine), width (int) and height (int)

    """
    dst_transform, _, _ = calculate_default_transform(
        src_dst.crs, dst_crs, src_dst.width, src_dst.height, *src_dst.bounds
    )
    w, s, e, n = bounds

    if not height or not width:
        vrt_width = math.ceil((e - w) / dst_transform.a)
        vrt_height = math.ceil((s - n) / dst_transform.e)
        vrt_transform = from_bounds(w, s, e, n, vrt_width, vrt_height)
        return vrt_transform, vrt_width, vrt_height

    tile_transform = from_bounds(w, s, e, n, width, height)
    w_res = (
        tile_transform.a
        if abs(tile_transform.a) < abs(dst_transform.a)
        else dst_transform.a
    )
    h_res = (
        tile_transform.e
        if abs(tile_transform.e) < abs(dst_transform.e)
        else dst_transform.e
    )

    vrt_width = math.ceil((e - w) / w_res)
    vrt_height = math.ceil((s - n) / h_res)
    vrt_transform = from_bounds(w, s, e, n, vrt_width, vrt_height)

    return vrt_transform, vrt_width, vrt_height
Example #5
0
def _calculate_default_transform(src_crs: Union[Dict[str, str], str],
                                 _TARGET_CRS: Union[Dict[str, str], str],
                                 width: int, height: int,
                                 *bounds: Number) -> Tuple[Affine, int, int]:
    """A more stable version of GDAL's default transform.

    Ensures that the number of pixels along the image's shortest diagonal remains
    the same in both CRS, without enforcing square pixels.

    Bounds are in order (west, south, east, north).
    """
    from rasterio import warp, transform

    if len(bounds) != 4:
        raise ValueError('Bounds must contain 4 values')

    if src_crs is None:
        src_crs = _TARGET_CRS

    # transform image corners to target CRS
    dst_corner_sw, dst_corner_nw, dst_corner_se, dst_corner_ne = (list(
        zip(*warp.transform(src_crs, _TARGET_CRS,
                            [bounds[0], bounds[0], bounds[2], bounds[2]],
                            [bounds[1], bounds[3], bounds[1], bounds[3]]))))

    # determine inner bounding box of corners in target CRS
    dst_corner_bounds = [
        max(dst_corner_sw[0], dst_corner_nw[0]),
        max(dst_corner_sw[1], dst_corner_se[1]),
        min(dst_corner_se[0], dst_corner_ne[0]),
        min(dst_corner_nw[1], dst_corner_ne[1])
    ]

    # compute target resolution
    dst_corner_transform = transform.from_bounds(*dst_corner_bounds,
                                                 width=width,
                                                 height=height)
    target_res = (dst_corner_transform.a, dst_corner_transform.e)

    # get transform spanning whole bounds (not just projected corners)
    dst_bounds = warp.transform_bounds(src_crs, _TARGET_CRS, *bounds)
    dst_width = math.ceil((dst_bounds[2] - dst_bounds[0]) / target_res[0])
    dst_height = math.ceil((dst_bounds[1] - dst_bounds[3]) / target_res[1])
    dst_transform = transform.from_bounds(*dst_bounds,
                                          width=dst_width,
                                          height=dst_height)

    return dst_transform, dst_width, dst_height
Example #6
0
 def transform(self):
     """Returns the affine transform."""
     return (
         from_bounds(*self.bounds, self.width, self.height)
         if self.bounds
         else Affine.scale(self.width, -self.height)
     )
def test_array_bounds():
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        w, s, e, n = src.bounds
        height = src.height
        width = src.width
        tr = transform.from_bounds(w, s, e, n, src.width, src.height)
    assert (w, s, e, n) == transform.array_bounds(height, width, tr)
def save_tile_mask(labels_poly, tile_poly, xyz, tile_size, save_path='', prefix='', display=False, greyscale=True):
    x, y, z = xyz
    img_save_path = f'{save_path}/{prefix}{z}_{x}_{y}.png'
    if os.path.exists(img_save_path):
        return
    
    # get affine transformation matrix for this tile using rasterio.transform.from_bounds: https://rasterio.readthedocs.io/en/stable/api/rasterio.transform.html#rasterio.transform.from_bounds
    tfm = from_bounds(*tile_poly.bounds, tile_size, tile_size) 

    # crop geometries to what overlaps our tile polygon bounds
    cropped_polys = [poly for poly in labels_poly if poly.intersects(tile_poly)]
    cropped_polys_gdf = gpd.GeoDataFrame(geometry=cropped_polys, crs='epsg:4326')

    # burn a footprint/boundary/contact 3-channel mask with solaris: https://solaris.readthedocs.io/en/latest/tutorials/notebooks/api_masks_tutorial.html
    fbc_mask = sol.vector.mask.df_to_px_mask(df=cropped_polys_gdf,
                                             channels=['footprint', 'boundary', 'contact'],
                                             affine_obj=tfm,
                                             shape=(tile_size, tile_size),
                                             boundary_width=5,
                                             boundary_type='inner',
                                             contact_spacing=5,
                                             meters=True)

    if display:
        plt.imshow(fbc_mask)
        plt.show()
  
    if greyscale:
        skimage.io.imsave(img_save_path, fbc_mask[:,:,0], check_contrast=False) 
    else:
        skimage.io.imsave(img_save_path, fbc_mask, check_contrast=False) 
Example #9
0
def geotiff_options(
    x: int,
    y: int,
    z: int,
    tilesize: int = 256,
    dst_crs: CRS = constants.WEB_MERCATOR_CRS,
) -> Dict:
    """
    GeoTIFF options.

    Attributes
    ----------
        x : int
            Mercator tile X index.
        y : int
            Mercator tile Y index.
        z : int
            Mercator tile ZOOM level.
        tilesize : int, optional
            Output tile size. Default is 256.
        dst_crs: CRS, optional
            Target coordinate reference system, default is "epsg:3857".

    Returns
    -------
        dict

    """
    bounds = mercantile.xy_bounds(mercantile.Tile(x=x, y=y, z=z))
    dst_transform = from_bounds(*bounds, tilesize, tilesize)
    return dict(crs=dst_crs, transform=dst_transform)
Example #10
0
def burn_single(tile, feature, size, multicolors):
    bounds = mercantile.xy_bounds(tile)
    transform = from_bounds(*bounds, size, size)

    return rasterize(feature_to_mercator(feature),
                     out_shape=(size, size),
                     transform=transform)
Example #11
0
    def write_raster(self, fname='output', epsg=None):
        try:
            import rasterio
            from rasterio import transform
        except ImportError:
            print('This method requires Rasterio')
            return

        tfm = transform.from_bounds(self.xmin, self.ymin, self.xmax, self.ymax,
                                    self.ncol, self.nrow)
        if epsg is not None:
            crs = {'init': 'epsg:{}'.format(epsg)}
        else:
            crs = None

        with rasterio.drivers():
            with rasterio.open(fname,
                               'w',
                               driver='GTiff',
                               width=self.ncol,
                               height=self.nrow,
                               count=1,
                               dtype=np.float64,
                               nodata=0,
                               transform=tfm,
                               crs=crs) as dst:
                dst.write_band(1, np.flipud(self.data))
Example #12
0
def get_vrt_transform(src, bounds, bounds_crs='epsg:3857'):
    """Calculate VRT transform.
    Attributes
    ----------
    src : rasterio.io.DatasetReader
        Rasterio io.DatasetReader object
    bounds : list
        Bounds (left, bottom, right, top)
    bounds_crs : str
        Coordinate reference system string (default "epsg:3857")
    Returns
    -------
    vrt_transform: Affine
        Output affine transformation matrix
    vrt_width, vrt_height: int
        Output dimensions
    """
    dst_transform, _, _ = calculate_default_transform(src.crs, bounds_crs,
                                                      src.width, src.height,
                                                      *src.bounds)
    w, s, e, n = bounds
    vrt_width = math.ceil((e - w) / dst_transform.a)
    vrt_height = math.ceil((s - n) / dst_transform.e)

    vrt_transform = transform.from_bounds(w, s, e, n, vrt_width, vrt_height)

    return vrt_transform, vrt_width, vrt_height
Example #13
0
def get_transform(
    geometry: Union[Polygon, MultiPolygon, Tuple[float, float, float, float]],
    width: int,
    height: int,
) -> affine.Affine:
    """Get transform of a Polygon or bounding box.

    Parameters
    ----------
    geometry : Polygon, MultiPolygon, or tuple of float
        The geometry or the bounding box, (west, south, east, north).
    width: int
        The width of the target raster in pixels.
    height: int
        The height of the target raster in pixels.

    Returns
    -------
    affin.Affine
        The affine transform of the geometry.
    """
    if isinstance(geometry, (Polygon, MultiPolygon)):
        west, south, east, north = geometry.bounds
    elif isinstance(geometry, tuple) and len(geometry) == 4:
        west, south, east, north = geometry
    else:
        raise InvalidInputType(
            "geometry", "Polygon, MultiPolygon, or (west, south, east, north)")

    return rio_transform.from_bounds(west, south, east, north, width, height)
Example #14
0
def test_identity_gcps():
    """Define an identity transform using GCPs"""
    # Tile: [53, 96, 8]
    src_crs = dst_crs = 'EPSG:3857'
    width = height = 1000
    left, bottom, right, top = (-11740727.544603072, 4852834.0517692715,
                                -11584184.510675032, 5009377.085697309)
    # For comparison only, these are not used to calculate the transform.
    transform = from_bounds(left, bottom, right, top, width, height)

    # Define 4 ground control points at the corners of the image.
    gcps = [
        GroundControlPoint(row=0, col=0, x=left, y=top, z=0.0),
        GroundControlPoint(row=0, col=1000, x=right, y=top, z=0.0),
        GroundControlPoint(row=1000, col=1000, x=right, y=bottom, z=0.0),
        GroundControlPoint(row=1000, col=0, x=left, y=bottom, z=0.0)
    ]

    # Compute an output transform.
    res_transform, res_width, res_height = _calculate_default_transform(
        src_crs, dst_crs, height=height, width=width, gcps=gcps)

    assert res_width == width
    assert res_height == height
    for res, exp in zip(res_transform, transform):
        assert round(res, 3) == round(exp, 3)
Example #15
0
def test_array_bounds():
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        w, s, e, n = src.bounds
        height = src.height
        width = src.width
        tr = transform.from_bounds(w, s, e, n, src.width, src.height)
    assert (w, s, e, n) == transform.array_bounds(height, width, tr)
Example #16
0
def test_identity_gcps():
    """Define an identity transform using GCPs"""
    # Tile: [53, 96, 8]
    src_crs = dst_crs = 'EPSG:3857'
    width = height = 1000
    left, bottom, right, top = (
        -11740727.544603072, 4852834.0517692715, -11584184.510675032,
        5009377.085697309)
    # For comparison only, these are not used to calculate the transform.
    transform = from_bounds(left, bottom, right, top, width, height)

    # Define 4 ground control points at the corners of the image.
    gcps = [
        GroundControlPoint(row=0, col=0, x=left, y=top, z=0.0),
        GroundControlPoint(row=0, col=1000, x=right, y=top, z=0.0),
        GroundControlPoint(row=1000, col=1000, x=right, y=bottom, z=0.0),
        GroundControlPoint(row=1000, col=0, x=left, y=bottom, z=0.0)]

    # Compute an output transform.
    res_transform, res_width, res_height = _calculate_default_transform(
        src_crs, dst_crs, height=height, width=width, gcps=gcps)

    assert res_width == width
    assert res_height == height
    for res, exp in zip(res_transform, transform):
        assert round(res, 3) == round(exp, 3)
Example #17
0
    def generate(self, bounds_polygon, raster_shape, resolution=30, hour: int = 8, **kwargs):
        risk_map, _ = self.make_strike_map(bounds_polygon, hour, raster_shape, resolution)

        bounds = bounds_polygon.bounds
        flipped_bounds = (bounds[1], bounds[0], bounds[3], bounds[2])
        risk_raster = gv.Image(risk_map, vdims=['strike_risk'], bounds=flipped_bounds).options(
            alpha=0.7,
            colorbar=True, colorbar_opts={'title': 'Person Strike Risk [h^-1]'},
            cmap='viridis',
            tools=['hover'],
            clipping_colors={
                'min': (0, 0, 0, 0)})
        import rasterio
        from rasterio import transform
        trans = transform.from_bounds(*flipped_bounds, *raster_shape)
        p = os.path.expanduser(f'~/GroundRiskMaps')
        if not os.path.exists(p):
            os.mkdir(p)
        rds = rasterio.open(p + f'/strike_risk_{hour}h_ac{hash(self.aircraft)}.tif',
                            'w', driver='GTiff', count=1, dtype=rasterio.float64, crs='EPSG:4326', transform=trans,
                            compress='lzw', width=raster_shape[0], height=raster_shape[1])
        rds.write(risk_map, 1)
        rds.close()

        return risk_raster, risk_map, None
Example #18
0
    def execute(self, eopatch):
        """ Execute function which adds new vector layer to the EOPatch

        :param eopatch: input EOPatch
        :type eopatch: EOPatch
        :return: New EOPatch with added vector layer
        :rtype: EOPatch
        """
        bbox_map = self._get_submap(eopatch)
        height, width = self._get_shape(eopatch)
        dst_transform = transform.from_bounds(*eopatch.bbox,
                                              width=width,
                                              height=height)

        if self.feature_name in eopatch[self.feature_type]:
            raster = eopatch[self.feature_type][self.feature_name].squeeze()
        else:
            raster = np.ones(
                (height, width), dtype=self.raster_dtype) * self.no_data_value

        if not bbox_map.empty:
            features.rasterize(
                [(bbox_map.cascaded_union.buffer(0), self.raster_value)],
                out=raster,
                transform=dst_transform,
                dtype=self.raster_dtype)

        eopatch[self.feature_type][self.feature_name] = raster[..., np.newaxis]

        return eopatch
Example #19
0
def save_mask_image(label_polygons, tile_polygons, xyz, tile_size, folder,
                    prefix):
    x, y, z = xyz

    # Create the geometry for the mask
    tile_transformation = from_bounds(*tile_polygons.bounds, tile_size,
                                      tile_size)
    cropped_polygons = [
        poly for poly in label_polygons if poly.intersects(tile_polygons)
    ]
    cropped_polygons_df = gpd.GeoDataFrame(geometry=cropped_polygons,
                                           crs='epsg:4326')

    # Create a mask using the footprint of the geometry
    tile_mask = sol.vector.mask.df_to_px_mask(df=cropped_polygons_df,
                                              channels=['footprint'],
                                              affine_obj=tile_transformation,
                                              shape=(tile_size, tile_size),
                                              boundary_width=5,
                                              boundary_type='inner',
                                              contact_spacing=5,
                                              meters=True)

    # Save the mask
    mask_image_filename = ('%s/%s_%s_%s_%s.png' % (folder, prefix, x, y, z))
    imsave(mask_image_filename, tile_mask, check_contrast=False)
    return (mask_image_filename)
Example #20
0
def save_tile_mask(labels_poly,
                   tile_poly,
                   xyz,
                   tile_size,
                   save_path="",
                   prefix="",
                   border_thickness=20):
    x, y, z = xyz
    tfm = from_bounds(*tile_poly.bounds, tile_size, tile_size)
    # get poly inside the tile
    cropped_polys = [
        poly for poly in labels_poly if poly.intersects(tile_poly)
    ]
    cropped_polys_gdf = gpd.GeoDataFrame(geometry=cropped_polys, crs=4326)
    # TODO: do manually because I don't like their definition of contact
    df = cropped_polys_gdf
    feature_list = list(zip(df["geometry"], [255] * len(df)))
    if len(feature_list) == 0:  # if no buildings return zero mask
        mask = np.zeros((tile_size, tile_size), np.uint8)
    else:
        mask = rast_features.rasterize(shapes=feature_list,
                                       out_shape=(args.tile_size,
                                                  args.tile_size),
                                       transform=tfm)
    dist = get_signed_distance_transform(mask, border_thickness)
    im = np.stack([mask, dist, dist], axis=2)
    imsave(f"{save_path}/{prefix}{z}_{x}_{y}.png", im, check_contrast=False)
Example #21
0
    def write_raster(self, fname='output', epsg=None):
        try:
            import rasterio
            from rasterio import transform
        except ImportError:
            print('This method requires Rasterio')
            return

        tfm = transform.from_bounds(self.xmin, self.ymin, self.xmax, self.ymax, self.ncol, self.nrow)
        if epsg is not None:
            crs = {'init': 'epsg:{}'.format(epsg)}
        else:
            crs = None

        with rasterio.drivers():
            with rasterio.open(fname,
                               'w',
                               driver='GTiff',
                               width=self.ncol,
                               height=self.nrow,
                               count=1,
                               dtype=np.float64,
                               nodata=0,
                               transform=tfm,
                               crs=crs) as dst:
                dst.write_band(1, np.flipud(self.data))
def save_raster(Z, x_min, x_max, y_min, y_max, res, crs, fname, fmt='GTIFF'):
    '''
		Save a raster at fname. I followed tutorial there to do so : https://rasterio.readthedocs.io/en/latest/quickstart.html#creating-data
		Arguments:
			Z (2d numpy array): the array
			x_min (float): x min
			y_min (float): y min
			x_max (float): x max
			y_max (float): y max
			res (float): resolution
			crs: coordinate system code (usually you will call it from a dem object, just give it dem.crs)
			fname: path+name+.tif according to your OS  ex: Windows: C://Data/Albania/Holtas/Holt.tif, Linux: /home/Henri/Albania/Shenalvash/She_zoom.tif
			fmt (str): string defining the format. "GTIFF" for tif files, see GDAL for option. WARNING: few outputs are buggy, FOR EXAMPLE "ENVI" bil format can be with the wrong dimensions.
		Returns:
			Nothing but saves a raster with the given parameters
		Authors: 
			B.G. 
		Date:
			08/2018
	'''

    transform = from_bounds(x_min, y_max, x_max, y_min, Z.shape[1], Z.shape[0])
    new_dataset = rio.open(fname,
                           'w',
                           driver=fmt,
                           height=Z.shape[0],
                           width=Z.shape[1],
                           count=1,
                           dtype=Z.dtype.type,
                           crs=crs,
                           transform=transform,
                           nodata=-9999)
    new_dataset.write(Z, 1)
    new_dataset.close()
Example #23
0
def burn(tile, features, size, multicolors):
    """Burn tile with features.

    Args:
      tile: the mercantile tile to burn.
      features: the geojson features to burn.
      size: the size of burned image.

    Returns:
      image: rasterized file of size with features burned.
    """

    if multicolors is True:
        geometry_list = []

        def add(geometry_list, geometry):
            geometry_list.append(geometry)
            return 1 + len(geometry_list)

        shapes = ((geometry, add(geometry_list, geometry))
                  for feature in features
                  for geometry in feature_to_mercator(feature))

    else:
        burnval = 1
        shapes = ((geometry, burnval) for feature in features
                  for geometry in feature_to_mercator(feature))

    bounds = mercantile.xy_bounds(tile)
    transform = from_bounds(*bounds, size, size)

    return rasterize(shapes, out_shape=(size, size), transform=transform)
Example #24
0
    def execute(self, eopatch):
        """ Execute function which adds new vector layer to the EOPatch

        :param eopatch: input EOPatch
        :type eopatch: eolearn.core.EOPatch
        :return: New EOPatch with added vector layer
        :rtype: eolearn.core.EOPatch
        """
        bbox_map = self._get_submap(eopatch)

        data_arr = eopatch.get_feature(FeatureType.MASK, 'IS_DATA')

        dst_shape = data_arr.shape
        dst_transform = transform.from_bounds(*eopatch.bbox,
                                              width=dst_shape[2],
                                              height=dst_shape[1])

        if eopatch.feature_exists(self.feature_type, self.feature_name):
            raster = eopatch.get_feature(self.feature_type, self.feature_name)
        else:
            raster = np.ones(dst_shape[1:3],
                             dtype=self.raster_dtype) * self.no_data_value

        if not bbox_map.empty:
            features.rasterize(
                [(bbox_map.cascaded_union.buffer(0), self.raster_value)],
                out=raster,
                transform=dst_transform,
                dtype=self.raster_dtype)

        eopatch.add_feature(self.feature_type, self.feature_name,
                            raster[..., np.newaxis])

        return eopatch
Example #25
0
def dump_ref_et_rasters(ref_et_filepath, dst_dir):
    ref_et_da = xr.open_dataarray(ref_et_filepath)

    # prepare metadata to dump the potential evapotranspiration rasters
    ref_et_da.name = 'ref_et'
    grid = ref_et_da.salem.grid
    width = grid.nx
    height = grid.ny
    west, east, south, north = grid.extent
    # prepare metadata to dump the potential evapotranspiration rasters
    meta = dict(driver='GTiff',
                dtype=ref_et_da.dtype,
                nodata=np.nan,
                width=width,
                height=height,
                count=1,
                transform=transform.from_bounds(west, south, east, north,
                                                width, height),
                crs=ref_et_da.attrs['pyproj_srs'])

    ref_et_raster_filepath_dict = {}
    for date, ref_et_day_da in ref_et_da.groupby('time'):
        ref_et_raster_filepath = _get_ref_eto_filepath(date, dst_dir)
        with rio.open(ref_et_raster_filepath, 'w', **meta) as dst:
            dst.write(ref_et_day_da.values, 1)
        ref_et_raster_filepath_dict[date] = ref_et_raster_filepath

    return ref_et_raster_filepath_dict
Example #26
0
    def to_terrain(self, dx, dy=None, resampling=warp.Resampling.bilinear):
        """Load geospatial raster data and reproject onto specified grid

        Usage
        =====
        dx,dy : float
            Grid spacings [m]. If dy is not specified, then uniform
            spacing is assumed.
        resampling : warp.Resampling value, optional
            See `list(warp.Resampling)`.
        """
        if dy is None:
            dy = dx

        # load raster
        if not os.path.isfile(self.tiffdata):
            raise FileNotFoundError('Need to download()')
        dem_raster = rasterio.open(self.tiffdata)

        # get source coordinate reference system, transform
        west, south, east, north = self.bounds
        src_height, src_width = dem_raster.shape
        src_crs = dem_raster.crs
        src_transform = transform.from_bounds(*self.bounds, src_width,
                                              src_height)
        src = dem_raster.read(1)

        # calculate destination coordinate reference system, transform
        dst_crs = self.utm_crs
        print('Projecting from', src_crs, 'to', dst_crs)
        # - get origin (the _upper_ left corner) from bounds
        orix, oriy = self.to_xy(north, west)
        origin = (orix, oriy)
        self.origin = origin
        dst_transform = transform.from_origin(*origin, dx, dy)
        # - get extents from lower right corner
        SE_x, SE_y = self.to_xy(south, east)
        Lx = SE_x - orix
        Ly = oriy - SE_y
        Nx = int(Lx / dx)
        Ny = int(Ly / dy)

        # reproject to uniform grid in the UTM CRS
        dem_array = np.empty((Ny, Nx))
        warp.reproject(src,
                       dem_array,
                       src_transform=src_transform,
                       src_crs=src_crs,
                       dst_transform=dst_transform,
                       dst_crs=dst_crs,
                       resampling=resampling)
        utmx = orix + np.arange(0, Nx * dx, dx)
        utmy = oriy + np.arange((-Ny + 1) * dy, dy, dy)
        self.x, self.y = np.meshgrid(utmx, utmy, indexing='ij')
        self.z = np.flipud(dem_array).T

        self.zfun = RectBivariateSpline(utmx, utmy, self.z)
        self.have_terrain = True

        return self.x, self.y, self.z
Example #27
0
def generate_chunk_tasks(image_source, tile_dim):
    tasks = []
    zoom = image_source.zoom
    (min_col, max_col) = (image_source.tile_bounds[0], image_source.tile_bounds[2])
    (min_row, max_row) = (image_source.tile_bounds[1], image_source.tile_bounds[3])

    for tile_col in range(min_col, min(max_col + 1, 2**zoom)):
        for tile_row in range(min_row, min(max_row + 1, 2**zoom)):
            tile_bounds = mercantile.bounds(tile_col, tile_row, zoom)
            (wm_left, wm_bottom, wm_right, wm_top)  = warp.transform_bounds("EPSG:4326",
                                                                           "EPSG:3857",
                                                                            tile_bounds.west,
                                                                            tile_bounds.south,
                                                                            tile_bounds.east,
                                                                            tile_bounds.north)
            affine = transform.from_bounds(wm_left, wm_bottom, wm_right, wm_top, tile_dim, tile_dim)
            target_meta = { 
                "transform": affine[:6],
                "width": tile_dim,
                "height": tile_dim 
            }

            target = os.path.join(image_source.image_folder, "%d/%d/%d.tif" % (zoom, tile_col, tile_row))
            task = ChunkTask(source_uri=image_source.source_uri,
                             target_meta=target_meta,
                             target=target)

            tasks.append(task)

    return tasks
Example #28
0
    def subdivide(self,
                  root: str = "",
                  name: str = "",
                  tif: rio.io.DatasetReader = (),
                  sub: int = 5) -> None:
        if sub is 0: return
        if type(tif) == tuple:
            arr, box, meta = tif
            #with open("./data_lookup.csv", "a") as csv:
            #    csv.write("|".join((root,"ROOT", repr(box))) +"\n")
        else:
            arr, box, meta = np.array(tif.read(1)), Box(tif.bounds), tif.meta

        width = meta["width"] = box.width / 2
        height = meta["height"] = box.height / 2
        sub_bound = {
            0: (0, 1, -1, 0),
            1: (1, 1, 0, 0),
            2: (0, 0, -1, -1),
            3: (1, 0, 0, -1)
        }
        sub_slice = {
            0: {
                "sx": slice(None, int(height)),
                "sy": slice(None, int(width))
            },
            1: {
                "sx": slice(None, int(height)),
                "sy": slice(int(width), None)
            },
            2: {
                "sx": slice(int(height), None),
                "sy": slice(None, int(width))
            },
            3: {
                "sx": slice(int(height), None),
                "sy": slice(int(width), None)
            }
        }
        for idx in range(4):
            sub_name = name + (str(idx) if name is "" else f"_{idx}")
            directory = f"./{root}/{sub_name}/"
            if not os.path.exists(directory): os.mkdir(directory)

            meta["transform"] = from_bounds(
                box.left + width * sub_bound[idx][0],
                box.bottom + height * sub_bound[idx][1],
                box.right + width * sub_bound[idx][2],
                box.top + height * sub_bound[idx][3], width, height)

            with rio.open(directory + f"{self.tif_type}.tif", "w+",
                          **meta) as sub_tif:
                sub_tif.write(arr[sub_slice[idx]["sx"], sub_slice[idx]["sy"]],
                              indexes=1)
                self.subdivide(root, sub_name, sub_tif, sub - 1)
                if sub > 1:
                    os.remove(directory + f"{self.tif_type}.tif")
                    os.rmdir(directory)
                    continue
def _get_transform_from_xr(dataset):
    """Create a geotransform from an xarray dataset.
    """

    from rasterio.transform import from_bounds
    geotransform = from_bounds(dataset.longitude[0], dataset.latitude[-1], dataset.longitude[-1], dataset.latitude[0],
                               len(dataset.longitude), len(dataset.latitude))
    return geotransform
Example #30
0
def get_overview_level(
    src_dst: Union[DatasetReader, DatasetWriter, WarpedVRT],
    bounds: Tuple[float, float, float, float],
    height: int,
    width: int,
    dst_crs: CRS = WEB_MERCATOR_CRS,
) -> int:
    """
    Return the overview level corresponding to the tile resolution.

    Freely adapted from https://github.com/OSGeo/gdal/blob/41993f127e6e1669fbd9e944744b7c9b2bd6c400/gdal/apps/gdalwarp_lib.cpp#L2293-L2362

    Attributes
    ----------
        src_dst : rasterio.io.DatasetReader
            Rasterio io.DatasetReader object
        bounds : list
            Bounds (left, bottom, right, top) in target crs ("dst_crs").
        height : int
            Output height.
        width : int
            Output width.
        dst_crs: CRS or str, optional
            Target coordinate reference system (default "epsg:3857").

    Returns
    -------
        ovr_idx: Int or None
            Overview level

    """
    dst_transform, _, _ = calculate_default_transform(src_dst.crs, dst_crs,
                                                      src_dst.width,
                                                      src_dst.height,
                                                      *src_dst.bounds)
    src_res = dst_transform.a

    # Compute what the "natural" output resolution
    # (in pixels) would be for this input dataset
    vrt_transform = from_bounds(*bounds, width, height)
    target_res = vrt_transform.a

    ovr_idx = -1
    if target_res > src_res:
        res = [src_res * decim for decim in src_dst.overviews(1)]

        for ovr_idx in range(ovr_idx, len(res) - 1):
            ovrRes = src_res if ovr_idx < 0 else res[ovr_idx]
            nextRes = res[ovr_idx + 1]
            if (ovrRes < target_res) and (nextRes > target_res):
                break
            if abs(ovrRes - target_res) < 1e-1:
                break
        else:
            ovr_idx = len(res) - 1

    return ovr_idx
Example #31
0
def geojson_tile_burn(tile, features, tile_size, burn_value=1):
    """Burn tile with GeoJSON features."""

    shapes = ((geometry, burn_value) for feature in features for geometry in geojson_to_mercator(feature))

    bounds = mercantile.xy_bounds(tile)
    transform = from_bounds(*bounds, tile_size, tile_size)

    return rasterize(shapes, out_shape=(tile_size, tile_size), transform=transform)
def _get_transform_from_xr(data, x_coord='longitude', y_coord='latitude'):
    """Create a geotransform from an xarray.Dataset or xarray.DataArray.
    """

    from rasterio.transform import from_bounds
    geotransform = from_bounds(data[x_coord][0], data[y_coord][-1],
                               data[x_coord][-1], data[y_coord][0],
                               len(data[x_coord]), len(data[y_coord]))
    return geotransform
Example #33
0
    def _format(pixels, data_format):
        data, (data_bounds, data_crs) = pixels
        if data_format is not "raw":
            raise Exception("raw data is required")

        (count, height, width) = data.shape

        if count == 1:
            resolution = get_resolution_in_meters(pixels.bounds,
                                                  (height, width))

            # downsample to int16 if ground resolution is more than 10 meters
            # (at the equator)
            if resolution[0] > 10 and resolution[1] > 10:
                data = data.astype(np.int16)
                data.fill_value = _nodata(data.dtype)

        if np.issubdtype(data.dtype, np.float):
            predictor = 3
        else:
            predictor = 2

        meta = {
            "blockxsize":
            blocksize if width >= blocksize else width,
            "blockysize":
            blocksize if height >= blocksize else height,
            "compress":
            "deflate",
            "count":
            count,
            "crs":
            data_crs,
            "dtype":
            data.dtype,
            "driver":
            "GTiff",
            "nodata":
            data.fill_value if data.dtype != np.uint8 else None,
            "predictor":
            predictor,
            "height":
            height,
            "width":
            width,
            "tiled":
            width >= blocksize and height >= blocksize,
            "transform":
            transform.from_bounds(*data_bounds, width=width, height=height),
        }

        with MemoryFile() as memfile:
            with memfile.open(**meta) as dataset:
                dataset.update_tags(AREA_OR_POINT=area_or_point)
                dataset.write(data.filled())

            return (CONTENT_TYPE, memfile.read())
Example #34
0
    def _write((tile, data)):
        if not contains_data((tile, data)):
            return

        print("Writing", tile)

        # Get the bounds of the tile.
        ulx, uly = mercantile.xy(
            *mercantile.ul(tile.x, tile.y, tile.z))
        lrx, lry = mercantile.xy(
            *mercantile.ul(tile.x + 1, tile.y + 1, tile.z))

        # TODO constantize
        tmp_path = "/vsimem/tile"

        # create GeoTIFF
        meta = creation_options.copy()
        meta["count"] = 1
        meta["nodata"] = data.fill_value
        meta["dtype"] = data.dtype
        meta["width"] = CHUNK_SIZE
        meta["height"] = CHUNK_SIZE
        meta["transform"] = from_bounds(ulx, lry, lrx, uly, CHUNK_SIZE, CHUNK_SIZE)

        with rasterio.drivers():
            with rasterio.open(tmp_path, "w", **meta) as tmp:
                tmp.write(data, 1)

        # write out
        output_uri = urlparse(out_dir)
        contents = bytearray(virtual_file_to_buffer(tmp_path))

        if output_uri.scheme == "s3":
            # TODO use mapPartitions so that the client only needs to be
            # instantiated once per partition
            client = boto3.client("s3")

            bucket = output_uri.netloc
            # TODO strip out trailing slashes on the path if necessary
            key = "%s/%d/%d/%d.tif" % (output_uri.path[1:], tile.z, tile.x, tile.y)

            response = client.put_object(
                ACL="public-read",
                Body=bytes(contents),
                Bucket=bucket,
                # CacheControl="TODO",
                ContentType="image/tiff",
                Key=key
            )
        else:
            output_path = os.path.join(out_dir, "%d/%d/%d.tif" % (tile.z, tile.x, tile.y))
            mkdir_p(os.path.dirname(output_path))

            f = open(output_path, "w")
            f.write(contents)
            f.close()
Example #35
0
def test_from_bounds_two():
    width = 80
    height = 80
    left = -120
    top = 70
    right = -80.5
    bottom = 30.5
    tr = transform.from_bounds(left, bottom, right, top, width, height)
    # pixelwidth, rotation, ULX, rotation, pixelheight, ULY
    expected = Affine(0.49375, 0.0, -120.0, 0.0, -0.49375, 70.0)
    assert [round(v, 7) for v in tr] == [round(v, 7) for v in expected]

    # Round right and bottom
    right = -80
    bottom = 30
    tr = transform.from_bounds(left, bottom, right, top, width, height)
    # pixelwidth, rotation, ULX, rotation, pixelheight, ULY
    expected = Affine(0.5, 0.0, -120.0, 0.0, -0.5, 70.0)
    assert [round(v, 7) for v in tr] == [round(v, 7) for v in expected]
Example #36
0
def test_identity():
    """Get the same transform and dimensions back for same crs."""
    # Tile: [53, 96, 8]
    src_crs = dst_crs = 'EPSG:3857'
    width = height = 1000
    left, bottom, right, top = (
        -11740727.544603072, 4852834.0517692715, -11584184.510675032,
        5009377.085697309)
    transform = from_bounds(left, bottom, right, top, width, height)

    res_transform, res_width, res_height = _calculate_default_transform(
        src_crs, dst_crs, width, height, left, bottom, right, top)

    assert res_width == width
    assert res_height == height
    for res, exp in zip(res_transform, transform):
        assert round(res, 3) == round(exp, 3)
Example #37
0
def process_tile(tile):
    """Process a single MBTiles tile."""
    global base_kwds, src
    # Get the bounds of the tile.
    ulx, uly = mercantile.xy(*mercantile.ul(tile.x, tile.y, tile.z))
    lrx, lry = mercantile.xy(*mercantile.ul(tile.x + 1, tile.y + 1, tile.z))

    kwds = base_kwds.copy()
    kwds["transform"] = from_bounds(ulx, lry, lrx, uly, 256, 256)

    with rasterio.open("/vsimem/tileimg", "w", **kwds) as tmp:
        # Reproject the src dataset into image tile.
        for bidx in tmp.indexes:
            reproject(rasterio.band(src, bidx), rasterio.band(tmp, bidx))

    # Get contents of the virtual file.
    contents = bytearray(virtual_file_to_buffer("/vsimem/tileimg"))
    return tile, contents
Example #38
0
def process_chunk(tile, input, creation_options, resampling):
    """Process a single tile."""

    from rasterio.warp import RESAMPLING

    input = input.replace("s3://", "/vsicurl/http://s3.amazonaws.com/")

    print("Chunking initial image for", tile)

    # Get the bounds of the tile.
    ulx, uly = mercantile.xy(
        *mercantile.ul(tile.x, tile.y, tile.z))
    lrx, lry = mercantile.xy(
        *mercantile.ul(tile.x + 1, tile.y + 1, tile.z))

    tmp_path = "/vsimem/tile"

    with rasterio.drivers():
        with rasterio.open(input, "r") as src:
            meta = src.meta.copy()
            meta.update(creation_options)
            meta["height"] = CHUNK_SIZE
            meta["width"] = CHUNK_SIZE
            meta["transform"] = from_bounds(ulx, lry, lrx, uly, CHUNK_SIZE, CHUNK_SIZE)

            # write to a tmp file to allow GDAL to handle the transform
            with rasterio.open(tmp_path, "w", **meta) as tmp:
                # Reproject the src dataset into image tile.
                for bidx in src.indexes:
                    reproject(
                        source=rasterio.band(src, bidx),
                        destination=rasterio.band(tmp, bidx),
                        resampling=getattr(RESAMPLING, resampling),
                        num_threads=multiprocessing.cpu_count(),
                    )

                # check for chunks containing only NODATA
                data = tmp.read(masked=True)

            if data.mask.all():
                return

            # TODO hard-coded for the first band
            return (tile, data[0])
Example #39
0
def downsample((tile, data)):
    if data is None:
        return

    print("Downsampling", tile)

    # Get the bounds of the tile.
    ulx, uly = mercantile.xy(
        *mercantile.ul(tile.x, tile.y, tile.z))
    lrx, lry = mercantile.xy(
        *mercantile.ul(tile.x + 1, tile.y + 1, tile.z))

    # TODO constantize
    tmp_path = "/vsimem/tile"

    # create GeoTIFF
    meta = {
        "driver": "GTiff",
        "crs": "EPSG:3857",
        "nodata": data.fill_value,
        "count": 1,
        "dtype": data.dtype,
        "width": CHUNK_SIZE,
        "height": CHUNK_SIZE,
        "transform": from_bounds(ulx, lry, lrx, uly, CHUNK_SIZE, CHUNK_SIZE),
    }

    with rasterio.drivers():
        with rasterio.open(tmp_path, "w", **meta) as tmp:
            # use GDAL to resample by writing an ndarray and immediately reading
            # it out into a smaller array
            tmp.write(data, 1)
            resampled = tmp.read(
                indexes=1,
                masked=True,
                out=ma.array(np.empty((CHUNK_SIZE / 2, CHUNK_SIZE / 2), data.dtype)),
            )

            if resampled.mask.all():
                return

            corner = CORNERS[(tile.x % 2, tile.y % 2)]
            return (mercantile.parent(tile), (corner, resampled))
def burn(tile, features, size):
    '''Burn tile with features.

    Args:
      tile: the mercantile tile to burn.
      features: the geojson features to burn.
      size: the size of burned image.

    Returns:
      image: rasterized file of size with features burned.
    '''

    # the value you want in the output raster where a shape exists
    burnval = 1
    shapes = ((geometry, burnval) for feature in features for geometry in feature_to_mercator(feature))

    bounds = mercantile.xy_bounds(tile)
    transform = from_bounds(*bounds, size, size)

    result = rasterize(shapes, out_shape=(size, size), transform=transform)
    return Image.fromarray(result, mode='P')
Example #41
0
def _tile_worker(tile):
    """
    For each tile, and given an open rasterio src, plus a`global_args` dictionary
    with attributes of `base_val`, `interval`, and a `writer_func`,
    warp a continous single band raster to a 512 x 512 mercator tile,
    then encode this tile into RGB.

    Parameters
    -----------
    tile: list
        [x, y, z] indices of tile

    Returns
    --------
    tile, buffer
        tuple with the input tile, and a bytearray with the data encoded into
        the format created in the `writer_func`

    """
    x, y, z = tile

    bounds = [c for i in (mercantile.xy(*mercantile.ul(x, y + 1, z)),
            mercantile.xy(*mercantile.ul(x + 1, y, z))) for c in i]

    toaffine = transform.from_bounds(*bounds + [512, 512])

    out = np.empty((512, 512), dtype=src.meta['dtype'])

    reproject(
        rasterio.band(src, 1), out,
        dst_transform=toaffine,
        dst_crs="epsg:3857",
        resampling=RESAMPLING.bilinear)

    out = data_to_rgb(out, global_args['base_val'], global_args['interval'])

    return tile, global_args['writer_func'](out, global_args['kwargs'].copy(), toaffine)
raster_extent_fields = ['x_min', 'y_min', 'x_max', 'y_max',
                        'cell_height', 'cell_width', 'rows',
                        'cols']
RasterExtent = namedtuple('RasterExtent', raster_extent_fields)
raster_extent = RasterExtent(562786.017, 4482993.928, 609786.017, 4530093.928,
                             50.0, 50.0, 942, 949)

# rasterio kwargs
raster_kwargs = {'blockxsize': 949, 'blockysize': 942, 'count': 1,
                 'crs': {'init': u'epsg:26918'}, 'driver': u'GTiff',
                 'dtype': 'float32', 'nodata': None,
                 'height': 949, 'width': 942,
                 'tiled': False, 'transform': from_bounds(
                     raster_extent.x_min,
                     raster_extent.y_min,
                     raster_extent.x_max,
                     raster_extent.y_max,
                     raster_extent.cols,
                     raster_extent.rows
                 )}

def get_weekday_dict():
    """Return a dictionary that maps period => list of weekday obs

    Used to create indicator variables for day of week for each period
    """
    current_day = datetime(2013, 01, 01)

    days_of_week = {}

    while current_day < datetime(2014, 01, 01):
        l = [0, 0, 0, 0, 0, 0, 0]
Example #43
0
import numpy
import rasterio
from rasterio import transform
from rasterio.warp import reproject, RESAMPLING

tempdir = '/tmp'
tiffname = os.path.join(tempdir, 'example.tif')

with rasterio.drivers():

    # Consider a 512 x 512 raster centered on 0 degrees E and 0 degrees N
    # with each pixel covering 15".
    rows, cols = src_shape = (512, 512)
    dpp = 1.0/240 # decimal degrees per pixel
    west, south, east, north = -cols*dpp/2, -rows*dpp/2, cols*dpp/2, rows*dpp/2
    src_transform = transform.from_bounds(west, south, east, north, cols, rows)
    src_crs = {'init': 'EPSG:4326'}
    source = numpy.ones(src_shape, numpy.uint8)*255

    # Prepare to reproject this rasters to a 1024 x 1024 dataset in
    # Web Mercator (EPSG:3857) with origin at -237481.5, 237536.4.
    dst_shape = (1024, 1024)
    dst_transform = transform.from_origin(-237481.5, 237536.4, 425.0, 425.0)
    dst_crs = {'init': 'EPSG:3857'}
    destination = numpy.zeros(dst_shape, numpy.uint8)

    reproject(
        source, 
        destination, 
        src_transform=src_transform,
        src_crs=src_crs,
Example #44
0
def test_from_bounds():
    with rasterio.open('tests/data/RGB.byte.tif') as src:
        w, s, e, n = src.bounds
        tr = transform.from_bounds(w, s, e, n, src.width, src.height)
        assert [round(v, 7) for v in tr] == [round(v, 7) for v in src.affine]