def test_show_tru_color_image(self):
     image = Raster \
         .read \
         .format("geotiff") \
         .options(crs=Crs("epsg:4326")) \
         .load(
         TEST_IMAGE_PATH)
     image.show(true_color=True)
    def test_different_crs_and_extent_crs(self):

        with self.assertRaises(CrsException):
            image = Raster \
                .read \
                .format("geotiff") \
                .options(crs=Crs("epsg:4326")) \
                .load(TEST_IMAGE_PATH)

            label = Raster \
                .read \
                .format("shp") \
                .options(
                extent=image.extent,
                crs=Crs("epsg:2008"),
                pixel=image.pixel
            ) \
                .load(self.shape_path)
    def test_split_image_to_cnn(self):
        px = Pixel(1.0, 1.0)
        epsg_4326 = Crs("epsg:4326")
        image_array = np.array([[*list(range(1, 8))], [*list(range(2, 9))],
                                [*list(range(3, 10))], [*list(range(4, 11))],
                                [*list(range(5, 12))], [*list(range(10, 17))],
                                [*list(range(20, 27))]]).reshape(7, 7, 1)

        image = Raster.from_array(image_array,
                                  extent=Extent.from_coordinates(
                                      [0, 0, 7.0, 7.0], epsg_4326),
                                  pixel=px)

        target_result = [
            Raster.from_array(image_array[0:5, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[0:5, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[0:5, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px)
        ]

        function_result = split_images_to_cnn(image=image, window_size=5)

        self.assertEqual(target_result, function_result)
Beispiel #4
0
 def load_from_file(cls, path: str, crs=None):
     """
     class method which based on path returns GdalImage object,
     It validates path location and its format
     :return: GdalImage instance
     """
     file = ImageFile(path)
     ds: gdal.Dataset = gdal.Open(file.path)
     if crs is None:
         projection = ds.GetProjection()
         srs = osr.SpatialReference(wkt=projection)
         crs_gdal = srs.GetAttrValue('AUTHORITY', 0).lower() + ":" + srs.GetAttrValue('AUTHORITY', 1)
         crs = Crs(crs_gdal)
     return cls(ds, path, crs)
    def _find_extent_from_multiple_wkt(cls,
                                       wkt_value_list,
                                       crs=Crs("epsg:4326")):
        from gis import Extent, Point

        bottom_corners = [el[0].extent.left_down for el in wkt_value_list]
        top_corners = [el[0].extent.right_up for el in wkt_value_list]

        min_x = min(bottom_corners, key=lambda x: x.x).x
        min_y = min(bottom_corners, key=lambda x: x.y).y
        max_x = max(top_corners, key=lambda x: x.x).x
        max_y = max(top_corners, key=lambda x: x.y).y

        extent = Extent(Point(min_x, min_y), Point(max_x, max_y), crs=crs)
        return extent
Beispiel #6
0
class Polygon(ShapelyPolygon):
    NAME = "Polygon"
    coordinates = attr.ib(type=List[List[float]])
    crs = attr.ib(default=Crs("epsg:4326"))

    def __attrs_post_init__(self):
        super().__init__(self.coordinates)

    @classmethod
    def from_wkt(cls, wkt, crs):
        polygon = wkt_loader.loads(wkt)
        try:
            assert polygon.type == cls.NAME
        except AssertionError:
            raise TypeError(f"wkt is type {polygon.type}")

        return cls(polygon.exterior.coords, crs)
Beispiel #7
0
    def from_file(cls, path, driver="ESRI Shapefile") -> 'GeometryFrame':
        """
        :param path: File location
        :param driver: Driver for operning the file, currentyl supported drivers are ex.
        ESRI Shapefile
        GeoJSON
        GPKG
        OpenFileGDB
        For all  supported drivers look at
        ```python
            import fiona
            fiona.supported_drivers
        ```
        :return: GeometryFrame
        """
        geometry = gpd.read_file(path, driver=driver)
        GeoFrame = cls(geometry, "geom", Crs(geometry.crs["init"]))

        return GeoFrame
class TestAnnPreparation(TestCase):
    empty_array_image = np.array([[[1, 2, 3], [5, 4, 7], [9, 3, 5]],
                                  [[5, 4, 7], [5, 4, 7], [9, 3, 5]],
                                  [[9, 3, 5], [5, 4, 7], [9, 3, 5]]])
    empty_array_label = np.array([[3, 20, 4], [11, 5, 10],
                                  [20, 5, 4]]).reshape(3, 3, 1)
    image = r.Raster.from_array(empty_array_image,
                                pixel=rc.Pixel(1.0, 1.0),
                                extent=Extent.from_coordinates(
                                    [0, 0, 1, 1], crs=Crs(epsg="epsg:2180")))
    label = r.Raster.from_array(empty_array_label,
                                pixel=image.pixel,
                                extent=image.extent)

    ann_data = AnnDataCreator(label=empty_array_label, image=empty_array_image)

    def test_label_wide(self):
        target_res = np.array([[3], [20], [4], [11], [5], [10], [20], [5],
                               [4]])
        wide_label = self.ann_data.wide_label
        self.assertEqual(np.array_equal(wide_label, target_res), True)

    def test_image_wide(self):
        target_res = np.array([[1, 2, 3], [5, 4, 7], [9, 3, 5], [5, 4, 7],
                               [5, 4, 7], [9, 3, 5], [9, 3, 5], [5, 4, 7],
                               [9, 3, 5]])
        wide_image = self.ann_data.wide_image
        self.assertEqual(np.array_equal(wide_image, target_res), True)

    def test_concat_arrays(self):
        target_res = np.array([[1, 2, 3, 3], [5, 4, 7, 20], [9, 3, 5, 4],
                               [5, 4, 7, 11], [5, 4, 7, 5], [9, 3, 5, 10],
                               [9, 3, 5, 20], [5, 4, 7, 5], [9, 3, 5, 4]])
        concat_ = self.ann_data.concat_arrays()
        self.assertEqual(np.array_equal(concat_, target_res), True)

    def test_create(self):
        target_test_x = np.array([[5, 4, 7], [9, 3, 5]])
        target_test_y = np.array([[11], [4]])
        self.assertEqual(
            np.array_equal(target_test_x,
                           self.ann_data.create().x_test), True)
        self.assertEqual(
            np.array_equal(target_test_y,
                           self.ann_data.create().y_test), True)

    def test_split_image_to_cnn(self):
        px = Pixel(1.0, 1.0)
        epsg_4326 = Crs("epsg:4326")
        image_array = np.array([[*list(range(1, 8))], [*list(range(2, 9))],
                                [*list(range(3, 10))], [*list(range(4, 11))],
                                [*list(range(5, 12))], [*list(range(10, 17))],
                                [*list(range(20, 27))]]).reshape(7, 7, 1)

        image = Raster.from_array(image_array,
                                  extent=Extent.from_coordinates(
                                      [0, 0, 7.0, 7.0], epsg_4326),
                                  pixel=px)

        target_result = [
            Raster.from_array(image_array[0:5, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[0:5, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[0:5, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[1:6, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 0:5],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 1:6],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px),
            Raster.from_array(image_array[2:7, 2:7],
                              extent=Extent.from_coordinates([0, 0, 1, 1],
                                                             crs=epsg_4326),
                              pixel=px)
        ]

        function_result = split_images_to_cnn(image=image, window_size=5)

        self.assertEqual(target_result, function_result)
 def test_geometry_frame_from_file(self):
     gdf = GeometryFrame.from_file(self.shape_path)
     self.assertEqual(gdf.crs, Crs("epsg:26917"))
 def test_extent_comparison(self):
     extent1 = Extent.from_coordinates([100.0, 100.0, 120.0, 120.0],
                                       crs=Crs("epsg:4326"))
     extent2 = Extent.from_coordinates([100.00, 100.00, 120.00, 120.00],
                                       crs=Crs("epsg:4326"))
     assert extent1 == extent2
 def test_polygon_from_wkt(self):
     poly = Polygon.from_wkt(
         "POLYGON((0.0 0.0, 0.0 1.0, 1.0 1.0, 1.0 0.0, 0.0 0.0))",
         Crs("local"))
     self.assertEqual(poly.area, 1.0)
Beispiel #12
0
class Extent:
    left_down = attr.ib(default=Point(0, 0))
    right_up = attr.ib(default=Point(1, 1))
    crs = attr.ib(default=Crs("epsg:4326"))
    origin = attr.ib(init=False)
    dx = attr.ib(init=False)
    dy = attr.ib(init=False)

    def __attrs_post_init__(self):
        self.origin = Origin(self.left_down.x, self.left_down.y)
        self.dx = count_delta(self.left_down.x, self.right_up.x)
        self.dy = count_delta(self.left_down.y, self.right_up.y)

    def transform(self, to_crs):

        pass

    def scale(self, x, y, origin=Point(0, 0)):
        """
        This function takes x and y as the scaling values and divide extent dx and dy by them
        If origin Point is not passed by default it is Point(0, 0)
        :param x: Scaling value x
        :param y: Scaling value y
        :param origin: is the left down corner from which scaled extent will have origin
        :return: returns New instance of extent
        """
        scaled_point = Point(int(self.dx / x + origin.x),
                             int(self.dy / y + origin.y))
        shrinked = Extent(origin, scaled_point)

        return shrinked

    def translate(self, x, y):
        """
        Translates extent coordinates
        :param x:
        :param y:
        :return:
        """

        return Extent(self.left_down, self.right_up.translate(x, y))

    @classmethod
    def from_coordinates(cls, coordinates: List[float], crs="local"):
        point_a = Point(*coordinates[:2])
        point_b = Point(*coordinates[2:])

        return cls(point_a, point_b, crs)

    def expand(self, dx, dy):
        ld = self.left_down.translate(-dx, -dy)
        ru = self.right_up.translate(dx, dy)

        return Extent(ld, ru, crs=self.crs)

    def expand_percentage(self, percent_x, percent_y):
        return self.expand(int(self.dx * percent_x), int(self.dy * percent_y))

    def expand_percentage_equally(self, percent):
        return self.expand_percentage(percent, percent)

    def expand_equally(self, value):
        return self.expand(value, value)

    def to_wkt(self):
        coordinates = [
            self.left_down,
            self.left_down.translate(0, self.dy), self.right_up,
            self.left_down.translate(self.dx, 0), self.left_down
        ]

        coordinates_text = ", ".join([f"{el.x} {el.y}" for el in coordinates])
        return f"POLYGON(({coordinates_text}))"

    def divide_dy(self, tile_size):
        tiles_number_dy = int(float(self.dy) // float(tile_size))
        extents = []
        for tile in range(0, tiles_number_dy):
            extents.append(
                Extent(self.right_up.translate(-self.dx,
                                               -(tile + 1) * tile_size),
                       self.right_up.translate(0, (-tile) * tile_size),
                       crs=self.crs))
        if int(float(self.dy) //
               float(tile_size)) != float(self.dy) / float(tile_size):
            extents.append(
                Extent(
                    self.right_up.translate(-self.dx, -self.dy),
                    self.right_up.translate(0, -tiles_number_dy * tile_size),
                    self.crs))
        return extents

    def divide_dx(self, tile_size):
        tiles_number_dx = int(float(self.dx) // float(tile_size))
        extents = []

        for tile in range(tiles_number_dx):
            extents.append(
                Extent(self.left_down.translate(tile * tile_size, 0),
                       self.left_down.translate((tile + 1) * tile_size,
                                                self.dy),
                       crs=self.crs))
        if int(float(self.dx) //
               float(tile_size)) == float(self.dx) / float(tile_size):
            extents.append(
                Extent(
                    self.left_down.translate(tiles_number_dx * tile_size, 0),
                    self.left_down.translate(self.dx, self.dy), self.crs))

        return extents

    def divide(self, dx, dy):

        if all([dx, dy]):
            dy_divided = self.divide_dy(dy)
            extents = []
            for dy_tile in dy_divided:
                dx_divided = dy_tile.divide_dx(dx)
                for dx_tile in dx_divided:
                    extents.append(dx_tile)
            return extents
        else:
            raise AttributeError("You have to pass all the arguments")
        pass
Beispiel #13
0
class GeometryFrame:
    frame = attr.ib()
    geometry_column = attr.ib()
    crs = attr.ib(default=Crs("epsg:4326"))

    def __attr__post_init__(self):
        self.type = self.__class__.__name__

    def to_wkt(self) -> 'GeometryFrame':
        """
        Based on geometry column this method returns wkt representation of it, it does not modify
        passed instance, it create new one

        :return: GeometryFrame with new wkt column
        """

        frame_copy = self.frame.copy()
        frame_copy["wkt"] = frame_copy["geometry"].apply(lambda x: x.wkt)

        return self.__class__(frame_copy, "geometry", crs=self.crs)

    @classmethod
    def from_file(cls, path, driver="ESRI Shapefile") -> 'GeometryFrame':
        """
        :param path: File location
        :param driver: Driver for operning the file, currentyl supported drivers are ex.
        ESRI Shapefile
        GeoJSON
        GPKG
        OpenFileGDB
        For all  supported drivers look at
        ```python
            import fiona
            fiona.supported_drivers
        ```
        :return: GeometryFrame
        """
        geometry = gpd.read_file(path, driver=driver)
        GeoFrame = cls(geometry, "geom", Crs(geometry.crs["init"]))

        return GeoFrame

    def transform(self, crs) -> 'GeometryFrame':
        """
        Transform GeometryFrame to other coordinate reference system
        :param crs: crs code example 'epsg:2180'
        :return: GeometryFrame with target coordinate reference system
        """
        return self.__class__(
            self.frame.to_crs({"init": crs}),
            crs=crs,
            geometry_column=self.geometry_column
        )

    def union(self, attribute) -> 'GeometryFrame':
        """

        :param attribute: name of column based on which dissolve will be done on geometry column
        :return: GeometryFrame
        """
        dissolved = self.frame.dissolve(by=attribute, aggfunc='sum')
        geoframe = self.__class__(dissolved, "geometry")
        geoframe.type = "Multi" + self.type
        geoframe.crs = self.crs
        return geoframe

    def _assert_geom_type(self):
        unique_geometries = [el for el in set(self.frame.type) if el is not None]
        if unique_geometries.__len__() != 1:
            raise GeometryCollectionError("Object can not be collection of geometries")

        try:
            assert str(list(set(self.frame.type))[0]) + "Frame" == self.type
        except AssertionError:
            raise GeometryTypeError("Your input geometry type is incorrect")

    def show(self, limit=5, truncate=True) -> NoReturn:
        """
        This function will show GeometryFrame in Apache Spark ASCII style
        :param limit: how many rows to show
        :param truncate: decide if record values should be truncated to 20 chars
        :return: NoReturn
        """
        DataFrameShower(self.frame).show(limit, truncate)

    def plot(self, interactive=False, **kwargs) -> NoReturn:
        """

        :param interactive: decide if this function should use folium or geopandas plotting function
        if Interactive is set to True than folium library will be used if False than geopandas plotting
        library.
        :param kwargs: Other arguments for plotting, look at geoframe plot function and folium Map constructor
        :return: NoReturn
        """
        if interactive:
            return InteractiveGeometryPlotter(self).plot(**kwargs)
        else:
            self.frame.plot(**kwargs)

    def head(self, limit=5):
        """
        This function returns number of rows specified in argument limit
        :param limit: How many rows to return
        :return:
        """
        return self.frame.head(limit)
Beispiel #14
0
 def in_memory(cls, x_shape, y_shape, crs=Crs("epsg:4326")):
     memory_ob = gdal.GetDriverByName('MEM')
     raster = memory_ob.Create('', x_shape, y_shape, 1, gdal.GDT_Byte)
     if raster is None:
         raise ValueError("Your image is to huge, please increase pixel size, by using pixel option in loading options, example pixel=Pixel(20.0, 20.0)")
     return cls(raster, crs=crs)
Beispiel #15
0
class GdalImage:

    ds = attr.ib(type=gdal.Dataset)
    path = attr.ib(default=None)
    crs = attr.ib(default=Crs("local"))

    def __attrs_post_init__(self):
        from gis import Pixel
        self.__transform_params = self.ds.GetGeoTransform()
        self.left_x = self.__transform_params[0]
        self.pixel_size_x = self.__transform_params[1]
        self.top_y = self.__transform_params[3]
        self.pixel_size_y = -self.__transform_params[5]
        self.x_size = self.ds.RasterXSize
        self.y_size = self.ds.RasterYSize
        self.pixel = Pixel(abs(self.pixel_size_x), abs(self.pixel_size_y))
        self.extent = Extent.from_coordinates([
            self.left_x, self.top_y - (self.y_size * abs(self.pixel_size_y)),
            self.left_x + abs(self.pixel_size_x) * self.x_size, self.top_y
        ], self.crs)
        self.band_number = self.ds.RasterCount

    @classmethod
    def load_from_file(cls, path: str, crs=None):
        """
        class method which based on path returns GdalImage object,
        It validates path location and its format
        :return: GdalImage instance
        """
        file = ImageFile(path)
        ds: gdal.Dataset = gdal.Open(file.path)
        if crs is None:
            projection = ds.GetProjection()
            srs = osr.SpatialReference(wkt=projection)
            crs_gdal = srs.GetAttrValue('AUTHORITY', 0).lower() + ":" + srs.GetAttrValue('AUTHORITY', 1)
            crs = Crs(crs_gdal)
        return cls(ds, path, crs)

    @classmethod
    def in_memory(cls, x_shape, y_shape, crs=Crs("epsg:4326")):
        memory_ob = gdal.GetDriverByName('MEM')
        raster = memory_ob.Create('', x_shape, y_shape, 1, gdal.GDT_Byte)
        if raster is None:
            raise ValueError("Your image is to huge, please increase pixel size, by using pixel option in loading options, example pixel=Pixel(20.0, 20.0)")
        return cls(raster, crs=crs)

    @classmethod
    def from_extent(cls, extent, pixel):
        new_extent = extent.scale(pixel.x, pixel.y)

        extent_new = Extent(Point(extent.origin.x, extent.origin.y),
                            Point((new_extent.origin.x + new_extent.dx) * pixel.x,
                                  (new_extent.origin.y + new_extent.dy) * pixel.y))

        raster = cls.in_memory(int(new_extent.dx), int(new_extent.dy), crs=extent.crs)

        transformed_raster = raster.transform(extent.origin, pixel)

        return transformed_raster, extent_new

    def __read_as_array(self, ds: gdal.Dataset) -> np.ndarray:
        if not hasattr(self, "__array"):
            setattr(self, "__array", ds.ReadAsArray())
        return getattr(self, "__array")

    def __str__(self):
        return "\n".join([f"{key}: {value}" for key, value in self.__dict__.items()])

    @property
    def array(self) -> np.ndarray:
        """
        Property which returns numpy.ndarray representation of file
        :return: np.ndarray
        """
        return self.__read_as_array(self.ds)

    def to_raster(self) -> Tuple['Pixel', 'ReferencedArray']:
        if self.array.shape.__len__() == 3:
            arr = self.array
        elif self.array.shape.__len__() == 2:
            arr = self.array.reshape(1, *self.array.shape)
        else:
            raise DimensionException("Array should be shape 2 or 3")

        ref = ReferencedArray(
            array=arr.transpose([1, 2, 0]),
            crs=self.crs,
            extent=self.extent,
            band_number=self.band_number,
            shape=[self.pixel_size_y,
                   self.pixel_size_x]
        )
        return self.pixel, ref

    def transform(self, origin: 'Origin', pixel: 'Pixel', projection='LOCAL_CS["arbitrary"]'):
        self.ds.SetGeoTransform((origin.x, pixel.x, 0.0, origin.y + (self.y_size * pixel.y), 0, -pixel.y))
        left_top_corner_x, pixel_size_x, _, left_top_corner_y, _, pixel_size_y = self.ds.GetGeoTransform()
        self.ds.SetProjection(projection)

        return GdalImage(self.ds, crs=self.crs)

    def insert_polygon(self, wkt, value):
        srs = osr.SpatialReference('LOCAL_CS["arbitrary"]')
        rast_ogr_ds = ogr.GetDriverByName('Memory').CreateDataSource('wrk')
        rast_mem_lyr = rast_ogr_ds.CreateLayer('poly', srs=srs)
        feat = ogr.Feature(rast_mem_lyr.GetLayerDefn())
        feat.SetGeometryDirectly(ogr.Geometry(wkt=wkt))
        rast_mem_lyr.CreateFeature(feat)
        err = gdal.RasterizeLayer(self.ds, [1], rast_mem_lyr, None, None, [value], ['ALL_TOUCHED=TRUE'])

        return GdalImage(self.ds)