Ejemplo n.º 1
0
    def apply(self, apply_fun, return_raster=False, gdaldtype=None, no_data_value=None): # apply functino to all images:
        """Apply a function to all splitted images.

        Parameters
        ----------
        apply_fun: function
            The function used to apply to all splitted images.

        Returns
        -------
        return_objs: nparray
            splitted images that have applied the function.
        """
        return_objs = []
        padded_image = self.padded_image
        geo_transforms = self.get_geo_attribute(True)['geo_transform']
        for i in range(self.n_splitted_images):
            idx_h , idx_w = self.convert_order_to_location_index(i)
            h_start_inner, h_stop_inner = self.__convert_to_inner_index_h(idx_h, idx_h)
            w_start_inner, w_stop_inner = self.__convert_to_inner_index_w(idx_w, idx_w)
            splitted_img = padded_image[h_start_inner:h_stop_inner,w_start_inner:w_stop_inner].copy()
            data = apply_fun(splitted_img)
            if return_raster:
                gt = geo_transforms[i]
                pj = self.proj
                gdaldtype = self.gdaldtype if gdaldtype is None else gdaldtype
                no_data_value = self.no_data_value if no_data_value is None else no_data_value
                raster = tgp.Raster(data, gt, pj, gdaldtype, no_data_value)
                return_objs.append(raster)
            else:
                return_objs.append(data)
        return return_objs
Ejemplo n.º 2
0
    def __getitem__(self, slice_value):
        if type(slice_value) in [int, slice]:
            h_start, h_stop = self.__process_slice_value(slice_value)
            w_start, w_stop = 0, self.n_steps_w
        elif type(slice_value) == tuple:
            h_start, h_stop = self.__process_slice_value(slice_value[0])
            w_start, w_stop = self.__process_slice_value(slice_value[1])

        h_start_inner, h_stop_inner = self.__convert_to_inner_index_h(h_start, h_stop)
        w_start_inner, w_stop_inner = self.__convert_to_inner_index_w(w_start, w_stop)

        data = self.src_image[h_start_inner:h_stop_inner, w_start_inner:w_stop_inner]
        gt = np.array(self.src_gt).copy()
        gt[[0, 3]] = tgp.npidxs_to_coords([(h_start_inner, w_start_inner)], self.src_gt)[0]
        raster = tgp.Raster(data, gt, self.proj, self.gdaldtype, self.no_data_value)
        return raster
Ejemplo n.º 3
0
def rasterize_layer(src_vector,
                    rows,
                    cols,
                    geo_transform,
                    use_attribute,
                    all_touched=False,
                    no_data_value=0):
    """Rasterize vector data. Get the cell value in defined grid (rows, cols, geo_transform)
    from its overlapped polygon.

    Parameters
    ----------
    src_vector: Geopandas.GeoDataFrame
        Which vector data to be rasterize.
    rows: int
        Target rasterized image's rows.
    cols: int
        Target rasterized image's cols.
    geo_transform: tuple
        Target rasterized image's geo_transform which is the affine parameter.
    use_attribute: str
        The column to use as rasterized image value.
    all_touched: bool, optioonal, default: False
        Pixels that touch (not overlap over 50%) the polygon will be assign the use_attribute value of the polygon.
    no_data_value: int or float
        The pixels not covered by any polygon will be filled no_data_value.

    Returns
    -------
    raster: Raster. 
        Rasterized result.

    Examples
    -------- 
    >>> import geopandas as gpd
    >>> import TronGisPy as tgp 
    >>> from TronGisPy import ShapeGrid
    >>> from matplotlib import pyplot as plt
    >>> ref_raster_fp = tgp.get_testing_fp('satellite_tif') # get the geoinfo from the raster
    >>> src_vector_fp = tgp.get_testing_fp('satellite_tif_clipper') # read source shapefile as GeoDataFrame
    >>> src_vector = gpd.read_file(src_vector_fp)
    >>> src_vector['FEATURE'] = 1 # make the value to fill in the raster cell
    >>> rows, cols, geo_transform = tgp.get_raster_info(ref_raster_fp, ['rows', 'cols', 'geo_transform'])
    >>> raster = ShapeGrid.rasterize_layer(src_vector, rows, cols, geo_transform, use_attribute='FEATURE', no_data_value=99)
    >>> fig, (ax1, ax2) = plt.subplots(1,2) # plot the result
    >>> tgp.read_raster(ref_raster_fp).plot(ax=ax1)
    >>> src_vector.plot(ax=ax1)
    >>> ax1.set_title('polygon with ref_raster')
    >>> raster.plot(ax=ax2)
    >>> ax2.set_title('rasterized image')
    >>> plt.show()
    """
    # Open your shapefile
    assert type(
        src_vector
    ) is gpd.GeoDataFrame, "src_vector should be GeoDataFrame type."
    assert use_attribute in src_vector.columns, "attribute not exists in src_vector."
    gdaldtype = tgp.npdtype_to_gdaldtype(src_vector[use_attribute].dtype)
    # projection = src_vector.crs.to_wkt() if src_vector.crs is not None else None
    projection = pyproj.CRS(
        src_vector.crs).to_wkt() if src_vector.crs is not None else None
    src_shp_ds = ogr.Open(src_vector.to_json())
    src_shp_layer = src_shp_ds.GetLayer()

    # Create the destination raster data source
    ds = tgp.write_gdal_ds(bands=1,
                           cols=cols,
                           rows=rows,
                           geo_transform=geo_transform,
                           gdaldtype=gdaldtype,
                           no_data_value=no_data_value)

    # set it to the attribute that contains the relevant unique
    options = ["ATTRIBUTE=" + use_attribute]
    if all_touched:
        options.append('ALL_TOUCHED=TRUE')
    gdal.RasterizeLayer(
        ds, [1], src_shp_layer, options=options
    )  # target_ds, band_list, source_layer, options = options

    data = ds.GetRasterBand(1).ReadAsArray()
    raster = tgp.Raster(data, geo_transform, projection, gdaldtype,
                        no_data_value)
    return raster
Ejemplo n.º 4
0
def clip_raster_with_multiple_polygons(src_raster,
                                       src_poly,
                                       partitions=10,
                                       return_raster=False,
                                       no_data_value=None,
                                       seed=None):
    """Clip raster with multiple polygons in the same shp as independent image.

    Parameters
    ----------
    src_raster: Raster
        Which raster data to be clipped.
    src_poly: Geopandas.GeoDataFrame
        The clipper(clipping boundary).
    partitions: int, default: 10
        The number of partitions used to split all polygons in diferent parts 
        and rasterize them in different iterations in order to avoid overlapping 
        when rasterizing.
    return_raster:bool, optional, default: False
        Return np.array if return_raster == False, else return tgp.Raster.
    no_data_value:int, optional
        Set no_data_value for clipped image. If None, use src_raster.no_data_value 
        as default. If src_raster.no_data_value is None, use 0 as default.
    seed: int, optional
        Seed to split partitions.

    Returns
    -------
    dst_raster: Raster 
        Clipped result.

    Examples
    -------- 
    >>> import numpy as np
    >>> import geopandas as gpd
    >>> import TronGisPy as tgp
    >>> from TronGisPy import ShapeGrid
    >>> from matplotlib import pyplot as plt
    >>> src_raster_fp = tgp.get_testing_fp('multiple_poly_clip_ras')
    >>> src_poly_fp = tgp.get_testing_fp('multiple_poly_clipper')
    >>> src_raster = tgp.read_raster(src_raster_fp)
    >>> src_shp = gpd.read_file(src_poly_fp)
    >>> clipped_imgs = ShapeGrid.clip_raster_with_multiple_polygons(src_raster, src_shp, return_raster=True)
    >>> fig, axes = plt.subplots(2, 5, figsize=(9, 6))
    >>> axes = axes.flatten()
    >>> for idx, ax in zip(np.arange(100, 100+10, 1), axes):
    >>>     clipped_imgs[idx].plot(ax=ax)
    >>> fig.suptitle("TestShapeGrid" + ": " + "test_clip_raster_with_multiple_polygons")
    >>> plt.show()
    """
    # init resource
    assert (len(src_poly) // partitions) < np.iinfo(
        np.int32
    ).max, "Please increase partitions in order the gdal type overflow issue."
    df_poly_for_rasterize = src_poly.copy()
    partitions = len(src_poly) if len(src_poly) < partitions else partitions
    df_poly_for_rasterize.loc[:, 'id'] = range(len(df_poly_for_rasterize))
    parts = __split_idxs_partitions(df_poly_for_rasterize['id'].values,
                                    partitions=partitions,
                                    seed=seed)
    if no_data_value is None:
        no_data_value = 0 if src_raster.no_data_value is None else src_raster.no_data_value

    # rasterize by its id and clipping
    clipped_imgs = []
    for ps_idx, ps in enumerate(
            parts
    ):  # deal with one part of poly in shp per loop: 1. rasterize => 2. find each poly in the shp
        # 1. rasterize: rasterize only df_plot['id'].isin(ps) (only id in the splitted shp)
        df_poly_for_rasterize_ps = pd.concat([
            df_poly_for_rasterize[df_poly_for_rasterize['id'] == p].copy()
            for p in ps
        ])
        df_poly_for_rasterize_ps.loc[:, 'id_ps'] = np.array(range(
            len(df_poly_for_rasterize_ps)),
                                                            dtype=np.int32)
        raster_poly_part = rasterize_layer(df_poly_for_rasterize_ps,
                                           src_raster.rows,
                                           src_raster.cols,
                                           src_raster.geo_transform,
                                           use_attribute='id_ps',
                                           all_touched=True,
                                           no_data_value=-1)

        for id_p in range(len(df_poly_for_rasterize_ps)):
            # 2. find each the location (in the raster) of each poly in the shp
            coords = df_poly_for_rasterize_ps[df_poly_for_rasterize_ps['id_ps']
                                              == id_p].total_bounds.reshape(
                                                  2, 2)
            npidxs = CRS.coords_to_npidxs(coords, src_raster.geo_transform)
            row_idxs_st, row_idxs_end, col_idxs_st, col_idxs_end = np.min(
                npidxs[:, 0]), np.max(npidxs[:, 0]) + 1, np.min(
                    npidxs[:, 1]), np.max(npidxs[:, 1]) + 1
            clipped_img = src_raster.data[row_idxs_st:row_idxs_end,
                                          col_idxs_st:col_idxs_end].copy()
            ploy_mask = raster_poly_part.data[row_idxs_st:row_idxs_end,
                                              col_idxs_st:col_idxs_end,
                                              0] == id_p
            if np.sum(ploy_mask) > 0:
                # generate clipped image
                clipped_img[~ploy_mask] = no_data_value
                if return_raster:
                    gt = np.array(src_raster.geo_transform)
                    gt[[0, 3
                        ]] = CRS.npidxs_to_coords([(row_idxs_st, col_idxs_st)],
                                                  src_raster.geo_transform)[0]
                    clipped_img = tgp.Raster(clipped_img, tuple(gt),
                                             src_raster.projection,
                                             src_raster.gdaldtype,
                                             no_data_value,
                                             src_raster.metadata)
                clipped_imgs.append(clipped_img)
            else:
                clipped_imgs.append(None)

        # na_percentage = np.sum([c is None for c in clipped_imgs[-len(df_poly_for_rasterize_ps):]]) / len(df_poly_for_rasterize_ps)
        # if na_percentage != 0 :
        #     print(ps_idx, na_percentage)

    clipped_imgs = [clipped_imgs[i] for i in np.argsort(np.hstack(parts))]
    return clipped_imgs