示例#1
0
def run_gdaldem(filepath: str, processing: str, options: str | None = None) -> np.ma.masked_array:
    """Run GDAL's DEMProcessing and return the read numpy array."""
    # Rasterio strongly recommends against importing gdal along rio, so this is done here instead.
    from osgeo import gdal

    # Converting string into gdal processing options here to avoid import gdal outside this function:
    # Riley or Wilson for Terrain Ruggedness, and Zevenberg or Horn for slope, aspect and hillshade
    gdal_option_conversion = {
        "Riley": gdal.DEMProcessingOptions(alg="Riley"),
        "Wilson": gdal.DEMProcessingOptions(alg="Wilson"),
        "Zevenberg": gdal.DEMProcessingOptions(alg="ZevenbergenThorne"),
        "Horn": gdal.DEMProcessingOptions(alg="Horn"),
        "hillshade_Zevenberg": gdal.DEMProcessingOptions(azimuth=315, altitude=45, alg="ZevenbergenThorne"),
        "hillshade_Horn": gdal.DEMProcessingOptions(azimuth=315, altitude=45, alg="Horn")
    }

    if options is None:
        gdal_option = gdal.DEMProcessingOptions(options=None)
    else:
        gdal_option = gdal_option_conversion[options]

    temp_dir = tempfile.TemporaryDirectory()
    temp_path = os.path.join(temp_dir.name, "output.tif")
    gdal.DEMProcessing(
        destName=temp_path,
        srcDS=filepath,
        processing=processing,
        options=gdal_option,
    )

    data = gu.Raster(temp_path).data
    temp_dir.cleanup()
    return data
示例#2
0
    def test_to_points(self) -> None:
        """Test the outputs of the to_points method and that it doesn't load if not needed."""
        # Create a small raster to test point sampling on
        img1 = gu.Raster.from_array(np.arange(25, dtype="int32").reshape(5, 5),
                                    transform=rio.transform.from_origin(
                                        0, 5, 1, 1),
                                    crs=4326)

        # Sample the whole raster (fraction==1)
        points = img1.to_points(1)

        # Validate that 25 points were sampled (equating to img1.height * img1.width) with x, y, and band0 values.
        assert isinstance(points, np.ndarray)
        assert points.shape == (25, 3)
        assert np.array_equal(np.asarray(points[:, 0]),
                              np.tile(np.linspace(0.5, 4.5, 5), 5))

        assert img1.to_points(0.2).shape == (5, 3)

        img2 = gu.Raster(datasets.get_path("landsat_RGB"), load_data=False)

        points = img2.to_points(10)

        assert points.shape == (10, 5)
        assert not img2.is_loaded

        points_frame = img2.to_points(10, as_frame=True)

        assert np.array_equal(points_frame.columns,
                              ["b1", "b2", "b3", "geometry"])
        assert points_frame.crs == img2.crs
示例#3
0
    def test_merge_bounds(self) -> None:
        """
        Check that merge_bounds and bounds2poly work as expected for all kinds of bounds objects.
        """
        img1 = gu.Raster(gu.datasets.get_path("landsat_B4"))
        img2 = gu.Raster(gu.datasets.get_path("landsat_B4_crop"))

        # Check union (default) - with Raster objects
        out_bounds = pt.merge_bounds((img1, img2))
        assert out_bounds[0] == min(img1.bounds.left, img2.bounds.left)
        assert out_bounds[1] == min(img1.bounds.bottom, img2.bounds.bottom)
        assert out_bounds[2] == max(img1.bounds.right, img2.bounds.right)
        assert out_bounds[3] == max(img1.bounds.top, img2.bounds.top)

        # Check intersection - with Raster objects
        out_bounds = pt.merge_bounds((img1, img2),
                                     merging_algorithm="intersection")
        assert out_bounds[0] == max(img1.bounds.left, img2.bounds.left)
        assert out_bounds[1] == max(img1.bounds.bottom, img2.bounds.bottom)
        assert out_bounds[2] == min(img1.bounds.right, img2.bounds.right)
        assert out_bounds[3] == min(img1.bounds.top, img2.bounds.top)

        # Check that the results is the same with rio.BoundingBoxes
        out_bounds2 = pt.merge_bounds((img1.bounds, img2.bounds),
                                      merging_algorithm="intersection")
        assert out_bounds2 == out_bounds

        # Check that the results is the same with a list
        out_bounds2 = pt.merge_bounds((list(img1.bounds), list(img2.bounds)),
                                      merging_algorithm="intersection")
        assert out_bounds2 == out_bounds

        # Check with gpd.GeoDataFrame
        outlines = gu.Vector(gu.datasets.get_path("glacier_outlines"))
        outlines = gu.Vector(outlines.ds.to_crs(
            img1.crs))  # reproject to img1's CRS
        out_bounds = pt.merge_bounds((img1, outlines.ds))

        assert out_bounds[0] == min(img1.bounds.left,
                                    outlines.ds.total_bounds[0])
        assert out_bounds[1] == min(img1.bounds.bottom,
                                    outlines.ds.total_bounds[1])
        assert out_bounds[2] == max(img1.bounds.right,
                                    outlines.ds.total_bounds[2])
        assert out_bounds[3] == max(img1.bounds.top,
                                    outlines.ds.total_bounds[3])
示例#4
0
def run_gdaldem(filepath: str, processing: str) -> np.ma.masked_array:
    """Run GDAL's DEMProcessing and return the read numpy array."""
    # rasterio strongly recommends against importing gdal along rio, so this is done here instead.
    from osgeo import gdal

    temp_dir = tempfile.TemporaryDirectory()
    temp_path = os.path.join(temp_dir.name, "output.tif")
    gdal.DEMProcessing(
        destName=temp_path,
        srcDS=filepath,
        processing=processing,
        options=gdal.DEMProcessingOptions(azimuth=315, altitude=45),
    )

    data = gu.Raster(temp_path).data
    temp_dir.cleanup()
    return data
示例#5
0
    def crop2raster(self, rst: gu.Raster) -> None:
        """
        Update self so that features outside the extent of a raster file are cropped.

        Reprojection is done on the fly if both data set have different projections.

        :param rst: A Raster object or string to filename
        """
        # If input is string, open as Raster
        if isinstance(rst, str):
            rst = gu.Raster(rst)

        # Convert raster extent into self CRS
        # Note: could skip this if we could test if rojections are same
        # Note: should include a method in Raster to get extent in other projections, not only using corners
        left, bottom, right, top = rst.bounds
        x1, y1, x2, y2 = warp.transform_bounds(rst.crs, self.ds.crs, left,
                                               bottom, right, top)
        self.ds = self.ds.cx[x1:x2, y1:y2]
示例#6
0
    def test_latlon_reproject(self) -> None:
        """
        Check that to and from latlon projections are self consistent within tolerated rounding errors
        """

        img = gu.Raster(gu.datasets.get_path("landsat_B4"))

        # Test on random points
        nsample = 100
        randx = np.random.randint(low=img.bounds.left,
                                  high=img.bounds.right,
                                  size=(nsample, ))
        randy = np.random.randint(low=img.bounds.bottom,
                                  high=img.bounds.top,
                                  size=(nsample, ))

        lat, lon = pt.reproject_to_latlon([randx, randy], img.crs)
        x, y = pt.reproject_from_latlon([lat, lon], img.crs)

        assert np.all(x == randx)
        assert np.all(y == randy)
示例#7
0
def test_read_paths_raster(test_dataset: str) -> None:
    assert isinstance(gu.Raster(datasets.get_path(test_dataset)), gu.Raster)
示例#8
0
"""Example scripts to open and print information about a raster."""
import geoutils as gu

# Fetch an example file
filename = gu.datasets.get_path("landsat_B4")

# Open the file
image = gu.Raster(filename)
#### TEXT
information = image.info()
#### TEXT
information = image.info(stats=True)
#### TEXT
with open("file.txt", "w") as fh:
    fh.writelines(information)
示例#9
0
    def rasterize(
        self,
        rst: str | gu.georaster.RasterType | None = None,
        crs: CRS | None = None,
        xres: float | None = None,
        yres: float | None = None,
        bounds: tuple[float, float, float, float] | None = None,
        in_value: int | float | abc.Iterable[int | float] | None = None,
        out_value: int | float = 0,
    ) -> np.ndarray:
        """
        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
        :param crs: A pyproj or rasterio CRS object (Default to rst.crs if not None then self.crs)
        :param xres: Output raster spatial resolution in x. Only is rst is None.
        :param yres: Output raster spatial resolution in y. Only if rst is None. (Default to xres)
        :param bounds: Output raster bounds (left, bottom, right, top). Only if rst is None (Default to self bounds)
        :param in_value: Value(s) to be burned inside the polygons (Default is self.ds.index + 1)
        :param out_value: Value to be burned outside the polygons (Default is 0)

        :returns: array containing the burned geometries
        """
        # If input rst is string, open as Raster
        if isinstance(rst, str):
            rst = gu.Raster(rst)  # type: ignore

        # 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  # type: ignore
            transform = rst.transform  # type: ignore
            crs = rst.crs  # type: ignore

        # 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, abc.Iterable):
            if len(in_value) != len(vect.geometry):  # type: ignore
                raise ValueError(
                    "in_value must have same length as self.ds.geometry, currently {} != {}"
                    .format(
                        len(in_value),
                        len(vect.geometry)  # type: ignore
                    ))

            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
示例#10
0
    def create_mask(
        self,
        rst: str | gu.georaster.RasterType | None = None,
        crs: CRS | None = None,
        xres: float | None = None,
        yres: float | None = None,
        bounds: tuple[float, float, float, float] | None = None,
    ) -> np.ndarray:
        """
        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
        :param crs: A pyproj or rasterio CRS object (Default to rst.crs if not None then self.crs)
        :param xres: Output raster spatial resolution in x. Only is rst is None.
        :param yres: Output raster spatial resolution in y. Only if rst is None. (Default to xres)
        :param bounds: Output raster bounds (left, bottom, right, top). Only if rst is None (Default to self bounds)

        :returns: array containing the mask
        """
        # If input rst is string, open as Raster
        if isinstance(rst, str):
            rst = gu.Raster(rst)  # type: ignore

        # 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  # type: ignore
            transform = rst.transform  # type: ignore
            crs = rst.crs  # type: ignore

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

        # Rasterize geometry
        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))  # type: ignore

        return mask
示例#11
0
import geoutils as gu

filename = gu.datasets.get_path("landsat_B4")

raster = gu.Raster(filename)

print(raster)
示例#12
0
"""
Loading and understanding Rasters
=================================

This is (right now) a dummy example for showing the functionality of :class:`geoutils.Raster`.
"""

import matplotlib.pyplot as plt

import geoutils as gu

# %%
# Example raster:
img = gu.Raster(gu.datasets.get_path("landsat_B4"))

# %%
# Info:
print(img)

# %%
# A plot:
img.show(cmap="Greys_r")
plt.show()
示例#13
0
"""Exemplify uses of crop and reproject."""
import geoutils as gu

large_image = gu.Raster(gu.datasets.get_path("landsat_B4"))

smaller_image = gu.Raster(gu.datasets.get_path("landsat_B4_crop"))
# TEXT
large_image_orig = large_image.copy(
)  # Since it gets modified inplace, we want to keep it to print stats.
large_image.crop(smaller_image)
# TEXT
large_image_reprojected = large_image.reproject(smaller_image)