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
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
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
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