def get_gridded_boundary(shapefile, cell_size=1000): # Get its bounds from new projected bbox = shapefile.geometry.bounds # Get the bounding box of the area area_bbox = sentinelhub.BBox(bbox=[(bbox['minx'], bbox['miny']), (bbox['maxx'], bbox['maxy'])], crs=sentinelhub.CRS.WGS84) # Convert into UTM projection (in meters) area_bbox = sentinelhub.geo_utils.to_utm_bbox(area_bbox) shapefile = shapefile.to_crs(str(area_bbox.crs)) bbox = shapefile.geometry.bounds ###Build the grid def get_shape_area(bbox, distance=cell_size): ##Would like division into 100*100 patches # Number of vertical patch xmin - xmax c1 = int((bbox['maxx'] - bbox['minx']) / distance) # + int((bbox['maxx'] - bbox['minx'])%distance) # Number of horizontal patch xmin - xmax c2 = int((bbox['maxy'] - bbox['miny']) / distance) # + int((bbox['maxy'] - bbox['miny'])%distance) return ((c1, c2)) split_shape = get_shape_area(bbox, distance=cell_size) bbox_splitter = BBoxSplitter([area_bbox.geometry], area_bbox.crs, split_shape) bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) # Prepare info of selected EOPatches geometry = [Polygon(bbox.get_polygon()) for bbox in bbox_list] # idxs = [info['index'] for info in info_list] idxs_x = [info['index_x'] for info in info_list] idxs_y = [info['index_y'] for info in info_list] gdf = gpd.GeoDataFrame({ 'index_x': idxs_x, 'index_y': idxs_y }, crs=shapefile.crs, geometry=geometry) gdf.reset_index(inplace=True) # Get the intersection of the contours from shapefile with the grid gdf['results'] = gdf.geometry.apply( lambda x: shapefile.geometry.intersection(x)) # Construct a boolean associated booleans = np.array([(1 - k.is_empty) for k in gdf.results]) gdf['check'] = booleans valid_obs = gdf.check.astype(bool) gdf = gdf.drop(['check'], axis=1) return gdf[valid_obs]
def setUpClass(cls): geojson = read_data(os.path.join(cls.INPUT_FOLDER, 'cies_islands.json')) cls.area = shape(geojson) cls.test_cases = [ cls.SplitterTestCase('BBoxSplitter', BBoxSplitter([cls.area], CRS.WGS84, 5, reduce_bbox_sizes=True), bbox_len=19), cls.SplitterTestCase('OsmSplitter', OsmSplitter([cls.area], CRS.WGS84, 15, reduce_bbox_sizes=True), bbox_len=24), cls.SplitterTestCase('TileSplitter', TileSplitter( [cls.area], CRS.WGS84, ('2017-10-01', '2018-03-01'), tile_split_shape=40, data_source=DataSource.SENTINEL2_L1C, reduce_bbox_sizes=True), bbox_len=13) ]
def setUpClass(cls): super().setUpClass() geojson = read_data(os.path.join(cls.INPUT_FOLDER, 'cies_islands.json')) cls.area = shapely.geometry.shape(geojson) bbox_grid = [BBox((x / 10, y / 100, (x + 1) / 10, (y + 1) / 100), CRS.WGS84) for x, y in itertools.product(range(-90, -87), range(4200, 4250))] cls.test_cases = [ cls.SplitterTestCase('BBoxSplitter', BBoxSplitter([cls.area], CRS.WGS84, 5, reduce_bbox_sizes=True), bbox_len=19), cls.SplitterTestCase('OsmSplitter', OsmSplitter([cls.area], CRS.WGS84, 15, reduce_bbox_sizes=True), bbox_len=24), cls.SplitterTestCase('TileSplitter', TileSplitter([cls.area], CRS.WGS84, ('2017-10-01', '2018-03-01'), tile_split_shape=40, data_source=DataSource.SENTINEL2_L1C, reduce_bbox_sizes=True), bbox_len=13), cls.SplitterTestCase('CustomGridSplitter', CustomGridSplitter([cls.area], CRS.WGS84, bbox_grid, bbox_split_shape=(3, 4), reduce_bbox_sizes=False), bbox_len=41), cls.SplitterTestCase('UTMGridSplitter', UtmGridSplitter([cls.area], CRS.WGS84, bbox_size=(1200, 1200)), bbox_len=16), cls.SplitterTestCase('UTMZoneSplitter', UtmZoneSplitter([cls.area], CRS.WGS84, bbox_size=(1000, 1000)), bbox_len=19) ]
def get_satellite_images(resolution, crs_output, time_interval, img_size, output_bucket, **kwargs): """ Main function for generating satellite images (patches) using the EO-Learn API """ path_land_cover = 'gcs/data/land_cover.geojson' path_aoi = 'gcs/data/aoi.geojson' # Get aoi dimensions in meters aoi_shape, aoi_width, aoi_height = get_aoi_dimensions(path_aoi, crs_output) # Load labels geodata labels_data = gpd.read_file(path_land_cover) labels_data = labels_data.to_crs(crs={'init': crs_output}) # Compute number of columns and rows based on expected image dimensions output columns = int((aoi_width / img_size) / resolution) rows = int((aoi_height / img_size) / resolution) # Create splitter to obtain list of bounding boxes bbox_splitter = BBoxSplitter([aoi_shape], crs_output, (columns, rows)) # Create and execute workflow workflow, input_task, save_task = create_workflow(resolution, labels_data, output_bucket) total_patches_created = execute_workflow(workflow, input_task, save_task, bbox_splitter, time_interval) return total_patches_created
def generate_slo_shapefile(path): DATA_FOLDER = os.path.join('data') area = gpd.read_file(os.path.join(DATA_FOLDER, 'svn_buffered.geojson')) # area = gpd.read_file(os.path.join(DATA_FOLDER, 'austria.geojson')) # Convert CRS to UTM_33N country_crs = CRS.UTM_33N area = area.to_crs(crs={'init': CRS.ogc_string(country_crs)}) # Get the country's shape in polygon format country_shape = area.geometry.values.tolist()[-1] # Plot country area.plot() plt.axis('off') # Create the splitter to obtain a list of bboxes bbox_splitter = BBoxSplitter([country_shape], country_crs, (25 * 3, 17 * 3)) bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) path_out = path + '/shapefiles' if not os.path.isdir(path_out): os.makedirs(path_out) geometry = [Polygon(bbox.get_polygon()) for bbox in bbox_list] idxs_x = [info['index_x'] for info in info_list] idxs_y = [info['index_y'] for info in info_list] gdf = gpd.GeoDataFrame({ 'index_x': idxs_x, 'index_y': idxs_y }, crs={'init': CRS.ogc_string(country_crs)}, geometry=geometry) shapefile_name = path_out + '/slovenia.shp' gdf.to_file(shapefile_name) return gdf, bbox_list
def split_box(self, bbox_epsg4326, res): """ splits WGS84 box coordinates into as many boxes as needed for Sentinel Hub :param bbox_epsg4326: list or tuple of length 4 with xmin, ymin, xmax, ymax :param res: float spatial resolution :return: list of Bbox instances in UTM """ try: upper_left_utm = utm.from_latlon(bbox_epsg4326[3], bbox_epsg4326[0]) except TypeError: # is already of class Bbox return [bbox_epsg4326] lower_right_utm = utm.from_latlon(bbox_epsg4326[1], bbox_epsg4326[2], upper_left_utm[2]) # same zone number sizes = self.calc_bbox_size(upper_left_utm, lower_right_utm, res) # split into several boxes hemisphere = "N" if bbox_epsg4326[3] >= 0 else "S" bbox_utm = Polygon(box(upper_left_utm[0], lower_right_utm[1], lower_right_utm[0], upper_left_utm[1])) crs = CRS["UTM_" + str(upper_left_utm[2]) + hemisphere] # use UTM y = int(np.clip(np.round(sizes["x"] / 2400 + 0.5), 1, np.inf)) # + 0.5 in order to ensure rounding upwards x = int(np.clip(np.round(sizes["y"] / 2400 + 0.5), 1, np.inf)) bbox_splitter = BBoxSplitter([bbox_utm], crs, (y, x), reduce_bbox_sizes=True) return bbox_splitter.get_bbox_list()
def main(): args = parse_args() grid = args.grid.split(",") coords = [float(x.strip()) for x in args.coords.split(",")] # if args.geo_json_file: # INPUT_FILE = args.data_file # # geo_json = read_data(INPUT_FILE) area = Polygon([[coords[0], coords[1]], [coords[0], coords[3]], [coords[2], coords[3]], [coords[2], coords[1]]]) bbox_splitter = BBoxSplitter([area], CRS.WGS84, (int(grid[0]), int(grid[1])), reduce_bbox_sizes=True) img_dict = make_request(bbox_splitter, args.instance_id, args.util, args.width, args.height, args.maxcc, args.time, args.start_time, args.end_time) if args.util == 'info': print_info(img_dict, args.maxcc, args.start_time, args.end_time)
#INSTANCE_ID = instance INSTANCE_ID = os.environ.get('INSTANCE_ID') print(INSTANCE_ID) # global image request parameters time_interval = (time_start, time_end) img_width = width img_height = height maxcc = max_accuracy # input location for the example: example_data/eastern_france.geojson # get the AOI and split into bboxes crs = CRS.UTM_31N aoi = geopandas.read_file(os.path.join(input_path, filename)) aoi = aoi.to_crs(crs=crs.pyproj_crs()) aoi_shape = aoi.geometry.values[-1] bbox_splitter = BBoxSplitter([aoi_shape], crs, (19, 10)) # set raster_value conversions for our Geopedia task # see more about how to do this here: raster_value = { '0%': (0, [0, 0, 0, 0]), '10%': (1, [163, 235, 153, 255]), '30%': (2, [119, 195, 118, 255]), '50%': (3, [85, 160, 89, 255]), '70%': (4, [58, 130, 64, 255]), '90%': (5, [36, 103, 44, 255]) } import matplotlib as mpl
#%% Section 2 #Defining AOI and making Bboxes country = gpd.read_file('./DK.geojson') # Convert CRS to UTM_32N country_crs = CRS.UTM_32N country = country.to_crs(crs={'init': CRS.ogc_string(country_crs)}) # Get the country's shape in polygon format country_shape = country.geometry.values.tolist()[-1] #country.plot() #plt.axis('off'); # Create the splitter to obtain a list of bboxes bbox_splitter_large = BBoxSplitter([country_shape], country_crs, (45, 35)) bbox_splitter_small = BBoxSplitter([country_shape], country_crs, (45 * 3, 35 * 3)) bbox_splitter = bbox_splitter_large bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) #Prepare info of selected patch IDs geometry = [Polygon(bbox.get_polygon()) for bbox in bbox_list[patchIDs]] idxs_x = [info['index_x'] for info in info_list[patchIDs]] idxs_y = [info['index_y'] for info in info_list[patchIDs]] df = pd.DataFrame({'index_x': idxs_x, 'index_y': idxs_y}) gdf = gpd.GeoDataFrame(df, crs={'init': CRS.ogc_string(country_crs)},
import os def get_current_folder(str): return os.path.abspath(str) if __name__ == '__main__': img = OBSImage('obs://obs-tiff-test/retile_china/ng47_05_41.tif') print("bounds: {}".format(img.bounds)) print("shape {}".format(img.shape)) image_box = box(img.bounds[0], img.bounds[1], img.bounds[2], img.bounds[3]) # Split the image into 3 * 3 tiles bbox_splitter = BBoxSplitter([image_box], img.proj, (3, 3)) bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) # Obtain patchIDs patchIDs = [] for idx, [bbox, info] in enumerate(zip(bbox_list, info_list)): patchIDs.append(idx) # Check if final size is 3x3 if len(patchIDs) != 9: print( 'Warning! Use a different central patch ID, this one is on the border.' )
facecolor='red', edgecolor='red')) plt.tight_layout() plt.show() show_area(hawaii_area) """ We want to split the area into smaller bounding boxes which can then be used to obtain data with WMS/WCS requests. There are different ways to split the area implemented in sentinelhub. The first way is to split the bounding box into smaller parts of equal size. For inputs we must provide: list of geometries, their CRS, and an int/tuple specifying how many parts the bounding box will be split into. """ bbox_splitter = BBoxSplitter([hawaii_area], CRS.WGS84, (5, 4)) # will produce 5x4 grid of bboxes print('Area bounding box: {}\n'.format( bbox_splitter.get_area_bbox().__repr__())) bbox_list = bbox_splitter.get_bbox_list() info_list = bbox_splitter.get_info_list() print( 'Each bounding box also has some info about how it was created.\nExample:\n' 'bbox: {}\ninfo: {}\n'.format(bbox_list[0].__repr__(), info_list[0])) # get a list of geometries geometry_list = bbox_splitter.get_geometry_list() print(geometry_list[0])
def download_data(self, dataset, orbit_dates, total_width, total_height, bbox, temporal_extent, bands, dataFilter_params, max_chunk_size=1000): auth_token = SHProcessingAuthTokenSingleton.get() url = 'https://services.sentinel-hub.com/api/v1/process' headers = { 'Accept': 'image/tiff', 'Authorization': f'Bearer {auth_token}' } n_width = math.ceil(total_width/max_chunk_size) n_height = math.ceil(total_height/(max_chunk_size*max_chunk_size/(total_width//n_width + 1))) bbox_list = BBoxSplitter([bbox.geometry], CRS.WGS84, (n_width, n_height)).get_bbox_list() x_image_shapes = [total_width//n_width + 1 if w < total_width % n_width else total_width//n_width for w in range(n_width)] y_image_shapes = [total_height//n_height + 1 if h < total_height % n_height else total_height//n_height for h in range(n_height)] adapter_kwargs = dict(pool_maxsize=len(orbit_dates)*n_width*n_height) executor = ThreadPoolExecutor(max_workers=len(orbit_dates)*n_width*n_height) requests_session = FuturesSession(executor=executor, adapter_kwargs=adapter_kwargs) response_futures = {} orbit_times_middle,shapes = [],{} tmp_folder = f"/tmp-{self.job_id}" if os.path.exists(tmp_folder): os.rmdir(tmp_folder) os.mkdir(tmp_folder) for i, date in enumerate(orbit_dates): mean_time = date["from"] + (date["to"] - date["from"]) / 2 tile_from = mean_time - timedelta(minutes=25) tile_to = mean_time + timedelta(minutes=25) orbit_times_middle.append(mean_time) shapes[i] = [] for j, bbox_section in enumerate(bbox_list): request_params = { "input": { "bounds": { "bbox": [bbox_section.min_x, bbox_section.min_y, bbox_section.max_x, bbox_section.max_y], "properties": { "crs": "http://www.opengis.net/def/crs/EPSG/0/4326", } }, "data": [ { "type": dataset, "dataFilter": { "timeRange": { "from": tile_from.strftime("%Y-%m-%dT%H:%M:%S+00:00"), "to": tile_to.strftime("%Y-%m-%dT%H:%M:%S+00:00"), }, **dataFilter_params, } }, ], }, "output": { "width": x_image_shapes[j//n_height], "height": y_image_shapes[j%n_height], }, "evalscript": f"""//VERSION=3 function setup() {{ return {{ input: [{', '.join([f'"{b}"' for b in bands])}, "dataMask"], output: {{ bands: {len(bands) + 1}, sampleType: "FLOAT32", }} }} }} function evaluatePixel(sample) {{ return [{", ".join(['sample.' + b for b in bands])}, sample.dataMask] }} """ } shapes[i].append((y_image_shapes[j%n_height],x_image_shapes[j//n_height],len(bands)+1)) r = requests_session.post(url, headers=headers, json=request_params) response_futures[r] = {"date":i,"bbox":j} dates_filenames = {} for r_future, indices in response_futures.items(): r = r_future.result() if r.status_code != 200: raise Internal(r.content) self.logger.debug('Image received.') tmp_filename = f'{tmp_folder}/image-{indices["date"]}-{indices["bbox"]}.tiff' if dates_filenames.get(indices["date"]) is None: dates_filenames[indices["date"]] = [tmp_filename] else: dates_filenames[indices["date"]].append(tmp_filename) with open(tmp_filename, 'wb') as f: f.write(r.content) response_data = [] for i in range(len(orbit_dates)): images = [delayed(imageio.imread)(filename) for filename in dates_filenames[i]] images = [da.from_delayed(image, shape=shapes[i][j], dtype=np.float32) for j,image in enumerate(images)] image_gdal = construct_image(images, n_width, n_height) response_data.append(image_gdal) response_data = da.stack(response_data) self.logger.debug('Images created.') return response_data, orbit_times_middle
def download_region(base_dir, minx, miny, maxx, maxy, time_range, target_tiles=None): ''' Defines a workflow that will download and process all EOPatces in a defined region. This workflow will download all EOPatches in a given larger region. The pipline has the folowing steps - Download data - Calculate NDVI - Calculate NDWI - Calculate FDI - Add cloud mask - Add water mask - Combine all masks - Perform local noramalization - Save the results. Parameters: - base_dir: the directory to save the patches to - minx: Min Longitude of the region - miny: Min Latitude of the region - maxx: Max Longitude of the region - maxy: Max Latitude of the region - time_range: An array of [start_time,end_time]. Any satelite pass in that range will be procesed. - target_tiles: A list of tiles to manually include (not used right now) Returns: Nothing. ''' region = box(minx, miny, maxx, maxy) bbox_splitter = BBoxSplitter([region], CRS.WGS84, (20, 20)) bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) # Prepare info of selected EOPatches geometry = [Polygon(bbox.get_polygon()) for bbox in bbox_list] idxs_x = [info['index_x'] for info in info_list] idxs_y = [info['index_y'] for info in info_list] ids = range(len(info_list)) gdf = gp.GeoDataFrame({ 'index': ids, 'index_x': idxs_x, 'index_y': idxs_y }, crs='EPSG:4326', geometry=geometry) ax = gdf.to_crs('EPSG:3857').plot(facecolor='w', edgecolor='r', figsize=(20, 20), alpha=0.3) for idx, row in gdf.to_crs("EPSG:3857").iterrows(): geo = row.geometry xindex = row['index_x'] yindex = row['index_y'] index = row['index'] ax.text(geo.centroid.x, geo.centroid.y, f'{index}', ha='center', va='center') cx.add_basemap(ax=ax) plt.savefig(f'{base_dir}/region.png') total = len(target_tiles) if target_tiles else len(bbox_list) for index, patch_box in enumerate(bbox_list): if (target_tiles and index not in target_tiles): continue print("Getting patch ", index, ' of ', total) try: patch = get_and_process_patch(patch_box, time_range, base_dir, index) fig, ax = plot_masks_and_vals(patch) fig.savefig(f'{base_dir}/feature_{index}/bands.png') plt.close(fig) fig, ax = plot_ndvi_fid_plots(patch) fig.savefig(f'{base_dir}/feature_{index}/ndvi_fdi.png') plt.close(fig) except: print("Failed to process ", index)
def split_large_polygon_epsg4326(self, polygon_epsg4326, res): bounds = polygon_epsg4326.bounds x_size, y_size = abs(bounds[0] - bounds[2]) * 111000, abs(bounds[1] - bounds[3]) * 111000 # meters x_nboxes, y_nboxes = int((x_size / res) / 2400), int((y_size / res) / 2400) # 2400 max. n pixels bbox_splitter = BBoxSplitter([polygon_epsg4326], CRS.WGS84, (x_nboxes, y_nboxes), reduce_bbox_sizes=True) return bbox_splitter.get_bbox_list()
# Convert CRS to WGS84 country_crs = CRS.WGS84 country = country.to_crs(crs={'init': CRS.ogc_string(country_crs)}) # Get the country's shape in polygon format country_shape = country.geometry.values.tolist()[-1] # Print size print('Dimension of the area is {0:.0f} x {1:.0f} m2'.format( country_shape.bounds[2] - country_shape.bounds[0], country_shape.bounds[3] - country_shape.bounds[1])) use_smaller_patches = False # Create the splitter to obtain a list of bboxes bbox_splitter_large = BBoxSplitter([country_shape], country_crs, (10, 10)) bbox_splitter_small = BBoxSplitter([country_shape], country_crs, (15 * 3, 15 * 3)) bbox_splitter = bbox_splitter_small if use_smaller_patches else bbox_splitter_large bbox_list = np.array(bbox_splitter.get_bbox_list()) info_list = np.array(bbox_splitter.get_info_list()) # For the future examples, we will be using a specific set of patches, # but you are free to change the patch ID numbers in the scope of this example # Select a central patch # ID = 1549 if use_smaller_patches else 190 # Obtain surrounding patches patchIDs = []