def write_quicklook(raster, filename, downfactor=4): """ write a JPG preview :param raster: raster (rasterio image) :param filename: path to the output preview :param downfactor: downsampling factor """ profile = raster.profile # update size in profile newwidth = int(raster.width / downfactor) newheight = int(raster.height / downfactor) try: aff = raster.affine newaffine = rasterio.Affine(aff.a / downfactor, aff.b, aff.c, aff.d, aff.e / downfactor, aff.f) profile.update(dtype=rasterio.uint8, count=3, compress='lzw', driver='JPEG', width=newwidth, height=newheight, transform=newaffine, affine=newaffine) # depend on rasterio version except AttributeError: aff = raster.transform newaffine = rasterio.Affine(aff.a / downfactor, aff.b, aff.c, aff.d, aff.e / downfactor, aff.f) profile.update(dtype=rasterio.uint8, count=3, compress='lzw', driver='JPEG', width=newwidth, height=newheight, transform=newaffine) # write raster with rasterio.open(filename, 'w', **profile) as dst: for n in range(3): if raster.count == 1: band = raster.read(1, out_shape=(int(raster.height / downfactor), int(raster.width / downfactor))) else: band = raster.read(n + 1, out_shape=(int(raster.height / downfactor), int(raster.width / downfactor))) band = normalize(band) dst.write(band, n + 1)
def test_data(): test_data_pan = np.array([(np.random.rand(60, 60) * 255).astype(np.uint8)]) test_data_pan = test_data_pan[0] test_data_rgb = np.array([(np.random.rand(30, 30) * 255).astype(np.uint8) for i in range(3)]) test_data_src_aff = rasterio.Affine(2.0, 0.0, 0.0, 0.0, -2.0, 0.0) test_data_src_crs = {'init': 'EPSG:3857'} test_data_dst_aff = rasterio.Affine(1.0, 0.0, 0.0, 0.0, -1.0, 0.0) test_data_dst_crs = {'init': 'EPSG:3857'} return test_data_pan, test_data_rgb, test_data_src_aff,\ test_data_src_crs, test_data_dst_aff, test_data_dst_crs
def read_hdf5(self, file_data): """Read centroids attributes from hdf5. Parameters ---------- file_data : str or h5 If string, path to read data. If h5 object, the datasets will be read from there. """ if isinstance(file_data, (str, Path)): LOGGER.info('Reading %s', file_data) data = h5py.File(file_data, 'r') else: data = file_data self.clear() crs = DEF_CRS if data.get('crs'): crs = u_coord.to_crs_user_input(data.get('crs')[0]) if data.get('lat') and data.get('lat').size: self.set_lat_lon(np.array(data.get('lat')), np.array(data.get('lon')), crs) elif data.get('latitude') and data.get('latitude').size: self.set_lat_lon(np.array(data.get('latitude')), np.array(data.get('longitude')), crs) else: centr_meta = data.get('meta') self.meta['crs'] = crs for key, value in centr_meta.items(): if key != 'transform': self.meta[key] = value[0] else: self.meta[key] = rasterio.Affine(*value) for centr_name in data.keys(): if centr_name not in ('crs', 'lat', 'lon', 'meta'): setattr(self, centr_name, np.array(data.get(centr_name))) if isinstance(file_data, str): data.close()
def set_raster_from_pix_bounds(self, xf_lat, xo_lon, d_lat, d_lon, n_lat, n_lon, crs=DEF_CRS): """Set raster metadata (meta attribute) from pixel border data Parameters ---------- xf_lat : float upper latitude (top) xo_lon : float left longitude d_lat : float latitude step (negative) d_lon : float longitude step (positive) n_lat : int number of latitude points n_lon : int number of longitude points crs : dict() or rasterio.crs.CRS, optional CRS. Default: DEF_CRS """ self.__init__() self.meta = { 'dtype': 'float32', 'width': n_lon, 'height': n_lat, 'crs': crs, 'transform': rasterio.Affine(d_lon, 0.0, xo_lon, 0.0, d_lat, xf_lat), }
def calculate_coverage(overlaps, dimensions, bounds): # get dimensions of coverage raster mminx, mminy, mmaxx, mmaxy = bounds y_count, x_count = dimensions # determine pixel width and height for transform width = (mmaxx - mminx) / x_count height = (mminy - mmaxy) / y_count # should be negative # Affine(a, b, c, d, e, f) where: # a = width of a pixel # b = row rotation (typically zero) # c = x-coordinate of the upper-left corner of the upper-left pixel # d = column rotation (typically zero) # e = height of a pixel (typically negative) # f = y-coordinate of the of the upper-left corner of the upper-left pixel # ref: http://www.perrygeo.com/python-affine-transforms.html transform = rasterio.Affine(width, 0, mminx, 0, height, mmaxy) coverage = np.zeros(dimensions, dtype=np.uint16) for overlap in overlaps: if not overlap.is_empty: # rasterize overlap vector, transforming to coverage raster # pixels inside overlap have a value of 1, others have a value of 0 overlap_raster = rfeatures.rasterize([sgeom.mapping(overlap)], fill=0, default_value=1, out_shape=dimensions, transform=transform) # add overlap raster to coverage raster coverage += overlap_raster return coverage
def __init__(self, config, root_dir, threshold=100): self.path = root_dir self.config = config self.overlap = config['overlap'] self.window = config['window'] self.transform = get_transform(config['transform'], config['resize']) self.identity = rasterio.Affine(1, 0, 0, 0, 1, 0) self.phase = config['phase'] self.cache_dir = config['cache_dir'] if self.phase == 'train' or self.phase == 'val': self.csv = pd.read_csv(self.path + '/train.csv', index_col=[0]) self.threshold = threshold else: self.csv = None self.x, self.y,self.masks,self.slices, self.files = [], [], [], [], [] self.shape = {} if self.cache_dir: if self.check_cache(): self.load_cache() else: os.system(f'mkdir -p {self.cache_dir}') self.build_cache() else: self.build_slices() self.len = len(self.slices) self.as_tensor = T.Compose([ T.ToTensor(), T.Normalize([0.625, 0.448, 0.688], [0.131, 0.177, 0.101]), ])
def crop(src_img, src_affine, n): """Crop a given image from each direction according to a given number of pixels. Also calculate a new Affine transformation. Parameters ---------- src_img : numpy 2d array Source image as a 2d numpy array. src_affine : Affine Source Affine object. n : int Number of pixels cropped from each direction. Returns ------- dst_img : numpy 2d array Output cropped image. dst_affine : Affine Updated affine. """ nrows, ncols = src_img.shape dst_img = src_img[n:nrows - n, n:ncols - n] a, b, c, d, e, f, _, _, _ = src_affine c += a * n f -= a * n dst_affine = rasterio.Affine(a, b, c, d, e, f) return dst_img, dst_affine
def export_prediction_to_tif(self, out_file_path, prediction): """ :param out_file_path: :param prediction: a np-array where second dim indicate n-channels :return: """ #Check if map-info is available if self.map_info is None: class MissingMapInfoException(Exception): pass raise MissingMapInfoException() #Compute geo-meta data geo = self.map_info['transform'] transf = rasterio.Affine(geo[1], geo[2], geo[0], geo[4], geo[5], geo[3]) crs = {'init': self.map_info['cs_code']} #Write to file with rasterio.open(out_file_path, "w", driver="GTiff", compress="lzw", bigtiff="YES", height=prediction.shape[0], width=prediction.shape[1], count=prediction.shape[2], dtype=prediction.dtype, crs=crs, transform=transf) as out_file: for band_no in range(0, prediction.shape[2]): out_file.write(prediction[:,:,band_no], band_no + 1) print('Exported predictions to', out_file_path)
def write_geotiff_prediction(image, jsonFile, aoi): with open(jsonFile, ) as file: mixer = json.load(file) transform = mixer['projection']['affine']['doubleMatrix'] crs = mixer['projection']['crs'] ppr = mixer['patchesPerRow'] tp = mixer['totalPatches'] rows = int(tp / ppr) if image.ndim < 3: image = np.expand_dims(image, axis=-1) affine = rio.Affine(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]) with rio.open(f'{aoi}.tif', 'w', driver='GTiff', width=image.shape[1], height=image.shape[0], count=image.shape[2], dtype=image.dtype, crs=crs, transform=affine) as dst: dst.write(np.transpose(image, (2, 0, 1)))
def mask_to_polygons_layer(mask, eopatch, tolerance): all_polygons = [] bbox = eopatch.bbox size_x = eopatch.meta_info['size_x'] size_y = eopatch.meta_info['size_y'] vx = bbox.min_x vy = bbox.max_y cx = (bbox.max_x - bbox.min_x) / size_x cy = (bbox.max_y - bbox.min_y) / size_y for shape, value in features.shapes(mask.astype(np.int16), mask=(mask == 1), transform=rasterio.Affine( cx, 0.0, vx, 0.0, -cy, vy)): return shapely.geometry.shape(shape).simplify(tolerance, False) all_polygons.append(shapely.geometry.shape(shape)) all_polygons = shapely.geometry.MultiPolygon(all_polygons) if not all_polygons.is_valid: all_polygons = all_polygons.buffer(0) if all_polygons.type == 'Polygon': all_polygons = shapely.geometry.MultiPolygon([all_polygons]) return all_polygons
def data_array_to_rasterio(xr_data, output_file=None, tag=None, fmt='GTiff', metadata=None): """Write xarray DataArray to file using rasterio. """ extensions = { 'GTiff': '.tif', } output_file = output_file or os.path.join(whitebox_temp_dir, str(tag) + extensions[fmt]) metadata = metadata or dict() shape = xr_data.shape if len(shape) == 2: shape = (1, *shape) count, height, width = shape bands = 1 if count == 1 else np.arange(count) + 1 metadata.update( driver=fmt, height=height, width=width, dtype=str(xr_data.dtype), count=count, ) if 'transform' in xr_data.attrs: metadata['transform'] = rasterio.Affine(*xr_data.attrs['transform'][:6]) if 'crs' in xr_data.attrs: metadata['crs'] = rasterio.crs.CRS.from_string(xr_data.attrs['crs']) with rasterio.open(output_file, 'w', **metadata) as output: output.write(xr_data.values.astype(metadata['dtype']), bands) return output_file
def pad_extent(src, src_transform, dst_transform, src_crs, dst_crs, **kwargs): """ Pad the extent of `src` by an equivalent of one cell of the target raster. This ensures that the array is large enough to not be treated as nodata in all cells of the destination raster. If src.ndim > 2, the function expects the last two dimensions to be y,x. Additional keyword arguments are used in `np.pad()`. """ if src.size == 0: return src, src_transform left, top, right, bottom = *(src_transform * (0, 0)), *(src_transform * (1, 1)) covered = transform_bounds(src_crs, dst_crs, left, bottom, right, top) covered_res = min(abs(covered[2] - covered[0]), abs(covered[3] - covered[1])) pad = int(dst_transform[0] // covered_res * 1.1) kwargs.setdefault('mode', 'constant') if src.ndim == 2: return rio.pad(src, src_transform, pad, **kwargs) npad = ((0, 0), ) * (src.ndim - 2) + ((pad, pad), (pad, pad)) padded = np.pad(src, npad, **kwargs) transform = list(src_transform) transform[2] -= pad * transform[0] transform[5] -= pad * transform[4] return padded, rio.Affine(*transform[:6])
def resample_by_raster(self): ''' ### Resampling raster by another raster Input: two rasters directories (one to be resampled and another for base) ''' with rasterio.open(self.__raster_base) as base: profile = base.meta.copy() height = base.shape[0] width = base.shape[1] # Resolution output image transform xres = int((base.bounds.right - base.bounds.left) /width) yres = int((base.bounds.top - base.bounds.bottom ) / height ) # Affine transform = rasterio.Affine(xres, base.transform.b, base.transform.c, base.transform.d, -yres, base.transform.f) # Getting the original raster profile and updating with new information profile.update(transform=transform, driver='GTiff', height=height, width=width, crs=base.crs, count=base.count, nodata= np.nan, dtype='float32' ) with rasterio.open(self.__raster, 'r+') as tif: # Reading raster to resample it data = tif.read(out_shape=(int(tif.count), int(height), int(width)), resampling=rasterio.enums.Resampling.average) # Writing a new raster output = self.__raster[:-4] + f'_R{xres}_.tif' with rasterio.open(output, 'w', **profile) as dst: dst.write(data) return data
def reproject_band(self, band, src_transform, bbox): # shift dst_transform # bbox --> (left, bottom, right, top) assert self.out_res in ["10", "30", "20", "60" ], "output resolution must be 10, 20, 30 or 60" transform_out_res = self.transform_dict[self.out_res][0] dst_transform = rasterio.Affine( transform_out_res.a, transform_out_res.b, bbox[0] if transform_out_res.a > 0 else bbox[2], transform_out_res.d, transform_out_res.e, bbox[3] if transform_out_res.e < 0 else bbox[1]) window_read = windows.from_bounds(*bbox, dst_transform) shape_new = tuple([int(round(s)) for s in windows.shape(window_read)]) data_new_proj = np.ndarray(shape=shape_new, dtype=band.dtype) reproject(band, data_new_proj, src_transform=src_transform, src_crs=self.crs, dst_transform=dst_transform, dst_crs=self.crs, resampling=Resampling.cubic_spline) return data_new_proj
def resample_profile(m, scale): """ Creates a rasterio profile with the dimensions resampled by a factor Parameters ---------- m : str, rasterio profile location of the map or rasterio profile scale : float factor with which height and width will be multiplied Returns ------- rasterio profile """ if isinstance(m, str): with rio.open(m) as ref_map: profile = ref_map.profile elif isinstance(m, rio.profiles.Profile): profile = copy.deepcopy(m) else: raise TypeError("M should be a filepath or rasterio profile") transform = profile['transform'] new_transform = rio.Affine(transform[0] / scale, transform[1], transform[2], transform[3], transform[4] / scale, transform[5]) profile.update({ 'transform': new_transform, 'width': int(profile['width'] * scale), 'height': int(profile['height'] * scale) }) return profile
def mask_to_polygons(mask, xmax, ymin, threshold=0.5, tolerance=1): all_polygons = [] mask[mask >= threshold] = 1 mask[mask < threshold] = 0 for shape, _ in rasterio.features.shapes(mask.astype(np.int16), mask=(mask == 1), transform=rasterio.Affine( 1.0, 0, 0, 0, 1.0, 0)): all_polygons.append(shapely.geometry.shape(shape)) all_polygons = shapely.geometry.MultiPolygon(all_polygons) # Transform from pixel coordinates to grid coordinates height, width = mask.shape all_polygons = shapely.affinity.scale(all_polygons, xfact=xmax / (width), yfact=ymin / (height), origin=(0, 0, 0)) # simplify the geometry of the masks # FIXME: magic constant. 2.7*1e-6 is size of one pixel in grid coordinates all_polygons = all_polygons.simplify(tolerance * 2.7 * 1e-6, preserve_topology=True) if not all_polygons.is_valid: all_polygons = all_polygons.buffer(0) # Sometimes buffer() converts a simple Multipolygon to just a Polygon, # need to keep it a Multi throughout if all_polygons.type == 'Polygon': all_polygons = shapely.geometry.MultiPolygon([all_polygons]) return all_polygons
def __init__(self, image_path, sz=256, scale=1, saturation_threshold=40): self.scale = scale self.s_th = saturation_threshold # saturation blancking threshold self.p_th = 1000 * ( sz // 256)**2 # threshold for the minimum number of pixels scale_transform = rasterio.Affine(1, 0, 0, 0, 1, 0) self.data = rasterio.open(os.path.join(image_path), transform=scale_transform, num_threads='all_cpus') # some images have issues with their format # and must be saved correctly before reading with rasterio if self.data.count != 3: subdatasets = self.data.subdatasets self.layers = [] if len(subdatasets) > 0: for i, subdataset in enumerate(subdatasets, 0): self.layers.append(rasterio.open(subdataset)) self.shape = self.data.shape self.width = self.shape[1] self.height = self.shape[0] self.sz = sz print(f"image loader for {image_path} created") print(f"original image size = {self.width} x {self.height}")
def mask_to_polygons(mask, epsilon=1, min_area=1., engine='opencv', buffer_amount=0.001): # print('Mask toi polygon') # __author__ = Konstantin Lopuhin # https://www.kaggle.com/lopuhin/dstl-satellite-imagery-feature-detection/full-pipeline-demo-poly-pixels-ml-poly # first, find contours with cv2: it's much faster than shapely if engine == 'opencv': # TODO check this shit. Тут добавил >=0.5 чтобы обойти кривые маски в файле (без бинаризации) image, contours, hierarchy = cv2.findContours( ((mask >= 0.5) * 255).astype(np.uint8), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_KCOS) # create approximate contours to have reasonable submission size approx_contours = [ cv2.approxPolyDP(cnt, epsilon, True) for cnt in contours ] if not contours: return MultiPolygon() # now messy stuff to associate parent and child contours cnt_children = defaultdict(list) child_contours = set() assert hierarchy.shape[0] == 1 # http://docs.opencv.org/3.1.0/d9/d8b/tutorial_py_contours_hierarchy.html for idx, (_, _, _, parent_idx) in enumerate(hierarchy[0]): if parent_idx != -1: child_contours.add(idx) cnt_children[parent_idx].append(approx_contours[idx]) # create actual polygons filtering by area (removes artifacts) all_polygons = [] for idx, cnt in enumerate(approx_contours): if idx not in child_contours and cv2.contourArea(cnt) >= min_area: assert cnt.shape[1] == 1 poly = Polygon(shell=cnt[:, 0, :], holes=[ c[:, 0, :] for c in cnt_children.get(idx, []) if cv2.contourArea(c) >= min_area ]) all_polygons.append(poly) # approximating polygons might have created invalid ones, fix them else: all_polygons = [] for shape, value in features.shapes(mask.astype(np.int16), mask=(mask == 1), transform=rasterio.Affine( 1.0, 0, 0, 0, 1.0, 0)): all_polygons.append(shapely.geometry.shape(shape)) all_polygons = MultiPolygon(all_polygons) if True: # not all_polygons.is_valid: all_polygons = all_polygons.buffer(buffer_amount) # Sometimes buffer() converts a simple Multipolygon to just a Polygon, # need to keep it a Multi throughout if all_polygons.type == 'Polygon': all_polygons = MultiPolygon([all_polygons]) return all_polygons
def get_transform_and_shape(bounds, res, out_logging): if out_logging: _logger.info("Stage 2/5: Get transform and shape") left, bottom = [(b // res) * res for b in bounds[:2]] right, top = [(b // res + 1) * res for b in bounds[2:]] shape = int((top - bottom) // res), int((right - left) / res) transform = rio.Affine(res, 0, left, 0, -res, top) return transform, shape
def _as_transform(x, y): lx, rx = x[[0, -1]] ly, uy = y[[0, -1]] dx = float(rx - lx) / float(len(x) - 1) dy = float(uy - ly) / float(len(y) - 1) return rio.Affine(dx, 0, lx - dx / 2, 0, dy, ly - dy / 2)
def geotransform_to_affine(geot): """ Convert GDAL geo transform to affine, which is used more commonly for specifying the configuration of raster datasets in newer frameworks like rasterio """ c, a, b, f, d, e = list(geot) return rio.Affine(a, b, c, d, e, f)
def append(self, centr): """Append raster or points. Parameters ---------- centr : Centroids If it's a raster, it needs to have the same `meta` attribute. If it's of non-raster form, it's geometry needs to have the same CRS. """ if self.meta and centr.meta: LOGGER.debug('Appending raster') if centr.meta['crs'] != self.meta['crs']: LOGGER.error('Different CRS not accepted.') raise ValueError if self.meta['transform'][0] != centr.meta['transform'][0] \ or self.meta['transform'][4] != centr.meta['transform'][4]: LOGGER.error('Different raster resolutions.') raise ValueError left = min(self.total_bounds[0], centr.total_bounds[0]) bottom = min(self.total_bounds[1], centr.total_bounds[1]) right = max(self.total_bounds[2], centr.total_bounds[2]) top = max(self.total_bounds[3], centr.total_bounds[3]) crs = self.meta['crs'] width = (right - left) / self.meta['transform'][0] height = (bottom - top) / self.meta['transform'][4] self.meta = { 'dtype': 'float32', 'width': width, 'height': height, 'crs': crs, 'transform': rasterio.Affine(self.meta['transform'][0], 0.0, left, 0.0, self.meta['transform'][4], top), } self.lat, self.lon = np.array([]), np.array([]) else: LOGGER.debug('Appending points') if not u_coord.equal_crs(centr.geometry.crs, self.geometry.crs): LOGGER.error('Different CRS not accepted.') raise ValueError self.lat = np.append(self.lat, centr.lat) self.lon = np.append(self.lon, centr.lon) self.meta = dict() # append all 1-dim variables for (var_name, var_val), centr_val in zip(self.__dict__.items(), centr.__dict__.values()): if isinstance(var_val, np.ndarray) and var_val.ndim == 1 and \ var_name not in ('lat', 'lon'): setattr( self, var_name, np.append(var_val, centr_val).astype(var_val.dtype, copy=False))
def padded_transform_and_shape(bounds, res): """ Get the (transform, shape) tuple of a raster with resolution `res` and bounds `bounds`. """ left, bottom = [(b // res) * res for b in bounds[:2]] right, top = [(b // res + 1) * res for b in bounds[2:]] shape = int((top - bottom) / res), int((right - left) / res) return rio.Affine(res, 0, left, 0, -res, top), shape
def test__vrt_transform(LAYER): tile = RasterSrcTile("10N_010E", LAYER.grid, LAYER) transform, width, height = tile._vrt_transform(9.1, 9.1, 9.2, 9.2) assert transform.almost_equals( rasterio.Affine(0.00025, 0, 9.1, 0, -0.00025, 9.2)) assert isclose(width, 400) assert isclose(height, 400)
def to_geotiff(ncf, out_folder): # startdate = dt.datetime.strptime(ncf.datetime, ncf_time_format) product = 'precip_probability' if 'precip_probability' in ncf.variables else 'precip_intensity' import os if product == 'precip_probability': out_folder = os.path.join(out_folder, 'nowcast') elif product == 'precip_intensity': out_folder = os.path.join(out_folder, 'prec_intensity') if not os.path.exists(out_folder): os.mkdir(out_folder) n, h, w = ncf.variables[product].shape Xmin = ncf.variables["xc"][0] Xmax = ncf.variables["xc"][-1] Ymin = ncf.variables["yc"][0] Ymax = ncf.variables["yc"][-1] affine = rasterio.Affine((Xmax - Xmin) / w, 0, Xmin, 0, (Ymin - Ymax) / h, Ymax) data = get_data(ncf, data_var=product) for key in data: data[key][:] = data[key][::-1, :] datetime = dt.datetime.strptime(key, ncf_time_format) if product == 'precip_intensity': pr = 'prec_intensity' else: pr = 'nowcast' filename = out_folder + "/{}_".format(pr) + dt.datetime.strftime( datetime, "%Y%m%d_%H%M") + ".tiff" import os filename = os.path.realpath(filename) if not os.path.exists(os.path.dirname(filename)): os.mkdir(os.path.dirname(filename)) print(filename) img_data = convert_probability_to_byte( data[key] ) if product == 'precip_probability' else convert_precipitation_to_byte( values=data[key].data) dtype = np.uint8 if product == 'precip_probability' else np.float32 with rasterio.open(filename, 'w', driver='GTiff', height=h, width=w, count=1, dtype=dtype, crs=ncf.projection, nodata=255, transform=affine) as ncfile: ncfile.write_band(1, img_data) update(datetime, ncf.projection, (-w * 2 * 1000, -h * 2 * 1000, w * 2 * 1000, h * 2 * 1000), pr)
def transform(self): """Get the affine transform of the cutout. """ return rio.Affine( self.dx, 0, self.coords["x"].values[0] - self.dx / 2, 0, self.dy, self.coords["y"].values[0] - self.dy / 2, )
def transform_r(self): """Get the affine transform of the cutout with reverse y-order.""" return rio.Affine( self.dx, 0, self.coords["x"].values[0] - self.dx / 2, 0, -self.dy, self.coords["y"].values[-1] + self.dy / 2, )
def regrid_PS2EASE(data): src_rcrs = rcrs.from_string(NSIDCNorthPolarStereo_crs.proj4_init) #src_rcrs = rcrs.from_string('+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +a=6378273 +b=6356889.449 +units=m +no_defs') dst_rcrs = rcrs.from_string(EASE_crs.proj4_init) #dst_rcrs = rcrs.from_string('+proj=laea +lat_0=90 +lon_0=0 +x_0=0 +y_0=0 +a=6371228 +b=6371228 +units=m +no_defs') # Get shape of source grid source_height, source_width = data.shape # Define source affine transformation src_transform = rasterio.Affine( NSIDCNorthPolarStereo_25km['pixel_width'], # pixel width 0., # row rotation NSIDCNorthPolarStereo_25km['bounds'][0], # Left coordinate 0., # Column rotation -1 * NSIDCNorthPolarStereo_25km['pixel_height'], # pixel height NSIDCNorthPolarStereo_25km['bounds'][3]) # Define destination affine transformation dst_transform = rasterio.Affine( dst_proj['pixel_width'], # pixel width 0., # row rotation dst_proj['bounds'][0], # Left coordinate 0., # Column rotation -1 * dst_proj['pixel_height'], # pixel height dst_proj['bounds'][3]) #Initialize the destination arrays data_ease = np.empty(dst_size, dtype=float) #do reprojection warp.reproject(source=data.astype(float), src_crs=src_rcrs, src_nodata=np.nan, src_transform=src_transform, destination=data_ease, dst_transform=dst_transform, dst_crs=dst_rcrs, dst_nodata=np.nan, SOURCE_EXTRA=0, resampling=warp.Resampling.nearest) return (data_ease)
def mask_to_polygons_via_shapely(mask): all_polygons = [] for shape, value in rasterio.features.shapes(mask, mask, connectivity=4, transform=rasterio.Affine( 1.0, 0, 0, 0, 1.0, 0)): all_polygons.append(shapely.geometry.shape(shape)) mp = shapely.geometry.MultiPolygon(all_polygons) mp = make_valid(mp) return mp
def get_image_and_mask(self, tile_geometry, debug_base_file_name=None): km2_to_m2 = 1000.0 * 1000.0 surface_area_m2 = tile_geometry.area * km2_to_m2 min_tile_e = int(tile_geometry.bounds[0]) min_tile_n = int(tile_geometry.bounds[1]) max_tile_e = int(tile_geometry.bounds[2]) max_tile_n = int(tile_geometry.bounds[3]) image_bgr = self.download_image(max_tile_e, max_tile_n, min_tile_e, min_tile_n) # [a, b, d, e, xoff, yoff] # x' = a * x + b * y + xoff # y' = d * x + e * y + yoff m = [ self.__final_tile_size, 0, 0, self.__final_tile_size, -min_tile_e * self.__final_tile_size, -min_tile_n * self.__final_tile_size ] affine_geometry = affine_transform(tile_geometry, m) min_x = floor(affine_geometry.bounds[0]) min_y = floor(affine_geometry.bounds[1]) max_x = floor(affine_geometry.bounds[2]) max_y = floor(affine_geometry.bounds[3]) max_y_vertically_flipped = image_bgr.shape[0] - 1 - min_y min_y_vertically_flipped = image_bgr.shape[0] - 1 - max_y affine = rasterio.Affine(1, 0, min_x, 0, -1, max_y) pixels_within_geometry = geometry_mask( [affine_geometry], (max_y_vertically_flipped - min_y_vertically_flipped + 1, max_x - min_x + 1), affine, invert=True) image_bgri_cropped = image_bgr[ min_y_vertically_flipped:max_y_vertically_flipped + 1, min_x:max_x + 1, :] tile_file_name = None if debug_base_file_name is not None: centre_point = tile_geometry.centroid tile_code = tile_eastings_and_northings_to_tile_code( centre_point.x, centre_point.y) tile_file_name = debug_base_file_name + '-' + tile_code return image_bgri_cropped, pixels_within_geometry, surface_area_m2, tile_file_name