Example #1
0
def test_rasterize_supported_dtype(basic_geometry):
    """ Supported data types should return valid results """

    with Env():
        supported_types = (
            ('int16', -32768),
            ('int32', -2147483648),
            ('uint8', 255),
            ('uint16', 65535),
            ('uint32', 4294967295),
            ('float32', 1.434532),
            ('float64', -98332.133422114)
        )

        for dtype, default_value in supported_types:
            truth = np.zeros(DEFAULT_SHAPE, dtype=dtype)
            truth[2:4, 2:4] = default_value

            result = rasterize(
                [basic_geometry],
                out_shape=DEFAULT_SHAPE,
                default_value=default_value,
                dtype=dtype
            )
            assert np.array_equal(result, truth)
            assert np.dtype(result.dtype) == np.dtype(truth.dtype)

            result = rasterize(
                [(basic_geometry, default_value)],
                out_shape=DEFAULT_SHAPE
            )
            if np.dtype(dtype).kind == 'f':
                assert np.allclose(result, truth)
            else:
                assert np.array_equal(result, truth)
Example #2
0
def test_rasterize_missing_shapes():
    """Shapes are required for this operation."""
    with rasterio.Env():
        with pytest.raises(ValueError) as ex:
            rasterize([], out_shape=DEFAULT_SHAPE)

        assert 'No valid geometry objects' in str(ex.value)
Example #3
0
def test_rasterize_unsupported_dtype(basic_geometry):
    """ Unsupported types should all raise exceptions """

    with Env():
        unsupported_types = (
            ('int8', -127),
            ('int64', 20439845334323),
            ('float16', -9343.232)
        )

        for dtype, default_value in unsupported_types:
            with pytest.raises(ValueError):
                rasterize(
                    [basic_geometry],
                    out_shape=DEFAULT_SHAPE,
                    default_value=default_value,
                    dtype=dtype
                )

            with pytest.raises(ValueError):
                rasterize(
                    [(basic_geometry, default_value)],
                    out_shape=DEFAULT_SHAPE,
                    dtype=dtype
                )
Example #4
0
def test_rasterize_fill_value_dtype_mismatch(basic_geometry):
    """A fill value that doesn't match dtype should fail."""
    with pytest.raises(ValueError):
        rasterize(
            [basic_geometry], out_shape=DEFAULT_SHAPE, fill=1000000,
            default_value=2, dtype=np.uint8
        )
Example #5
0
def test_rasterize_invalid_shapes():
    """Invalid shapes should raise an exception rather than be skipped."""
    with rasterio.Env():
        with pytest.raises(ValueError) as ex:
            rasterize([{'foo': 'bar'}], out_shape=DEFAULT_SHAPE)

        assert 'Invalid geometry object' in str(ex.value)
Example #6
0
def test_rasterize_invalid_fill_value(basic_geometry):
    """A fill value that requires an int64 should raise an exception."""
    with pytest.raises(ValueError):
        rasterize(
            [basic_geometry], out_shape=DEFAULT_SHAPE, fill=1000000000000,
            default_value=2
        )
Example #7
0
def test_rasterize_invalid_out_dtype(basic_geometry):
    """ A non-supported data type for out should raise an exception """

    out = np.zeros(DEFAULT_SHAPE, dtype=np.int64)
    with Env():
        with pytest.raises(ValueError):
            rasterize([basic_geometry], out=out)
Example #8
0
def test_rasterize_shapes_out_dtype_mismatch(basic_geometry):
    """ Shape values must be able to fit in data type for out """

    out = np.zeros(DEFAULT_SHAPE, dtype=np.uint8)
    with Env():
        with pytest.raises(ValueError):
            rasterize([(basic_geometry, 10000000)], out=out)
Example #9
0
def test_rasterize_invalid_value(basic_geometry):
    """A shape value that requires an int64 should raise an exception."""
    with pytest.raises(ValueError) as ex:
        rasterize(
            [(basic_geometry, 1000000000000)], out_shape=DEFAULT_SHAPE
        )

    assert 'dtype must be one of' in str(ex.value)
Example #10
0
def test_rasterize_invalid_out_shape(basic_geometry):
    """output array shape must be 2D."""
    with pytest.raises(ValueError) as ex:
        rasterize([basic_geometry], out_shape=(1, 10, 10))
    assert 'Invalid out_shape' in str(ex.value)

    with pytest.raises(ValueError) as ex:
        rasterize([basic_geometry], out_shape=(10,))
    assert 'Invalid out_shape' in str(ex.value)
Example #11
0
def test_rasterize_invalid_default_value(basic_geometry):
    """ A default value that requires an int64 should raise an exception """

    with Env():
        with pytest.raises(ValueError):
            rasterize(
                [basic_geometry], out_shape=DEFAULT_SHAPE,
                default_value=1000000000000
            )
Example #12
0
def test_rasterize(basic_geometry, basic_image_2x2):
    """Rasterize operation should succeed for both an out_shape and out."""
    assert np.array_equal(
        basic_image_2x2,
        rasterize([basic_geometry], out_shape=DEFAULT_SHAPE)
    )

    out = np.zeros(DEFAULT_SHAPE)
    rasterize([basic_geometry], out=out)
    assert np.array_equal(basic_image_2x2, out)
Example #13
0
    def set_roi(self, shape=None, geometry=None, crs=wgs84, grid=None,
                corners=None, noerase=False):
        """Set a region of interest for the dataset.
        If set succesfully, a ROI is simply a mask of the same size as the
        dataset's grid, obtained with the .roi attribute.
        I haven't decided yet if the data should be masekd out when a ROI
        has been set.
        Parameters
        ----------
        shape: path to a shapefile
        geometry: a shapely geometry
        crs: the crs of the geometry
        grid: a Grid object
        corners: a ((x0, y0), (x1, y1)) tuple of the corners of the square
        to subset the dataset to. The coordinates are not expressed in
        wgs84, set the crs keyword
        noerase: set to true in order to add the new ROI to the previous one
        """

        # The rois are always defined on the original grids, but of course
        # we take that into account when a subset is set (see roi
        # decorator below)
        ogrid = self._ogrid

        # Initial mask
        if noerase and (self.roi is not None):
            mask = self.roi
        else:
            mask = np.zeros((ogrid.ny, ogrid.nx), dtype=np.int16)

        # Several cases
        if shape is not None:
            gdf = sio.read_shapefile(shape)
            gis.transform_geopandas(gdf, to_crs=ogrid.corner_grid,
                                    inplace=True)
            with rasterio.Env():
                mask = features.rasterize(gdf.geometry, out=mask)
        if geometry is not None:
            geom = gis.transform_geometry(geometry, crs=crs,
                                          to_crs=ogrid.corner_grid)
            with rasterio.Env():
                mask = features.rasterize(np.atleast_1d(geom), out=mask)
        if grid is not None:
            _tmp = np.ones((grid.ny, grid.nx), dtype=np.int16)
            mask = ogrid.map_gridded_data(_tmp, grid, out=mask).filled(0)
        if corners is not None:
            cgrid = self._ogrid.center_grid
            xy0, xy1 = corners
            x0, y0 = cgrid.transform(*xy0, crs=crs, nearest=True)
            x1, y1 = cgrid.transform(*xy1, crs=crs, nearest=True)
            mask[np.min([y0, y1]):np.max([y0, y1])+1,
                 np.min([x0, x1]):np.max([x0, x1])+1] = 1

        self.roi = mask
Example #14
0
def test_rasterize(basic_geometry, basic_image_2x2):
    """ Rasterize operation should succeed for both an out_shape and out """

    with rasterio.drivers():
        assert numpy.array_equal(
            basic_image_2x2,
            rasterize([basic_geometry], out_shape=DEFAULT_SHAPE)
        )

        out = numpy.zeros(DEFAULT_SHAPE)
        rasterize([basic_geometry], out=out)
        assert numpy.array_equal(basic_image_2x2, out)
Example #15
0
def gdf_to_rst(gdf, trs, w, h, path_to_desc):
    '''
    Convert a view of a gdf to a color-coded numpy array.
    '''
    unitcolor = generate_unitcolor_lookup(path_to_desc)
    rz = rasterize([(x.geometry, unitcolor.R[gdf.mapunit[i]]) for i, x in gdf.iterrows()],
                   out_shape=(w, h), transform=trs)
    gz = rasterize([(x.geometry, unitcolor.G[gdf.mapunit[i]]) for i, x in gdf.iterrows()],
                   out_shape=(w, h), transform=trs)
    bz = rasterize([(x.geometry, unitcolor.B[gdf.mapunit[i]]) for i, x in gdf.iterrows()],
                   out_shape=(w, h), transform=trs)
    
    return np.dstack((rz, gz, bz))
def test_rasterize_geometries():
    """
    Make sure that geometries are correctly rasterized according to parameters
    """

    rows = cols = 10
    transform = (1.0, 0.0, 0.0, 0.0, 1.0, 0.0)
    geometry = {
        'type': 'Polygon',
        'coordinates': [[(2, 2), (2, 4.25), (4.25, 4.25), (4.25, 2), (2, 2)]]
    }

    with rasterio.drivers():
        # we expect a subset of the pixels using default mode
        result = rasterize([geometry], out_shape=(rows, cols))
        truth = numpy.zeros((rows, cols))
        truth[2:4, 2:4] = 1
        assert numpy.array_equal(result, truth)

        out = numpy.zeros((rows, cols))
        result = rasterize([geometry], out=out, default_value=1)
        assert numpy.array_equal(out, truth)

        # we expect all touched pixels
        result = rasterize(
            [geometry], out_shape=(rows, cols), all_touched=True
        )
        truth = numpy.zeros((rows, cols))
        truth[2:5, 2:5] = 1
        assert numpy.array_equal(result, truth)

        # we expect the pixel value to match the one we pass in
        value = 5
        result = rasterize([(geometry, value)], out_shape=(rows, cols))
        truth = numpy.zeros((rows, cols))
        truth[2:4, 2:4] = value
        assert numpy.array_equal(result, truth)

        # Check the fill and default transform.
        # we expect the pixel value to match the one we pass in
        value = 5
        result = rasterize(
            [(geometry, value)],
            out_shape=(rows, cols),
            fill=1
        )
        truth = numpy.ones((rows, cols))
        truth[2:4, 2:4] = value
        assert numpy.array_equal(result, truth)
Example #17
0
 def get_costRaster(self,mbb,transform,psize,crs):
     x_min = mbb[0]
     y_min = mbb[1]
     x_max = mbb[2]
     y_max = mbb[3]
     x_res = int((x_max - x_min) / psize)
     y_res = int((y_max - y_min) / psize)
     
     features = self.get_projected_gjson(crs)['features']
     feats = [g['geometry'] for g in features]
     
     raster = rasterize(
         feats,
         out_shape=(y_res, x_res),
         transform=transform,
         dtype='float32',
         all_touched=True)
     
     if self.interpretation == 'boundary':
         #1000 is just an arbitrarily large number, could try np.inf
         raster = np.where(raster==0,1000.0,self.cost)
         print 'at boundary', raster
     elif self.interpretation == 'crossing':
         raster = raster*(self.cost/psize)
         print 'at all else', raster
     return raster
def main(infile, outfile, bbox, res):

    """
    Rasterize vector with constraints.
    """

    x_min, y_min, x_max, y_max = bbox

    width = int((x_max - x_min) / res)
    if width % 2 is not 0:
        width += 1
        res = (x_max - x_min) / width
    height = int((y_max - y_min) / res)

    with fio.open(infile) as src:
        aff = affine.Affine(res, 0.0, x_min,
                            0.0, -res, y_max)
        meta = {
            'driver': 'GTiff',
            'count': 1,
            'crs': src.crs,
            'affine': aff,
            'transform': rio.guard_transform(aff),
            'COMPRESS': 'DEFLATE',
            'INTERLEAVE': 'BAND',
            'BIGTIFF': 'YES',
            'TILED': 'NO',
            'PREDICTOR': '2',
            'dtype': rio.ubyte,
            'nodata': None,
            'width': width,
            'height': height
        }

        print(width)
        print(height)
        exit()

    with fio.open(infile) as src, rio.open(outfile, 'w', **meta) as dst:
        length = len([i for i in dst.block_windows()])
        with click.progressbar(dst.block_windows(), length=length) as block_windows:
            for _, window in block_windows:
                aff = dst.window_transform(window)
                ((row_min, row_max), (col_min, col_max)) = window
                x_min, y_min = aff * (col_min, row_max)
                x_max, y_max = aff * (col_max, row_min)
                data = np.zeros((row_max - row_min, col_max - col_min))
                try:
                    data = rasterize(
                        shapes=(feat['geometry'] for feat in src.filter(bbox=(x_min, y_min, x_max, y_max))),
                        fill=0,
                        out=data,
                        transform=aff,
                        all_touched=True,
                        default_value=1,
                        dtype=dst.meta['dtype']
                    )
                except ValueError:
                    pass
                dst.write(data, window=window)
Example #19
0
def test_rasterize_all_touched(basic_geometry, basic_image):
    assert np.array_equal(
        basic_image,
        rasterize(
            [basic_geometry], out_shape=DEFAULT_SHAPE, all_touched=True
        )
    )
Example #20
0
def test_rasterize_skip_invalid_geom(geojson_polygon, basic_image_2x2):
    """Rasterize operation should succeed for at least one valid geometry
    and should skip any invalid or empty geometries with an error."""

    with pytest.warns(UserWarning, match="Invalid or empty shape"):
        out = rasterize([geojson_polygon, {'type': 'Polygon', 'coordinates': []}], out_shape=DEFAULT_SHAPE)

    assert np.array_equal(out, basic_image_2x2)
    def handle(self, *args, **options):

        js = Jurisdiction.objects.all()

        for j in js:
            image = str(settings.BASE_DIR.path('config/static/jurisdictions/%s.png' % j.id))
            image_aux = image + '.aux.xml'

            if not os.path.exists(image):
                obj = {
                    'type': 'Feature',
                    'geometry': json.loads(j.geometry.geojson)
                }
                rasterize(obj, image, fill=0, default_value=180, res=(0.001,), driver='PNG')

                # Remove all .aux.xml files
                os.unlink(image_aux)
Example #22
0
def test_rasterize_geometries_symmetric():
    """Make sure that rasterize is symmetric with shapes."""
    transform = (1.0, 0.0, 0.0, 0.0, -1.0, 0.0)
    truth = np.zeros(DEFAULT_SHAPE, dtype=rasterio.ubyte)
    truth[2:5, 2:5] = 1
    s = shapes(truth, transform=transform)
    result = rasterize(s, out_shape=DEFAULT_SHAPE, transform=transform)
    assert np.array_equal(result, truth)
	def _rasterize_id( df, value, out_shape, out_transform, background_value=0 ):
		from rasterio.features import rasterize
		geom = df.geometry
		out = rasterize( ( ( g, value ) for g in geom ),
							out_shape=out_shape,
							transform=out_transform,
							fill=background_value )
		return out
Example #24
0
def test_rasterize_point(geojson_point):
    expected = np.zeros(shape=DEFAULT_SHAPE, dtype='uint8')
    expected[2, 2] = 1

    assert np.array_equal(
        rasterize([geojson_point], out_shape=DEFAULT_SHAPE),
        expected
    )
def main(no_data_val=-9999, fname_out='county_level_pop_out.tif', year=2017, grwth_rate_fct=0.0):
    '''
    '''
    # Get raster reference project from configuration file (ref_proj)
    with self.input()['ref_proj'].open('r') as fid:
        ref_proj = json.load(fid)

    # Read the shapefile with total population data
    shp_pop_obj = self.input()['geoshape_file']
    pop_data = gpd.read_file(shp_pop_obj.path)

    # -------------------------------------
    # Calculate Population from 2008 Census
    # data and growth rate
    # Apply growth rate adjustment
    # -------------------------------------
    nstep = self.year - 2008
    pop_data['GROWTHRATE'] = pop_data['GROWTHRATE'] * (1 + self.grwth_rate_fct)
    pop_data['Population'] = pop_data['SS2008'] * np.exp(pop_data['GROWTHRATE'] * nstep)
    pop_data['Population'] = pop_data['Population'].apply(lambda x: np.round(x))
    pop_data['Population'] = pop_data['Population'].astype('int32')

    # -----------------------------------------------------------------------
    # Rasterize Total population along with age and gender ratios
    # Total population and age & gender ratios should go into one raster file
    # -----------------------------------------------------------------------
    (ncols, nrows) = ref_proj['ncolsrows']
    rast_meta = {
        'driver': 'GTiff',
        'height': nrows,
        'width': ncols,
        'count': 1,
        'dtype': np.int32,
        'crs': ref_proj['srs'],
        'transform': ref_proj['pixel'],
        'nodata': -9999.0,
    }

    # Open raster file for writing
    with self.output().open("wb") as fout:
        with rasterio.open(fout.name, 'w', **rast_meta) as out_raster:

            out_array = out_raster.read(1)

            # Rasterize geopandas geometries with population values
            shapes = (
                (geom, pop_values)
                for geom, pop_values in zip(pop_data['geometry'], pop_data['Population'])
            )
            burned_data = features.rasterize(
                shapes=shapes, fill=0, out=out_array, transform=out_raster.transform
            )

            out_raster.write_band(1, burned_data)

            # Tag raster bands
            band_tags = {'band_1': 'Total_Population'}
            out_raster.update_tags(**band_tags)
Example #26
0
def test_rasterize_geomcollection(geojson_geomcollection):
    expected = np.zeros(shape=DEFAULT_SHAPE, dtype='uint8')
    expected[0:1, 0:1] = 1
    expected[2:4, 2:4] = 1

    assert np.array_equal(
        rasterize([geojson_geomcollection], out_shape=DEFAULT_SHAPE),
        expected
    )
Example #27
0
def test_rasterize_geo_interface_2(geojson_polygon):
    """Objects that implement the geo interface should rasterize properly"""

    class GeoObj:
        @property
        def __geo_interface__(self):
            return geojson_polygon

    assert rasterize([GeoObj()], out_shape=DEFAULT_SHAPE).sum() == 4
Example #28
0
def test_rasterize_mismatched_dtype(basic_geometry):
    """Mismatched values and dtypes should raise exceptions."""
    mismatched_types = (('uint8', 3.2423), ('uint8', -2147483648))
    for dtype, default_value in mismatched_types:
        with pytest.raises(ValueError):
            rasterize(
                [basic_geometry],
                out_shape=DEFAULT_SHAPE,
                default_value=default_value,
                dtype=dtype
            )

        with pytest.raises(ValueError):
            rasterize(
                [(basic_geometry, default_value)],
                out_shape=DEFAULT_SHAPE,
                dtype=dtype
            )
Example #29
0
def rasterize_geom(geom, like, all_touched=False):
    geoms = [(geom, 1)]
    rv_array = features.rasterize(
        geoms,
        out_shape=like.shape,
        transform=like.affine,
        fill=0,
        all_touched=all_touched)
    return rv_array
Example #30
0
def rasterize_geom(geom, shape, affine, all_touched=False, scale=None):
    geoms = [(geom, 1)]
    rv_array = features.rasterize(
        geoms,
        out_shape=shape,
        transform=affine,
        fill=0,
        all_touched=all_touched)
    return rv_array
Example #31
0
    print(out_meta)
    out_meta.update(dtype=rasterio.int16, driver='GTiff')
    mask = features.geometry_mask(
        [feature["feature"]["geometry"] for feature in list_of_dicts],
        src_rst.shape,
        transform=src_rst.transform,
        all_touched=True,
        invert=True)
    new_dsm = np.copy(np.squeeze(
        dsm))  #Forstaer ikke hvorfor, men dsm'en har en ekstra dimension,
    #som jeg fjerner med squeeze, saa den passer med result dsm'en
    with rasterio.Env():
        result = features.rasterize(
            ((feature['feature']['geometry'],
              np.int(feature['feature']['properties']['hoejde']) * 1000)
             for feature in list_of_dicts),
            out_shape=src_rst.shape,
            transform=src_rst.transform,
            all_touched=True)
        new_dsm[mask] = result[mask]

        with Session(gisdb=grassdb, location="test", create_opts=vrt):
            import grass.script.array as garray
            r_viewshed = Module('r.viewshed')
            r_out_gdal = Module('r.out.gdal')
            from_np_raster = garray.array()
            from_np_raster[...] = new_dsm
            from_np_raster.write('ny_rast', overwrite=True)
            print(from_np_raster)
            gcore.run_command('r.viewshed',
                              overwrite=True,
Example #32
0
def rasterize(ctx, files, output, driver, like, bounds, dimensions, res,
              src_crs, all_touched, default_value, fill, property,
              creation_options):
    """Rasterize GeoJSON into a new or existing raster.

    If the output raster exists, rio-rasterize will rasterize feature values
    into all bands of that raster.  The GeoJSON is assumed to be in the same
    coordinate reference system as the output unless --src-crs is provided.

    --default_value or property values when using --property must be using a
    data type valid for the data type of that raster.


    If a template raster is provided using the --like option, the affine
    transform and data type from that raster will be used to create the output.
    Only a single band will be output.

    The GeoJSON is assumed to be in the same coordinate reference system unless
    --src-crs is provided.

    --default_value or property values when using --property must be using a
    data type valid for the data type of that raster.

    --driver, --bounds, --dimensions, and --res are ignored when output exists
    or --like raster is provided


    If the output does not exist and --like raster is not provided, the input
    GeoJSON will be used to determine the bounds of the output unless
    provided using --bounds.

    --dimensions or --res are required in this case.

    If --res is provided, the bottom and right coordinates of bounds are
    ignored.


    Note:
    The GeoJSON is not projected to match the coordinate reference system
    of the output or --like rasters at this time.  This functionality may be
    added in the future.
    """

    from rasterio._base import is_geographic_crs, is_same_crs
    from rasterio.features import rasterize
    from rasterio.features import bounds as calculate_bounds

    verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1

    output, files = resolve_inout(files=files, output=output)

    has_src_crs = src_crs is not None
    src_crs = src_crs or 'EPSG:4326'

    # If values are actually meant to be integers, we need to cast them
    # as such or rasterize creates floating point outputs
    if default_value == int(default_value):
        default_value = int(default_value)
    if fill == int(fill):
        fill = int(fill)

    with rasterio.drivers(CPL_DEBUG=verbosity > 2):

        def feature_value(feature):
            if property and 'properties' in feature:
                return feature['properties'].get(property, default_value)
            return default_value

        with click.open_file(files.pop(0) if files else '-') as gj_f:
            geojson = json.loads(gj_f.read())
        if 'features' in geojson:
            geometries = []
            for f in geojson['features']:
                geometries.append((f['geometry'], feature_value(f)))
        elif 'geometry' in geojson:
            geometries = ((geojson['geometry'], feature_value(geojson)), )
        else:
            raise click.BadParameter('Invalid GeoJSON',
                                     param=input,
                                     param_hint='input')

        geojson_bounds = geojson.get('bbox', calculate_bounds(geojson))

        if os.path.exists(output):
            with rasterio.open(output, 'r+') as out:
                if has_src_crs and not is_same_crs(src_crs, out.crs):
                    raise click.BadParameter(
                        'GeoJSON does not match crs of '
                        'existing output raster',
                        param='input',
                        param_hint='input')

                if _disjoint_bounds(geojson_bounds, out.bounds):
                    click.echo(
                        "GeoJSON outside bounds of existing output "
                        "raster. Are they in different coordinate "
                        "reference systems?",
                        err=True)

                meta = out.meta.copy()

                result = rasterize(geometries,
                                   out_shape=(meta['height'], meta['width']),
                                   transform=meta.get('affine',
                                                      meta['transform']),
                                   all_touched=all_touched,
                                   dtype=meta.get('dtype', None),
                                   default_value=default_value,
                                   fill=fill)

                for bidx in range(1, meta['count'] + 1):
                    data = out.read_band(bidx, masked=True)
                    # Burn in any non-fill pixels, and update mask accordingly
                    ne = result != fill
                    data[ne] = result[ne]
                    data.mask[ne] = False
                    out.write_band(bidx, data)

        else:
            if like is not None:
                template_ds = rasterio.open(like)

                if has_src_crs and not is_same_crs(src_crs, template_ds.crs):
                    raise click.BadParameter(
                        'GeoJSON does not match crs of '
                        '--like raster',
                        param='input',
                        param_hint='input')

                if _disjoint_bounds(geojson_bounds, template_ds.bounds):
                    click.echo(
                        "GeoJSON outside bounds of --like raster. "
                        "Are they in different coordinate reference "
                        "systems?",
                        err=True)

                kwargs = template_ds.meta.copy()
                kwargs['count'] = 1
                template_ds.close()

            else:
                bounds = bounds or geojson_bounds

                if is_geographic_crs(src_crs):
                    if (bounds[0] < -180 or bounds[2] > 180 or bounds[1] < -80
                            or bounds[3] > 80):
                        raise click.BadParameter(
                            "Bounds are beyond the valid extent for "
                            "EPSG:4326.",
                            ctx,
                            param=bounds,
                            param_hint='--bounds')

                if dimensions:
                    width, height = dimensions
                    res = ((bounds[2] - bounds[0]) / float(width),
                           (bounds[3] - bounds[1]) / float(height))

                else:
                    if not res:
                        raise click.BadParameter(
                            'pixel dimensions are required',
                            ctx,
                            param=res,
                            param_hint='--res')

                    elif len(res) == 1:
                        res = (res[0], res[0])

                    width = max(
                        int(ceil((bounds[2] - bounds[0]) / float(res[0]))), 1)
                    height = max(
                        int(ceil((bounds[3] - bounds[1]) / float(res[1]))), 1)

                src_crs = src_crs.upper()
                if not src_crs.count('EPSG:'):
                    raise click.BadParameter(
                        'invalid CRS.  Must be an EPSG code.',
                        ctx,
                        param=src_crs,
                        param_hint='--src_crs')

                kwargs = {
                    'count':
                    1,
                    'crs':
                    src_crs,
                    'width':
                    width,
                    'height':
                    height,
                    'transform':
                    Affine(res[0], 0, bounds[0], 0, -res[1], bounds[3]),
                    'driver':
                    driver
                }
                kwargs.update(**creation_options)

            result = rasterize(geometries,
                               out_shape=(kwargs['height'], kwargs['width']),
                               transform=kwargs.get('affine',
                                                    kwargs['transform']),
                               all_touched=all_touched,
                               dtype=kwargs.get('dtype', None),
                               default_value=default_value,
                               fill=fill)

            if 'dtype' not in kwargs:
                kwargs['dtype'] = result.dtype

            kwargs['nodata'] = fill

            with rasterio.open(output, 'w', **kwargs) as out:
                out.write_band(1, result)
Example #33
0
def negative_buffer_and_small_filter(params):
    """
    Applies a negative buffer to wv2 labels since some are too close together and 
    produce conjoined instances when connected components is run (even after 
    erosion/dilation). This may not get rid of all conjoinments and should be adjusted.
    It relies too on the source projection of the label file to calculate distances for
    the negative buffer. Currently hardcodes in projections, need to look up utm pojection
    based on spatial location somehow if I'm to extend this to work with labels anywhere.

    Returns rasterized labels that are ready to be gridded
    """
    class_int = params['label_vals']['class']
    neg_buffer = float(params['label_vals']['neg_buffer'])
    small_area_filter = float(params['label_vals']['small_area_filter'])
    big_area_filter = float(params['label_vals']['big_area_filter'])
    # This is a helper  used with sorted for a list of strings by specific indices in 
    # each string. Was used for a long path that ended with a file name
    # Not needed here but may be with different source imagery and labels
    # def takefirst_two(elem):
    #     return int(elem[-12:-10])

    items = os.listdir(SOURCE_LABELS)
    labels = []
    for name in items:
        if name.endswith(".shp"):
            labels.append(os.path.join(SOURCE_LABELS,name))  

    shp_list = sorted(labels)
    # need to use Source imagery for geotransform data for rasterized shapes, didn't preserve when save imgs to reorder
    scenes = os.listdir(SOURCE_IMGS)
    #hard coded season because it will take more tinkering to have the model and preprocessing work with multichannel
    scenes = [scene for scene in scenes if 'GS' in scene]
    img_list = []
    for name in scenes:
        img_list.append(os.path.join(SOURCE_IMGS,name))  

    img_list = sorted(img_list)


    for shp_path, img_path in zip(shp_list, img_list):
        shp_frame = gpd.read_file(shp_path)
        # keeps the class of interest if it is there and the polygon of raster extent
        shp_frame = shp_frame[(shp_frame['class'] == class_int) | (shp_frame['DN'] == 1)]
        with rasterio.open(img_path) as rast:
            meta = rast.meta.copy()
            meta.update(compress="lzw")
            meta['count'] = 1
        tifname = os.path.splitext(os.path.basename(shp_path))[0] + '.tif'
        rasterized_name = os.path.join(NEG_BUFFERED, tifname)
        with rasterio.open(rasterized_name, 'w+', **meta) as out:
            out_arr = out.read(1)
            # we get bounds to deterimine which projection to use for neg buffer
            shp_frame.loc[0,'DN'] = 0
            shp_frame.loc[1:,'DN'] = 1
            maxx_bound = shp_frame.bounds.maxx.max()
            minx_bound = shp_frame.bounds.minx.min()
            #need to project to correct utm before buffering in units of meters
            if maxx_bound >= 30 and minx_bound>= 30:
                shp_frame = shp_frame.to_crs({'init': 'epsg:32736'})
                shp_frame['geometry'] = shp_frame['geometry'].buffer(neg_buffer)
                shp_frame['Shape_Area'] = shp_frame.area
                shp_frame = shp_frame.to_crs({'init': 'epsg:4326'})

            else:
                shp_frame = shp_frame.to_crs({'init': 'epsg:32735'})
                shp_frame['geometry'] = shp_frame['geometry'].buffer(neg_buffer)
                shp_frame['Shape_Area'] = shp_frame.area
                shp_frame = shp_frame.to_crs({'init': 'epsg:4326'})

            if len(shp_frame) == 1: # added for case, where entire wv2 scenes have no foreground class and need empty masks
                shapes = ((geom,value) for geom, value in zip(shp_frame.geometry, shp_frame.DN))
                burned = features.rasterize(shapes=shapes, fill=0, out=out_arr, transform=out.transform, default_value=1)
                burned[burned < 0] = 0
                out.write_band(1, burned)

            else: # added for center pivot case, where entire wv2 scenes have no center pivots and need empty masks
                shp_frame = shp_frame.loc[shp_frame.Shape_Area > small_area_filter]
                shp_frame = shp_frame.loc[shp_frame.Shape_Area < big_area_filter]
                shp_frame = shp_frame[shp_frame.DN==1] # get rid of extent polygon
                # https://gis.stackexchange.com/questions/151339/rasterize-a-shapefile-with-geopandas-or-fiona-python#151861
                shapes = ((geom,value) for geom, value in zip(shp_frame.geometry, shp_frame.DN))
                burned = features.rasterize(shapes=shapes, fill=0, out=out_arr, transform=out.transform, default_value=1)
                burned[burned < 0] = 0
                out.write_band(1, burned)
    print('Done applying negbuff of {negbuff} and filtering small labels of area less than {area}'.format(negbuff=neg_buffer,area=small_area_filter))  
Example #34
0
def test_rasterize_geo_interface(geojson_polygon, basic_image_2x2):
    assert np.array_equal(
        rasterize([MockGeoInterface(geojson_polygon)], out_shape=DEFAULT_SHAPE),
        basic_image_2x2
    )
Example #35
0
def test_rasterize_shapes_out_dtype_mismatch(basic_geometry):
    """Shape values must be able to fit in data type for out."""
    out = np.zeros(DEFAULT_SHAPE, dtype=np.uint8)
    with pytest.raises(ValueError):
        rasterize([(basic_geometry, 10000000)], out=out)
Example #36
0
def burn_polygons_to_a_raster(ref_raster,
                              polygons,
                              burn_values,
                              save_path,
                              date_type='uint8',
                              xres=None,
                              yres=None,
                              extent=None,
                              ref_prj=None,
                              nodata=None):
    # if save_path is None, it will return the array, not saving to disk
    # burn polygons to a new raster
    # if ref_raster is None, we must set xres and yres, and extent (read from polygons) and ref_prj (from shapefile)
    # extent: (minx, miny, maxx, maxy)

    if save_path is not None and os.path.isfile(save_path):
        print('%s exist, skip burn_polygons_to_a_raster' % save_path)
        return save_path

    if isinstance(burn_values, int):
        values = [burn_values] * len(polygons)
    elif isinstance(burn_values, list):
        values = burn_values
        if len(burn_values) != len(polygons):
            raise ValueError(
                'polygons and burn_values do not have the same size')
    else:
        raise ValueError('unkonw type of burn_values')

    if date_type == 'uint8':
        save_dtype = rasterio.uint8
        np_dtype = np.uint8
    elif date_type == 'uint16':
        save_dtype = rasterio.uint16
        np_dtype = np.uint16
    elif date_type == 'int32':
        save_dtype = rasterio.int32
        np_dtype = np.int32
    else:
        raise ValueError('not yet support')

    if ref_raster is None:
        # exent (minx, miny, maxx, maxy)
        height, width = math.ceil((extent[3] - extent[1]) / yres), math.ceil(
            (extent[2] - extent[0]) / xres)
        burn_out = np.zeros((height, width), dtype=np_dtype)
        if nodata is not None:
            burn_out[:] = nodata
        # rasterize the shapes
        burn_shapes = [(item_shape, item_int)
                       for (item_shape, item_int) in zip(polygons, values)]
        ## new_transform = (burn_boxes[0], resX, 0, burn_boxes[3], 0, -resY )  # (X_min, resX, 0, Y_max, 0, -resY)  # GDAL-style transforms, have been deprecated after raster 1.0
        # affine.Affine() vs. GDAL-style geotransforms: https://rasterio.readthedocs.io/en/stable/topics/migrating-to-v1.html
        transform = (xres, 0, extent[0], 0, -yres, extent[3]
                     )  # (resX, 0, X_min, 0, -resY, Y_max)
        out_label = rasterize(burn_shapes,
                              out=burn_out,
                              transform=transform,
                              fill=0,
                              all_touched=False,
                              dtype=save_dtype)

        if save_path is None:
            return out_label

        with rasterio.open(save_path,
                           'w',
                           driver='GTiff',
                           height=height,
                           width=width,
                           count=1,
                           dtype=save_dtype,
                           crs=ref_prj,
                           transform=transform,
                           nodata=nodata) as dst:
            dst.write_band(1, out_label.astype(save_dtype))

    else:
        with rasterio.open(ref_raster) as src:
            transform = src.transform
            burn_out = np.zeros((src.height, src.width), dtype=np_dtype)
            if nodata is not None:
                burn_out[:] = nodata
            # rasterize the shapes
            burn_shapes = [(item_shape, item_int)
                           for (item_shape, item_int) in zip(polygons, values)]
            #
            out_label = rasterize(burn_shapes,
                                  out=burn_out,
                                  transform=transform,
                                  fill=0,
                                  all_touched=False,
                                  dtype=save_dtype)
            if save_path is None:
                return out_label

            # test: save it to disk
            kwargs = src.meta
            kwargs.update(dtype=save_dtype, count=1, nodata=nodata)

            # # remove nodta in the output
            # if 'nodata' in kwargs.keys():
            #     del kwargs['nodata']

            with rasterio.open(save_path, 'w', **kwargs) as dst:
                dst.write_band(1, out_label.astype(save_dtype))
def rasterize_polygons_to_ref_raster(ref_raster,
                                     poly_path,
                                     burn_value,
                                     attribute_name,
                                     save_path,
                                     datatype='Byte',
                                     ignore_edge=True):
    '''
    rasterize polygons to a raster with the same size of ref_raster
    :param ref_raster:  reference raster
    :param poly_path: shapefile path
    :param burn_value: if attribute_name is None, then we will use burn_value
    :param attribute_name: the attribute to be burned into raster
    :param save_path:
    :param datatype: datatype
    :param ignore_edge: if True, will burn a buffer areas (~5 pixel as 255)
    :return:
    '''

    if isinstance(burn_value, int) is False or isinstance(burn_value, float):
        raise ValueError('The burn value should be int or float')

    # need to check the projection
    # need to check: the shape file and raster should have the same projection.
    if get_projection_proj4(ref_raster) != get_projection_proj4(poly_path):
        raise ValueError(
            'error, the input raster (e.g., %s) and vector (%s) files don\'t have the same projection'
            % (ref_raster, poly_path))

    # read polygons (can read geojson file directly)
    shapefile = gpd.read_file(poly_path)
    polygons = shapefile.geometry.values
    if attribute_name is None:
        class_labels = [burn_value] * len(polygons)
    else:
        class_labels = shapefile[attribute_name].tolist()

    # output datatype: https://gdal.org/programs/gdal_rasterize.html
    # -ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/
    #             CInt16/CInt32/CFloat32/CFloat64}]
    if datatype == 'Byte':
        dtype = rasterio.uint8
    elif datatype == 'UInt16':
        dtype = rasterio.uint16
    else:
        dtype = rasterio.int32

    with rasterio.open(ref_raster) as src:

        transform = src.transform
        burn_out = np.zeros((src.height, src.width))
        out_label = burn_out

        if len(polygons) > 0:
            if ignore_edge is False:
                # rasterize the shapes
                burn_shapes = [
                    (item_shape, item_class_int)
                    for (item_shape,
                         item_class_int) in zip(polygons, class_labels)
                ]
                #
                out_label = rasterize(burn_shapes,
                                      out=burn_out,
                                      transform=transform,
                                      fill=0,
                                      all_touched=False,
                                      dtype=dtype)
            else:
                # burn a buffer area (4 to 5 pixel) of edge as 255
                xres, yres = src.res
                outer_list = [poly.buffer(2 * xres) for poly in polygons]
                inner_list = [poly.buffer(-2 * xres) for poly in polygons]
                # after negative buffer, some small polygons may be deleted, need to check
                inner_list = [
                    item for item in inner_list
                    if item.is_valid and item.is_empty is False
                ]
                if len(inner_list) > 0:
                    # rasterize the outer
                    burn_shapes = [(item_shape, 255)
                                   for item_shape in outer_list]
                    out_label = rasterize(burn_shapes,
                                          out=burn_out,
                                          transform=transform,
                                          fill=0,
                                          all_touched=False,
                                          dtype=dtype)
                    # rasterize the inner  parts
                    burn_shapes = [
                        (item_shape, item_class_int)
                        for (item_shape,
                             item_class_int) in zip(inner_list, class_labels)
                    ]
                    out_label = rasterize(burn_shapes,
                                          out=out_label,
                                          transform=transform,
                                          fill=0,
                                          all_touched=False,
                                          dtype=dtype)
                else:
                    print(
                        'After negative buffer operation, there is no polygon valid for rasterizing'
                    )
        else:
            print('Warning, no Polygon in %s, will save a dark label' %
                  poly_path)

        # save it to disk
        kwargs = src.meta
        kwargs.update(dtype=dtype, count=1)

        if 'nodata' in kwargs.keys():
            del kwargs['nodata']

        with rasterio.open(save_path, 'w', **kwargs) as dst:
            dst.write_band(1, out_label.astype(dtype))

    return True
Example #38
0
def SwathProfile(axis, gid, geometry):
    """
    Calculate Elevation Swath Profile for Valley Unit (axis, gid)
    """

    refaxis_shapefile = os.path.join(workdir, 'AX%03d_REFAXIS.shp' % axis)
    network_shapefile = os.path.join(workdir, 'RHT_AXIS_TILED.shp')
    elevation_raster = '/var/local/fct/RMC/RGEALTI.tif'

    with rio.open(elevation_raster) as ds:

        # Read elevations

        click.echo('Read elevations')

        window = as_window(geometry.bounds, ds.transform)
        elevations = ds.read(1,
                             window=window,
                             boundless=True,
                             fill_value=ds.nodata)
        transform = ds.transform * ds.transform.translation(
            window.col_off, window.row_off)

        height, width = elevations.shape
        buf = geometry.buffer(100.0)

        # Create DGO mask

        mask = features.rasterize([geometry],
                                  out_shape=elevations.shape,
                                  transform=transform,
                                  fill=0,
                                  default_value=1,
                                  dtype='uint8')

        # Measure and distance from reference axis

        click.echo('Measure and distance from reference axis')

        refaxis_pixels = list()

        def accept_pixel(i, j):
            x, y = ta.xy(i, j, transform)
            return all([
                i >= -height, i < 2 * height, j >= -width, j < 2 * width
            ]) and buf.contains(Point(x, y))

        coord = itemgetter(0, 1)

        # mmin = float('inf')
        # mmax = float('-inf')

        with fiona.open(refaxis_shapefile) as fs:
            for feature in fs:

                m0 = feature['properties']['M0']
                length = feature['properties']['LENGTH']

                # if m0 < mmin:
                #     mmin = m0

                # if m0 + length > mmax:
                #     mmax = m0 + length

                coordinates = np.array([
                    coord(p) + (m0, )
                    for p in reversed(feature['geometry']['coordinates'])
                ],
                                       dtype='float32')

                coordinates[1:, 2] = m0 + np.cumsum(
                    np.linalg.norm(coordinates[1:, :2] - coordinates[:-1, :2],
                                   axis=1))

                coordinates[:, :2] = ta.worldtopixel(coordinates[:, :2],
                                                     transform,
                                                     gdal=False)

                for a, b in zip(coordinates[:-1], coordinates[1:]):
                    for i, j, m in rasterize_linestringz(a, b):
                        if accept_pixel(i, j):
                            # distance[i, j] = 0
                            # measure[i, j] = m
                            refaxis_pixels.append((i, j, m))

        # mmin = math.floor(mmin / mdelta) * mdelta
        # mmax = math.ceil(mmax / mdelta) * mdelta

        mask1 = np.float32(mask)
        mask1[mask1 == 0] = ds.nodata

        measure, distance = nearest_value_and_distance(
            np.flip(np.array(refaxis_pixels), axis=0), mask1, ds.nodata)

        distance = 5.0 * distance
        distance[(elevations == ds.nodata) | (mask == 0)] = ds.nodata
        measure[(elevations == ds.nodata) | (mask == 0)] = ds.nodata

        # Relative elevations (Height above nearest drainage)

        click.echo('Relative elevations (Height above nearest drainage)')

        stream_pixels = list()

        def accept_feature(feature):

            properties = feature['properties']
            return properties['AXH'] == axis

        coord = itemgetter(0, 1, 2)
        unique = set()

        with fiona.open(network_shapefile) as fs:
            for feature in fs:

                if accept_feature(feature):

                    coordinates = np.array(
                        [coord(p) for p in feature['geometry']['coordinates']],
                        dtype='float32')

                    coordinates[:, :2] = ta.worldtopixel(coordinates[:, :2],
                                                         transform,
                                                         gdal=False)

                    for a, b in zip(coordinates[:-1], coordinates[1:]):
                        for i, j, z in rasterize_linestringz(a, b):
                            if accept_pixel(i, j) and (i, j) not in unique:
                                # distance[i, j] = 0
                                # measure[i, j] = m
                                # z = elevations[i, j]
                                stream_pixels.append((i, j, z))
                                unique.add((i, j))

        reference, _ = nearest_value_and_distance(np.array(stream_pixels),
                                                  mask1, ds.nodata)

        relz = elevations - reference
        relz[(elevations == ds.nodata) | (mask == 0)] = ds.nodata

        # Swath profiles

        click.echo('Swath profiles')

        xbins = np.arange(np.min(distance[mask == 1]),
                          np.max(distance[mask == 1]), 10.0)
        binned = np.digitize(distance, xbins)
        x = 0.5 * (xbins[1:] + xbins[:-1])
        density = np.zeros_like(x, dtype='int32')

        # Profile density

        for i in range(1, len(xbins)):

            density[i - 1] = np.sum((mask == 1) & (binned == i))

        # Absolute elevation swath profile

        swath_absolute = np.full((len(xbins) - 1, 5), np.nan, dtype='float32')

        for i in range(1, len(xbins)):

            swath_elevations = elevations[(mask == 1) & (binned == i)]
            if swath_elevations.size:
                swath_absolute[i - 1, :] = np.percentile(
                    swath_elevations, [5, 25, 50, 75, 95])

        # Relative-to-stream elevation swath profile

        swath_rel_stream = np.full((len(xbins) - 1, 5),
                                   np.nan,
                                   dtype='float32')

        for i in range(1, len(xbins)):

            swath_elevations = relz[(mask == 1) & (binned == i)]
            if swath_elevations.size:
                swath_rel_stream[i - 1, :] = np.percentile(
                    swath_elevations, [5, 25, 50, 75, 95])

        # Relative-to-valley-floor elevation swath profile

        click.echo('Fit valley floor')

        swath_rel_valley = np.full((len(xbins) - 1, 5),
                                   np.nan,
                                   dtype='float32')

        def fit_valley_floor(fit_mask=None,
                             error_threshold=1.0,
                             iterations=100):

            if fit_mask is None:
                mask0 = (mask == 1)
            else:
                mask0 = (mask == 1) & fit_mask

            size = elevations.shape[0] * elevations.shape[1]
            matrix = np.stack([
                measure.reshape(size),
                np.ones(size, dtype='float32'),
                elevations.reshape(size)
            ]).T
            matrix = matrix[mask0.reshape(size), :]
            samples = matrix.shape[0] // 10
            model = LinearModel([0, 1], [2])

            (slope, z0), _, _ = ransac(matrix, model, samples, iterations,
                                       error_threshold, 2 * samples)

            relative = elevations - (z0 + slope * measure)

            for i in range(1, len(xbins)):

                swath_elevations = relative[(mask == 1) & (binned == i)]
                if swath_elevations.size:
                    swath_rel_valley[i - 1, :] = np.percentile(
                        swath_elevations, [5, 25, 50, 75, 95])

        try:

            fit_valley_floor()

        except RuntimeError:

            try:

                fit_valley_floor(fit_mask=(relz <= 10.0))

            except RuntimeError:

                swath_rel_valley = np.array([])

        values = dict(x=x,
                      density=density,
                      swath_abs=swath_absolute,
                      swath_rel=swath_rel_stream,
                      swath_vb=swath_rel_valley)

        return axis, gid, values
Example #39
0
def test_rasterize_invalid_out_dtype(basic_geometry):
    """A non-supported data type for out should raise an exception."""
    out = np.zeros(DEFAULT_SHAPE, dtype=np.int64)
    with pytest.raises(ValueError):
        rasterize([basic_geometry], out=out)
Example #40
0
def test_rasterize_invalid_geom():
    """Invalid GeoJSON should fail with exception"""

    with pytest.raises(ValueError):
        rasterize([{'type'}], out_shape=DEFAULT_SHAPE)

    with pytest.raises(ValueError):
        rasterize([{'type': 'Invalid'}], out_shape=DEFAULT_SHAPE)

    with pytest.raises(ValueError):
        rasterize([{'type': 'Point'}], out_shape=DEFAULT_SHAPE)

    with pytest.raises(ValueError):
        # Empty coordinates should fail
        rasterize([{
            'type': 'Point',
            'coordinates': []
        }],
                  out_shape=DEFAULT_SHAPE)

    with pytest.raises(ValueError):
        # Empty GeometryCollection should fail
        rasterize([{
            'type': 'GeometryCollection',
            'geometries': []
        }],
                  out_shape=DEFAULT_SHAPE)

    with pytest.raises(ValueError):
        # GeometryCollection with bad geometry should fail
        rasterize([{
            'type': 'GeometryCollection',
            'geometries': [{
                'type': 'Invalid',
                'coordinates': []
            }]
        }],
                  out_shape=DEFAULT_SHAPE)
Example #41
0
def test_rasterize_polygon(geojson_polygon, basic_image_2x2):
    assert np.array_equal(
        rasterize([geojson_polygon], out_shape=DEFAULT_SHAPE), basic_image_2x2)
Example #42
0
def test_rasterize_internal_driver_manager(basic_geometry):
    """Rasterize should work without explicitly calling driver manager."""
    assert rasterize([basic_geometry], out_shape=DEFAULT_SHAPE).sum() == 4
Example #43
0
def test_rasterize_missing_shapes():
    """Shapes are required for this operation."""
    with pytest.raises(ValueError) as ex:
        rasterize([], out_shape=DEFAULT_SHAPE)

    assert 'No valid geometry objects' in str(ex.value)
Example #44
0
def test_rasterize_invalid_value(basic_geometry):
    """A shape value that requires an int64 should raise an exception."""
    with pytest.raises(ValueError, match="Values out of range for supported dtypes"):
        rasterize(
            [(basic_geometry, 1000000000000)], out_shape=DEFAULT_SHAPE
        )
Example #45
0
def test_rasterize_missing_out(basic_geometry):
    """If both out and out_shape are missing, should raise exception."""
    with pytest.raises(ValueError):
        rasterize([basic_geometry], out=None, out_shape=None)
Example #46
0
def test_rasterize_default_value_for_none(basic_geometry, basic_image_2x2):
    """All shapes should rasterize to the default value."""
    assert np.all(
        rasterize([(basic_geometry, None)], out_shape=DEFAULT_SHAPE, fill=2) == 2
    )
Example #47
0
def test_rasterize_invalid_geom(input):
    """Invalid GeoJSON should fail with exception"""
    with pytest.raises(ValueError), pytest.warns(ShapeSkipWarning):
        rasterize(input, out_shape=DEFAULT_SHAPE)
Example #48
0
def _mapper(x, y, z, data, args):
    """Iterate over OSM QA Tiles and return a label for each tile

    Iterate over the .mbtiles input. Decode the provided vector tile. Depending upon the
    desired type of eventual machine learning training, return a label list:
    - For 'object-detection' tasks, each list element is a bounding box like [xmin, ymin, xmax, ymax, class_index].
      There is one list element for each feature matching the provided classes.
    - For 'classification' tasks, the entire list is a "one-hot" vector representing which class
      the tile matches

    Parameters
    ------------
    x, y, z: int
        tile indices
    data: str
        Encoded vector tile data
    args: dict
        Additional arguments passed to the tile worker

    Returns
    ---------
    label: tuple
        The first element is a tile index of the form x-y-z. The second element is a list
        representing the label of the tile

    """
    ml_type = args.get('ml_type')
    classes = args.get('classes')

    if data is None:
        return ('{!s}-{!s}-{!s}'.format(x, y, z), _create_empty_label(ml_type, classes))

    tile = mapbox_vector_tile.decode(data)
    # for each class, determine if any features in the tile match

    if tile['osm']['features']:
        if ml_type == 'classification':
            class_counts = np.zeros(len(classes) + 1, dtype=np.int)
            for i, cl in enumerate(classes):
                ff = create_filter(cl.get('filter'))
                class_counts[i + 1] = int(bool([f for f in tile['osm']['features'] if ff(f)]))
            # if there are no classes, activate the background
            if np.sum(class_counts) == 0:
                class_counts[0] = 1
            return ('{!s}-{!s}-{!s}'.format(x, y, z), class_counts)
        elif ml_type == 'object-detection':
            bboxes = _create_empty_label(ml_type, classes)
            for feat in tile['osm']['features']:
                for i, cl in enumerate(classes):
                    ff = create_filter(cl.get('filter'))
                    if ff(feat):
                        geo = shape(feat['geometry'])
                        if cl.get('buffer'):
                            geo = geo.buffer(cl.get('buffer'), 4)
                        bb = _pixel_bbox(geo.bounds) + [i + 1]
                        bboxes = np.append(bboxes, np.array([bb]), axis=0)
            return ('{!s}-{!s}-{!s}'.format(x, y, z), bboxes)
        elif ml_type == 'segmentation':
            geos = []
            for feat in tile['osm']['features']:
                for i, cl in enumerate(classes):
                    ff = create_filter(cl.get('filter'))
                    if ff(feat):
                        feat['geometry']['coordinates'] = _convert_coordinates(feat['geometry']['coordinates'])
                        geo = shape(feat['geometry'])
                        try:
                            geo = geo.intersection(clip_mask)
                        except TopologicalError as e:
                            print(e, 'skipping')
                            break
                        if cl.get('buffer'):
                            geo = geo.buffer(cl.get('buffer'), 4)
                        if not geo.is_empty:
                            geos.append((mapping(geo), i + 1))
            result = rasterize(geos, out_shape=(256, 256))
            return ('{!s}-{!s}-{!s}'.format(x, y, z), result)
    return ('{!s}-{!s}-{!s}'.format(x, y, z), np.array())
Example #49
0
def prepare_roads(roads_in, aoi_in, ntl_in, include_power=True):
    """Prepare a roads feature layer for use in algorithm.

    Parameters
    ----------
    roads_in : str, Path
        Path to a roads feature layer. This implementation is specific to
        OSM data and won't assign proper weights to other data inputs.
    aoi_in : str, Path or GeoDataFrame
        AOI to clip roads.
    ntl_in : str, Path
        Path to a raster file, only used for correct shape and
        affine of roads raster.

    Returns
    -------
    roads_raster : numpy array
        Roads as a raster array with the value being the cost of traversing.
    affine : affine.Affine
        Affine raster transformation for the new raster (same as ntl_in).
    """

    ntl_rd = rasterio.open(ntl_in)
    shape = ntl_rd.read(1).shape
    affine = ntl_rd.transform

    if isinstance(aoi_in, gpd.GeoDataFrame):
        aoi = aoi_in
    else:
        aoi = gpd.read_file(aoi_in)

    roads = gpd.read_file(roads_in)
    roads = clip_line_poly(roads, aoi)

    roads["weight"] = 1
    roads.loc[roads["highway"] == "motorway", "weight"] = 1 / 10
    roads.loc[roads["highway"] == "trunk", "weight"] = 1 / 9
    roads.loc[roads["highway"] == "primary", "weight"] = 1 / 8
    roads.loc[roads["highway"] == "secondary", "weight"] = 1 / 7
    roads.loc[roads["highway"] == "tertiary", "weight"] = 1 / 6
    roads.loc[roads["highway"] == "unclassified", "weight"] = 1 / 5
    roads.loc[roads["highway"] == "residential", "weight"] = 1 / 4
    roads.loc[roads["highway"] == "service", "weight"] = 1 / 3

    # Power lines get weight 0
    roads.loc[roads["power"] == "line", "weight"] = 0

    roads = roads[roads.weight != 1]

    # sort by weight descending so that lower weight (bigger roads) are
    # processed last and overwrite higher weight roads
    roads = roads.sort_values(by="weight", ascending=False)

    roads_for_raster = [(row.geometry, row.weight)
                        for _, row in roads.iterrows()]
    roads_raster = rasterize(
        roads_for_raster,
        out_shape=shape,
        fill=1,
        default_value=0,
        all_touched=True,
        transform=affine,
    )

    return roads_raster, affine
Example #50
0
def vesper_text_to_raster(control_textfile, krig_epsg=0, nodata_value=-9999):
    """Convert an vesper kriged text file output to a prediction and a standard error (SE) tif raster, and create a
    confidence interval (CI) metadata file. If the output files already exists, they will be overwritten.

    Kriging using Vesper creates 3 new files:
        *_kriged_*.txt, *_report_*.txt, *_parameter_*.txt.

      There is a 100 character file path limitation set within vesper for the kriged and report files. By using the
      control filename as the input, the truncated files can be renamed to their correct names and is used as a base for
      derived tiff and metadata

    The *_kriged_*.txt file contains the data to create the desired outputs.

    Args:
        control_textfile (str): The control file for the associated vesper krige raster (see note above) to convert.
        krig_epsg (int): The EPSG number to assign to the output raster
        nodata_value (int): The value to assign to nodata pixels.

    Outputs:
        *_CI_*.txt      The confidence interval (CI) metadata file.
        *_PRED_*.tif    The kriged column prediction tif
        *_SE_*.tif      The kriged column standard error (SE) tif

    """

    if not os.path.exists(control_textfile):
        raise IOError("Invalid path: {}".format(control_textfile))

    for argCheck in [('krig_epsg', krig_epsg), ('nodata_value', nodata_value)]:
        if not isinstance(argCheck[1], (int, long)):
            raise TypeError('{} must be a integer.'.format(argCheck[0]))

    start_time = time.time()

    # There is a 100 character file path limitation set for the kriged and report outputs from vesper. By using the
    # control filename we can find these truncated files and correct their names.
    if len(control_textfile) > 100:
        search_dir = os.path.dirname(control_textfile)
        search_file = os.path.basename(control_textfile[:101]).replace('control', '*')
        suffix = control_textfile[101:]
        for ea_file in glob.glob(os.path.join(search_dir, search_file)):
            os.rename(ea_file, ea_file + suffix)
            logging.debug('Renaming file {} to {}'.format(ea_file, ea_file + suffix))

    krige_textfile = control_textfile.replace('control', 'kriged')
    out_CITxt = control_textfile.replace('control', 'CI')

    # using pd.read_table takes care of the multiple white space delimiter
    dfKrige = pd.read_table(krige_textfile, delim_whitespace=True)

    median_val = dfKrige['SE_Pred'].median()
    with open(out_CITxt, 'w') as ci_file:
        ci_file.writelines("Median Prediction SE    : {:.5f}\n".format(median_val))
        ci_file.writelines("95% Confidence Interval : {:.5f}\n\n".format(2 * 1.96 * median_val))
        ci_file.writelines("Date/time : " + datetime.datetime.now().strftime("%d-%b-%Y %H:%M") + "\n")
        userhome = os.path.expanduser('~')
        ci_file.writelines("Username  : "******"\n")

    LOGGER.debug("CI File contents : \n\tMedian Prediction SE    : {:.5f}\n"
                 "\t95% Confidence Interval : {:.5f}".format(median_val, 2 * 1.96 * median_val))

    x_field, y_field = predictCoordinateColumnNames(dfKrige.columns.tolist())
    gdfKrig, gdfCRS = add_point_geometry_to_dataframe(dfKrige, [x_field, y_field], krig_epsg)

    cellsize_x = float(dfKrige[x_field].sort_values().drop_duplicates().diff(1).mode())
    cellsize_y = float(dfKrige[y_field].sort_values().drop_duplicates().diff(1).mode())
    pixel_size = min(cellsize_x, cellsize_y)

    pixel_size_str = numeric_pixelsize_to_string(pixel_size)

    LOGGER.debug("Cellsize: {}  X: {}  Y: {}".format(pixel_size, cellsize_x, cellsize_y))
    out_SETif = control_textfile.replace('control', 'SE_{}'.format(pixel_size_str)).replace('.txt', '.tif')
    out_PredTif = control_textfile.replace('control', 'PRED_{}'.format(pixel_size_str)).replace('.txt', '.tif')

    # create an affine transformation matrix to associate the array to the coordinates.
    transform, x_cols, y_rows, new_bbox = create_raster_transform(list(gdfKrig.total_bounds), pixel_size=pixel_size)
    LOGGER.debug('Width (xCols):     {}   Height (yRows):     {}'.format(x_cols, y_rows))

    # create the two tifs and populate with data. This method is by far the quickest of all 3 methods trialed.
    with rasterio.open(os.path.normpath(out_PredTif), 'w', driver='GTiff',
                       width=x_cols, height=y_rows, count=1, crs=rasterio.crs.CRS.from_epsg(krig_epsg),
                       dtype='float32', nodata=-9999, transform=transform) as outPred:

        # uses points to burn values into the corresponding raster pixel.
        shapes = ((geom, value) for geom, value in zip(gdfKrig['geometry'], gdfKrig['Predicted']))
        burned = features.rasterize(shapes=shapes, out_shape=(y_rows,x_cols), transform=outPred.transform, fill=nodata_value)

        outPred.write(burned, indexes=1)

    with rasterio.open(os.path.normpath(out_SETif), 'w', driver='GTiff', width=x_cols, height=y_rows, count=1,
                       crs= rasterio.crs.CRS.from_epsg(krig_epsg), dtype='float32', nodata=-9999, transform=transform) as outSE:

        # uses points to burn values into the corresponding raster pixel.
        shapes = ((geom, value) for geom, value in zip(gdfKrig['geometry'], gdfKrig['SE_Pred']))
        burned = features.rasterize(shapes=shapes, out_shape=(y_rows,x_cols), transform=outSE.transform, fill=nodata_value)
        outSE.write(burned, indexes=1)

    LOGGER.info('{:<30}\t{dur:<15}\t{}'.format(inspect.currentframe().f_code.co_name, '',
                                               dur=datetime.timedelta(seconds=time.time() - start_time)))
    return out_PredTif, out_SETif, out_CITxt
Example #51
0
    def create_mask(self,
                    rst=None,
                    crs=None,
                    xres=None,
                    yres=None,
                    bounds=None):
        """
        Rasterize the vector features into a boolean raster which has the extent/dimensions of \
the provided raster file.

        Alternatively, user can specify a grid to rasterize on using xres, yres, bounds and crs. Only xres is mandatory, by default yres=xres and bounds/crs are set to self's.
        Vector features which fall outside the bounds of the raster file are not written to the new mask file.

        :param rst: A Raster object or string to filename
        :type rst: Raster object or str
        :param crs: A pyproj or rasterio CRS object (Default to rst.crs if not None then self.crs)
        :type crs: pyproj.crs.crs.CRS, rasterio.crs.CRS
        :param xres: Output raster spatial resolution in x. Only is rst is None.
        :type xres: float
        :param yres: Output raster spatial resolution in y. Only if rst is None. (Default to xres)
        :type yres: float
        :param bounds: Output raster bounds (left, bottom, right, top). Only if rst is None (Default to self bounds)
        :type bounds: tuple

        :returns: array containing the mask
        :rtype: numpy.array
        """
        # If input rst is string, open as Raster
        if isinstance(rst, str):
            from geoutils.georaster import Raster
            rst = Raster(rst)

        # If no rst given, use provided dimensions
        if rst is None:

            # At minimum, xres must be set
            if xres is None:
                raise ValueError('at least rst or xres must be set')
            if yres is None:
                yres = xres

            # By default, use self's CRS and bounds
            if crs is None:
                crs = self.ds.crs
            if bounds is None:
                bounds = self.ds.total_bounds

            # Calculate raster shape
            left, bottom, right, top = bounds
            height = abs((right - left) / xres)
            width = abs((top - bottom) / yres)

            if width % 1 != 0 or height % 1 != 0:
                warnings.warn(
                    "Bounds not a multiple of xres/yres, use rounded bounds")

            width = int(np.round(width))
            height = int(np.round(height))
            out_shape = (height, width)

            # Calculate raster transform
            transform = rio.transform.from_bounds(left, bottom, right, top,
                                                  width, height)

        # otherwise use directly rst's dimensions
        else:
            out_shape = rst.shape
            transform = rst.transform
            crs = rst.crs

        # Reproject vector into rst CRS
        # Note: would need to check if CRS are different
        vect = self.ds.to_crs(crs)

        # Rasterize geomtry
        mask = features.rasterize(shapes=vect.geometry,
                                  fill=0,
                                  out_shape=out_shape,
                                  transform=transform,
                                  default_value=1,
                                  dtype='uint8').astype('bool')

        # Force output mask to be of same dimension as input rst
        if rst is not None:
            mask = mask.reshape((rst.count, rst.height, rst.width))

        return mask
Example #52
0
def process_building(geom, crs, proj, btype, bid):

    #     geom, crs, proj = args

    ct = geom.centroid

    lon, lat = pyproj.transform(proj, proj_84, ct.x, ct.y)

    # open building data files
    try:

        hor5kpath = os.path.join(base_path, r"5khorizons")
        horpath = os.path.join(base_path, r"horizons")

        horfname = "{}_{}.tar.gz".format(btype, bid)
        building_path = os.path.join(horpath, horfname)

        if not os.path.exists(building_path):
            logging.info("{} no datafiles found for {}".format(
                str(datetime.datetime.now()), building_path))
            return

        zipdirpath = tempfile.mkdtemp(prefix="/tmp/")
        shutil.unpack_archive(building_path,
                              extract_dir=zipdirpath,
                              format='gztar')

        # Load slope/aspect if not existing
        if not os.path.exists(os.path.join(zipdirpath, 'slope')):
            horfnamesa = "{}_{}sa.tar.gz".format(btype, bid)
            building_path2 = os.path.join(horpath, horfnamesa)
            shutil.unpack_archive(building_path2,
                                  extract_dir=zipdirpath,
                                  format='gztar')

        def read_data(ds):
            with rasterio.open(os.path.join(zipdirpath, ds)) as src:
                return src.read()[0], src.transform, not src.meta['transform'][
                    0] == 0.5, src.meta

        slopes, fwd, bad, meta = read_data('slope')
        if bad:
            logging.info("BAD SLOPE")
            return
        aspects, fwd_a, bad, meta = read_data('aspect')
        if bad:
            logging.info("BAD ASPECT")
            return

        slopes[np.where(np.isnan(slopes))] = 99999
        aspects[np.where(np.isnan(aspects))] = 99999

        horizons = {}
        for az in range(-120, 121, 5):
            horizons[float(az)] = read_data("{}_{}_{}".format(btype, bid,
                                                              az))[0]

        horizons2 = defaultdict(lambda: 0.0)
        hor5kfname = "{}_{}_hor.txt".format(btype, bid)
        hor2_path = os.path.join(hor5kpath, hor5kfname)
        with open(hor2_path, mode='r') as ff:
            for line in ff:
                vals = list(map(float, line.strip().split(';')))
                horizons2[vals[0]] = vals[1]


#         pprint.pprint(horizons2)

#         logging.info("{} read {}_{}s".format(str(datetime.datetime.now()),
#                                              btype,
#                                              bid))
# PROCESS

        h, w = slopes.shape

        geom2 = geom.buffer(6.0)
        buildingmap = rasterize([(geom2, 1)],
                                out_shape=(h, w),
                                fill=0,
                                all_touched=True,
                                transform=fwd,
                                dtype=rasterio.uint8)

        # get 30min of year (we could optimize this)
        t = 0
        d = datetime.datetime(2017, 1, 1, 0, 0)
        while d.year == 2017:
            t += 1
            d += datetime.timedelta(minutes=30)

        # Create output file
        fpath = os.path.join(outpath, "rad30min_{}_{}.tif".format(btype, bid))
        with rasterio.open(fpath,
                           mode='w',
                           driver="GTiff",
                           width=w,
                           height=h,
                           count=t,
                           transform=fwd,
                           crs=crs,
                           nodata=NODATA,
                           dtype='float32') as dst:

            # Iterate over all radiation data, each file contains the 30 minutes values of one day
            d = datetime.date(2017, 1, 1)
            b = 0
            while d.year < 2018:
                #                 logging.info("{}_{}: {}".format(btype, bid, str(d)))
                year = d.year
                month = d.month
                day = d.day

                fname = "SISin{year}{month:02d}{day:02d}0000003231000101UD.nc".format(
                    year=year, month=month, day=day)

                src_sis = rasterio.open(os.path.join(cmsaf_path, "sis", fname))

                fwd_sis = src_sis.transform
                c_sis, r_sis = (lon, lat) * ~fwd_sis
                data_sis = src_sis.read(
                    window=Window(int(c_sis), int(r_sis), 1, 1))

                fname = "SIDin{year}{month:02d}{day:02d}0000003231000101UD.nc".format(
                    year=year, month=month, day=day)

                src_sid = rasterio.open(os.path.join(cmsaf_path, "sid", fname))

                fwd_sid = src_sid.transform
                c_sid, r_sid = (lon, lat) * ~fwd_sid
                data_sid = src_sid.read(
                    window=Window(int(c_sid), int(r_sid), 1, 1))

                # Each nc file contains the 30 minute periods of a day as band
                # We iterate over each band
                dd = datetime.datetime(year, month, day)
                end_dd = datetime.datetime(year, month,
                                           day) + datetime.timedelta(days=1)

                i = 0
                while dd < end_dd:

                    rad = np.zeros((h, w))

                    # Solar irradiation config for spa.c algorithm
                    s = csolar2.solar.Solar(lat,
                                            lon,
                                            dd,
                                            0,
                                            elevation=600,
                                            temperature=11,
                                            pressure=1020)

                    # global rad hor
                    sis = float(max(data_sis[i, 0, 0], 0))

                    # direct rad hor
                    sid = float(max(data_sid[i, 0, 0], 0))

                    # Iterate over all cells
                    for _h in range(h):
                        for _w in range(w):

                            _rad = 0.0
                            if slopes[_h, _w] < 99999 and aspects[_h,
                                                                  _w] < 99999:
                                # slope
                                beta_deg = slopes[_h, _w]

                                # azimuth
                                alpha_deg = transform_angle(aspects[_h, _w])

                                # transform alpha

                                # direct rad dif
                                dif = sis - sid
                                assert dif >= 0.0

                                dir_tilted, dif_tilted, sis_tilted = csolar2.solar.get_tilted_rad(
                                    s, sis, sid, 0.2, beta_deg, alpha_deg)

                                sun_elevation = s.get_elevation_angle()
                                sun_azimuth = round(
                                    s.get_azimuth() / 5.0) * 5.0

                                # We do nothing if we have no irradiation
                                if sis_tilted >= 0.0 and sun_elevation >= 0.0 and sun_azimuth >= -120 and sun_azimuth <= 120.0:

                                    h1 = horizons[sun_azimuth][_h, _w]
                                    h2 = horizons2[sun_azimuth]
                                    max_hor = max(h1, h2)

                                    if max_hor < sun_elevation:
                                        _rad = dir_tilted + dif_tilted
                                    else:
                                        _rad = dif_tilted

                            rad[_h, _w] = _rad
                    dst.write(rad.astype(np.float32), b + 1)
                    dd += datetime.timedelta(minutes=30)
                    i += 1
                    b += 1

                src_sis.close()
                src_sid.close()

                d += datetime.timedelta(days=1)

    except Exception as e:
        logging.error("{}: ERROR: {} \n {}".format(
            str(datetime.datetime.now()), str(e), traceback.format_exc()))
Example #53
0
    def rasterize(self,
                  rst=None,
                  crs=None,
                  xres=None,
                  yres=None,
                  bounds=None,
                  in_value=None,
                  out_value=0):
        """
        Return an array with input geometries burned in.

        By default, output raster has the extent/dimensions of the provided raster file.
        Alternatively, user can specify a grid to rasterize on using xres, yres, bounds and crs.
        Only xres is mandatory, by default yres=xres and bounds/crs are set to self's.

        Burn value is set by user and can be either a single number, or an iterable of same length as self.ds.
        Default is an index from 1 to len(self.ds).

        :param rst: A raster to be used as reference for the output grid
        :type rst: Raster object or str
        :param crs: A pyproj or rasterio CRS object (Default to rst.crs if not None then self.crs)
        :type crs: pyproj.crs.crs.CRS, rasterio.crs.CRS
        :param xres: Output raster spatial resolution in x. Only is rst is None.
        :type xres: float
        :param yres: Output raster spatial resolution in y. Only if rst is None. (Default to xres)
        :type yres: float
        :param bounds: Output raster bounds (left, bottom, right, top). Only if rst is None (Default to self bounds)
        :type bounds: tuple
        :param in_value: Value(s) to be burned inside the polygons (Default is self.ds.index + 1)
        :type in_value: int, float, iterable
        :param out_value: Value to be burned outside the polygons (Default is 0)
        :type out_value: int, float

        :returns: array containing the burned geometries
        :rtype: numpy.array
        """
        # If input rst is string, open as Raster
        if isinstance(rst, str):
            from geoutils.georaster import Raster
            rst = Raster(rst)

        # If no rst given, use provided dimensions
        if rst is None:

            # At minimum, xres must be set
            if xres is None:
                raise ValueError('at least rst or xres must be set')
            if yres is None:
                yres = xres

            # By default, use self's CRS and bounds
            if crs is None:
                crs = self.ds.crs
            if bounds is None:
                bounds = self.ds.total_bounds

            # Calculate raster shape
            left, bottom, right, top = bounds
            height = abs((right - left) / xres)
            width = abs((top - bottom) / yres)

            if width % 1 != 0 or height % 1 != 0:
                warnings.warn(
                    "Bounds not a multiple of xres/yres, use rounded bounds")

            width = int(np.round(width))
            height = int(np.round(height))
            out_shape = (height, width)

            # Calculate raster transform
            transform = rio.transform.from_bounds(left, bottom, right, top,
                                                  width, height)

        # otherwise use directly rst's dimensions
        else:
            out_shape = rst.shape
            transform = rst.transform
            crs = rst.crs

        # Reproject vector into rst CRS
        # Note: would need to check if CRS are different
        vect = self.ds.to_crs(crs)

        # Set default burn value, index from 1 to len(self.ds)
        if in_value is None:
            in_value = self.ds.index + 1

        # Rasterize geometry
        if isinstance(in_value, collections.abc.Iterable):
            if len(in_value) != len(vect.geometry):
                raise ValueError(
                    "in_value must have same length as self.ds.geometry, currently {} != {}"
                    .format(len(in_value), len(vect.geometry)))

            out_geom = ((geom, value)
                        for geom, value in zip(vect.geometry, in_value))

            mask = features.rasterize(shapes=out_geom,
                                      fill=out_value,
                                      out_shape=out_shape,
                                      transform=transform)

        elif isinstance(in_value, Number):
            mask = features.rasterize(shapes=vect.geometry,
                                      fill=out_value,
                                      out_shape=out_shape,
                                      transform=transform,
                                      default_value=in_value)
        else:
            raise ValueError(
                "in_value must be a single number or an iterable with same length as self.ds.geometry"
            )

        return mask
Example #54
0
def test_rasterize_invalid_shapes():
    """Invalid shapes should raise an exception rather than be skipped."""
    with pytest.raises(ValueError) as ex, pytest.warns(ShapeSkipWarning):
        rasterize([{'foo': 'bar'}], out_shape=DEFAULT_SHAPE)

    assert 'No valid geometry objects found for rasterize' in str(ex.value)
Example #55
0
def rasterize_polygon(polygon:Polygon, class_id:int, out:np.ndarray, all_touched=True):
    rasterize([(polygon, class_id)], out=out, all_touched=all_touched, default_value=0)
Example #56
0
def main(in_file, out_file, boundary):
    if os.path.exists(out_file):
        confirm = input(
            "The output file '{}' already exists. Do you wish to replace it? [y/n] "
            .format(out_file))
        if confirm.lower().strip() not in ['y', 'yes']:
            sys.exit()

    print('Loading DEM...')
    with rasterio.open(in_file) as ds:
        grid = ds.read()[0]
        bounds = ds.bounds
        affine = ds.profile['affine']
        width = ds.profile['width']

    if boundary:
        mask = (grid != ds.profile['nodata']).astype('uint8')

        with fiona.open(boundary, 'r') as shp:
            grid_projection = Proj('+init=EPSG:4326')
            shp_projection = Proj(shp.crs)

            ll = transform(grid_projection, shp_projection, bounds.left,
                           bounds.bottom)
            ur = transform(grid_projection, shp_projection, bounds.right,
                           bounds.top)

            features = list(shp.items(bbox=(*ll, *ur)))
            num_features = len(features)

            for i, feature in enumerate(features):
                geometry = transform_geom(shp.crs, {'init': 'EPSG:4326'},
                                          feature[1]['geometry'])
                mask |= rasterize(((geometry, 1), ),
                                  out_shape=mask.shape,
                                  transform=affine,
                                  fill=0,
                                  dtype=numpy.dtype('uint8'),
                                  default_value=1)

                print('Masking DEM... ({}%)'.format(
                    round(i / float(num_features) * 100)),
                      end='\r')
            print('')

            grid = numpy.ma.masked_where(mask == 0, grid)

    print('Writing CSV...')
    with open(out_file, 'w') as f_out:
        csv_file = csv.writer(f_out)
        csv_file.writerow(['ID1', 'ID2', 'Lat', 'Lon', 'El'])

        for i, value in enumerate(grid.ravel()):
            if is_masked(value):
                continue

            col = i % width
            row = i // width
            x, y = affine * (col, row)

            # Todo: adjust to center of cell?

            csv_file.writerow([row, col, round(y, 7), round(x, 7), value])

    print('Done.')
Example #57
0
def FindPolygonOutlet(basin, zone, root, overwrite):
    """
    DOCME
    """

    output = os.path.join(basin, zone, 'ZONEHYDRO_OUTLETS.shp')
    # output2 = os.path.join(basin, zone, 'ZONEHYDRO_OUTLET.shp')
    flow_raster = os.path.join(basin, zone, 'FLOW.tif')
    zone_shapefile = os.path.join(basin, zone, 'ZONEHYDRO_BDC.shp')
    min_lca = 1e6 / 25

    if os.path.exists(output) and not overwrite:
        # if os.path.exists(output1):
        #     click.secho('Output already exists : %s' % output1, fg='yellow')
        # if os.path.exists(output2):
        #     click.secho('Output already exists : %s' % output2, fg='yellow')
        return 0
    
    with rio.open(flow_raster) as ds:

        flow = ds.read(1)
        mask = np.zeros_like(flow, dtype=np.uint8)

        def shapes():
            with fiona.open(zone_shapefile) as fs:
                for feature in fs:
                    yield feature['geometry'], 1

        rasterize(shapes(), fill=0, transform=ds.transform, out=mask)

        outlets = list()

        with fiona.open(zone_shapefile) as fs:

            for f in fs:

                driver = fs.driver
                crs = fs.crs
                geometry = np.float32(f['geometry']['coordinates'][0])
                outlets.extend(ta.polygon_outlets(geometry, flow, mask, riotogdal(ds.transform)))

        def isdata(i, j):
            return i >= 0 and i < ds.height and j >=0 and j < ds.width

        def path(i, j, flow):
            ix, jx = i, j
            while isdata(ix, jx) and flow[ix, jx] != 0 and flow[ix, jx] != -1:
                yield ix, jx
                direction = int(np.log2(flow[ix, jx]))
                ix = ix + ci[direction]
                jx = jx + cj[direction]

        ci = [-1, -1,  0,  1,  1,  1,  0, -1]
        cj = [ 0,  1,  1,  1,  0, -1, -1, -1]

        def common_outlet(a, b, flow):
            ai, aj = a
            path_a = set(path(ai, aj, flow))
            bi, bj = b
            for i, j in path(bi, bj, flow):
                if (i, j) in path_a:
                    return i, j
            return None

        outlet = None
        score = 0
        zone_area = np.sum(mask)
        count = 0

        schema = {'geometry': 'Point', 'properties': [('CDZONEHYDRO', 'str:4'), ('DRAINAGE', 'int'), ('SCORE', 'float')]}
        options=dict(driver='ESRI Shapefile', schema=schema, crs=crs)

        queue = [(-lca, (i, j)) for (i, j), lca in outlets]
        outlets = list()
        cum_area = 0
        heapify(queue)

        while queue:

            lca, (i, j) = heappop(queue)
            lca = -lca

            if outlets and (lca < min_lca or cum_area > 0.95*zone_area):
                break

            # if lca / zone_area >= 0.005:

            #     if outlet is None:
            #         outlet = (i, j)
            #         score = lca
            #     else:
            #         o = common_outlet(outlet, (i, j), flow)
            #         if o is not None:
            #             outlet = o
            #             score += lca

            outlets.append(((i, j), lca))
            cum_area += lca

            # count += 1
            # if count > 100:
            #     break

        with fiona.open(output, 'w', **options) as dst:
            for (i, j), lca in outlets:

                geom = {
                'type': 'Point',
                'coordinates': ds.xy(i, j)
                }
                props = {
                    'CDZONEHYDRO': zone,
                    'DRAINAGE': lca,
                    'SCORE': lca/zone_area*100
                }
                
                dst.write({'geometry': geom, 'properties': props})

        # if outlet is not None:

        #     with fiona.open(output2, 'w', **options) as dst:
                
        #         geom = {
        #             'type': 'Point',
        #             'coordinates': ds.xy(*outlet)
        #         }
        #         props = {
        #             'CDZONEHYDRO': zone,
        #             'DRAINAGE': score,
        #             'SCORE': score/zone_area*100
        #         }
                
        #         dst.write({'geometry': geom, 'properties': props})

        # else:

        #     click.secho('No outlet found for zone %s' % zone, fg='red')

    return len(outlets)
Example #58
0
def test_rasterize_point(geojson_point):
    expected = np.zeros(shape=DEFAULT_SHAPE, dtype='uint8')
    expected[2, 2] = 1

    assert np.array_equal(rasterize([geojson_point], out_shape=DEFAULT_SHAPE),
                          expected)
Example #59
0
def test_rasterize_out_image(basic_geometry, basic_image_2x2):
    """Rasterize operation should succeed for an out image."""
    out = np.zeros(DEFAULT_SHAPE)
    rasterize([basic_geometry], out=out)
    assert np.array_equal(basic_image_2x2, out)
    (geom, int(value)) for geom, value in zip(
        truth_patches['geometry'], truth_patches['rstr_cd'])  #.map(labels))
]

#rasterize using the shape and transform of the satellite image
out_shape = src.shape
transform = src.transform
#out_meta  = src.meta
# 'shapes' in rasterio.rasterize  is iterable of (geometry, value) pairs
# or iterable over

array_to_rast = features.rasterize(
    shapes=shapes,
    out_shape=out_shape,
    transform=transform,
    fill=-1,
    all_touched=False,
    #default_value=1,
    dtype='float32',
)

out_meta = {
    "driver": "GTiff",
    "dtype": 'float32',
    "nodata": None,
    "height": src.height,
    "width": src.width,
    "transform": transform,
    "count": 1,
    # Specify to any crs by defining here. if you don't do so,
    # it sets up to wgs84 geographic by default (weird tho)