def _make_src_affine(src_data_array): src_bounds = _get_bounds(src_data_array) src_left, src_bottom, src_right, src_top = src_bounds src_resolution_x, src_resolution_y = _get_resolution(src_data_array, as_tuple=True) return Affine.translation(src_left, src_top) * Affine.scale( src_resolution_x, src_resolution_y)
def get_transform(xul, yul, dx, dy=None, rotation=0.): """Returns an affine.Affine instance that can be used to locate raster grids in space. See https://www.perrygeo.com/python-affine-transforms.html https://rasterio.readthedocs.io/en/stable/topics/migrating-to-v1.html Parameters ---------- xul : float x-coorindate of upper left corner of raster grid yul : float y-coorindate of upper left corner of raster grid dx : float cell spacing in the x-direction dy : float cell spacing in the y-direction rotation : rotation of the raster grid in degrees, clockwise Returns ------- affine.Affine instance """ if not rasterio: raise ModuleNotFoundError( 'This function requires rasterio. Please conda install rasterio.') if dy is None: dy = -dx return Affine(dx, 0., xul, 0., dy, yul) * \ Affine.rotation(rotation)
def areagrid(outraster, c = 0.083333001, r = 6371007.2, minx = -180, miny = -90, w = 360, h = 180): """ Generates a global grid in geograpic coordinates with the area of each gridcell as the value of the cell Parameters: outraster = path to output raster file c = cellsize in decimal degrees r = radius of earth in desired units (e.g. 6371007.2m for sq. meters) minx, miny = the south west coordinate of the raster in degrees w, h = the width and height of the raster in degrees Returns: None """ c = float(c) r = float(r) # make a vector of ones [1,1,1, ... 1] of length equal to the number of cells from west to east. X = np.ones(round(w/c)) # make a vector counting from 0 to the number of cells from south to north. e.g. [0,1,2,...,179] for 1 deg cells. Y = np.arange(round(h/c)) # multiply all the numbers in the Y vector by the cell size, # so it extends from 0 to <180 (if the cell size is different than 1 deg) # then add the southernmost coordinate (-90deg). This makes a vector of -90 to +90 degrees North degN = Y*c + miny # convert degrees vector to radians radN = degN*np.pi/180.0 # convert the cell size to radians radc = c * np.pi/180.0 # calculate the area of the cell # there's some implicit geometry that's been done here already' # but basically it averages the width of the top of a cell and the bottom of a cell # and mutiplies it by the height of the cell (which is constant no matter how far or south north you are) # then by the square of the radius # since the angles are in radians it works out area correctly # you end up with a vector of cell area from south to north A = (np.sin(radN+radc/2)-np.sin(radN-radc/2)) * radc * r**2 # the outer product of any vector and a vector of ones just duplicates the first vector into columns in a matrix # basically we just copy the latitude vector across from east to west M = np.outer(A,X) cols = round(w/c) rows = round(h/c) # save the matrix as a raster with rasterio.open(outraster,'w', 'GTiff', width=cols, height=rows, dtype=M.dtype, crs={'init': 'EPSG:4326'}, transform=Affine.translation(-cols*c/2, rows*c/2) * Affine.scale(c, -c), count=1) as dst: dst.write_band(1,M)
def data_arrays_resampling_demo(): """init demo data arrays (2d) and meta data for resampling""" data_arrays = list() # demo pop: data_arrays.append(np.array([[0, 1, 2], [3, 4, 5]], dtype='float32')) data_arrays.append(np.array([[0, 1, 2], [3, 4, 5]], dtype='float32')) # array([[0, 1, 2], # [3, 4, 5]]) # demo nightlight: data_arrays.append( np.array([[2, 10, 0, 0, 0, 0], [10, 2, 10, 0, 0, 0], [0, 0, 0, 0, 1, 1], [1, 0, 0, 0, 1, 1]], dtype='float32')) # array([[ 2., 10., 0., 0., 0., 0.], # [10., 2., 10., 0., 0., 0.], # [ 0., 0., 0., 0., 1., 1.], # [ 1., 0., 0., 0., 1., 1.]], dtype=float32)] meta_list = [ { 'driver': 'GTiff', 'dtype': 'float32', 'nodata': -3.4028230607370965e+38, 'width': 3, 'height': 2, 'count': 1, 'crs': CRS.from_epsg(4326), #'crs': CRS.from_epsg(4326), 'transform': Affine(1, 0.0, -10, 0.0, -1, 40), }, { 'driver': 'GTiff', 'dtype': 'float32', 'nodata': -3.4028230607370965e+38, 'width': 3, 'height': 2, 'count': 1, 'crs': CRS.from_epsg(4326), #'crs': CRS.from_epsg(4326), 'transform': Affine(1, 0.0, -10, 0.0, -1, 41), # shifted by 1 degree latitude to the north }, { 'driver': 'GTiff', 'dtype': 'float32', 'nodata': None, 'width': 6, 'height': 4, 'count': 1, 'crs': CRS.from_epsg(4326), # 'crs': CRS.from_epsg(32662), 'transform': Affine(.5, 0.0, -10, 0.0, -.5, 40), # higher resolution } ] return data_arrays, meta_list
def defineSquare(self, x, y, alpha, length): transform0 = rasterio.open(self.imgdir + self.imgWithCoords(x, y), 'r').transform x_ras, y_ras = np.round((~transform0) * (x, y)) transform1 = transform0 * A.translation(x_ras, y_ras) * A.rotation(alpha) corners = [ transform1 * (0, 0), transform1 * (length, 0), transform1 * (length, length), transform1 * (0, length) ] return corners
def _get_affine_transform(self, bounding_box): lng1, lng2 = bounding_box.west, bounding_box.east lat1, lat2 = bounding_box.south, bounding_box.north x_scale = self.google_static_maps.image_w / (lng2 - lng1) y_scale = -self.google_static_maps.image_h / (lat2 - lat1) affine_translate = Affine.translation(-lng1, -lat2) affine_scale = Affine.scale(x_scale, y_scale) # affine_mirror = Affine(1, 0, 0, 0, -1, image_h) affine_transform = affine_scale * affine_translate return affine_transform
def transform(self): """Rasterio-style affine transform object. https://www.perrygeo.com/python-affine-transforms.html """ if self.uniform: for param in ['dx', 'rotation', 'xul', 'dy', 'yul']: if self.__dict__[param] is None: print('This method requires a uniform grid and ' 'specification of xul, yul, dx, dy, and rotation.') return return Affine(self.dx, 0., self.xul, 0., -self.dy, self.yul) * Affine.rotation(self.rotation)
def from_dataset(cls, dataset, map_crs='epsg:4326'): transform = dataset.transform image_crs = None if dataset.crs is None else dataset.crs.wkt no_crs_tf = (image_crs is None) or (image_crs == map_crs) no_affine_tf = (transform is None) or (transform == Affine.identity()) if no_crs_tf and no_affine_tf: return IdentityCRSTransformer() if transform is None: transform = Affine.identity() return cls(transform, image_crs, map_crs)
def resample_meta(solar_zenith, solar_azimuth,meta_name, index): """ Resamples Solar Zenith and solar azimuth angle from 5x5 km to 10 m Grid (nearest neighbor) and writes into GeoTIFF Parameters ---------- solar_zenith: np.array float64 data in 5km x 5 km grid solar_azimuth: np.array float64 data in 5 km x 5 km grid meta_name: str Name of .xml file containing metadata index: int number of current tile (just used for naming convention) Returns ------- None """ reference_tile = glob.glob(os.path.join(meta_name[:-10],'IMG_DATA','*_B02.jp2'))[0] # Open 10 m resolution tile to read size and dimension of final tile: with rasterio.open(reference_tile) as src: out_meta = src.meta.copy() newarr = src.read() newarr = np.squeeze(newarr) newarr = newarr.astype(float) new_transform = src.transform old_transform = Affine(new_transform.a * 500, new_transform.b, new_transform.c, new_transform.d, new_transform.e * 500, new_transform.f) out_meta['dtype'] = 'float64' out_meta['driver'] = "GTiff" angles = [solar_zenith, solar_azimuth] angles_str = ["solar_zenith.tif", "solar_azimuth.tif"] id = 0 if not os.path.exists(os.path.join(cfg.PATHS['working_dir'], 'cache', str(cfg.PARAMS['date'][0]), 'meta')): os.makedirs(os.path.join(cfg.PATHS['working_dir'], 'cache', str(cfg.PARAMS['date'][0]), 'meta')) for angle in angles: with rasterio.open(os.path.join(cfg.PATHS['working_dir'], 'cache', str(cfg.PARAMS['date'][0]), 'meta', str(index)+angles_str[id]), "w", **out_meta) \ as dest: reproject( source=angle, destination=newarr, src_transform=old_transform, dst_transform=src.transform, src_crs=src.crs, dst_crs=src.crs, resampling=Resampling.nearest) dest.write(newarr, indexes=1) id = id + 1
def main(): samplefile = r'bxk1-d-ck.idf' tiffile = samplefile.replace('.idf', '.geotiff') dtype = rasterio.float64 driver = 'AAIGrid' crs = CRS.from_epsg(28992) # read data from idf file idffile = idfpy.IdfFile(filepath=samplefile, mode='rb') geotransform = idffile.geotransform height = idffile.header['nrow'] width = idffile.header['ncol'] nodata = idffile.header['nodata'] transform = Affine.from_gdal(*geotransform) # write data from idf file to geotiff with rasterio profile = { 'width': width, 'height': height, 'count': 1, 'dtype': dtype, 'driver': driver, 'crs': crs, 'transform': transform, 'nodata': nodata, } # the default profile would be sufficient for the example, however the profile dict shows how to make the export # profile idffile.to_raster(tiffile, **profile)
def make_affine(height, width, ul, lr): """ Create an affine for a tile of a given size """ xCell = (ul[0] - lr[0]) / width yCell = (ul[1] - lr[1]) / height return Affine(-xCell, 0.0, ul[0], 0.0, -yCell, ul[1])
def makeTesting(output, size, windowsize, bands): kwargs = { 'count': bands, 'crs': { 'init': u'epsg:3857' }, 'dtype': 'uint8', 'driver': u'GTiff', 'transform': Affine(4.595839562240513, 0.0, -13550756.3744, 0.0, -4.595839562240513, 6315533.02503), 'height': size, 'width': size, 'compress': 'lzw', 'blockxsize': windowsize, 'blockysize': windowsize, 'tiled': True } randArr = np.array([(np.random.rand(size, size) * 255).astype(np.uint8) for i in range(bands)]) with rasterio.open(output, 'w', **kwargs) as dst: dst.write(randArr)
def resample_raster_dataset(raster, scale): t = raster.transform # rescale the metadata transform = Affine(t.a / scale, t.b, t.c, t.d, t.e / scale, t.f) height = int(raster.height * scale) width = int(raster.width * scale) profile = raster.profile profile.update(transform=transform, driver='GTiff', height=height, width=width) data = raster.read( # Note changed order of indexes, arrays are band, row, col order not row, col, band out_shape=(raster.count, height, width), resampling=Resampling.bilinear, ) with MemoryFile() as memfile: with memfile.open(**profile) as dataset: # Open as DatasetWriter dataset.write(data) with memfile.open() as dataset: # Reopen as DatasetReader return data, dataset
def ShapeToArray(inputgeodf, cellsize, valfield=None, fillval=0): """Transform vector data into numpy arrays. Locations that vector data presents are valued to 1, otherwise 0. :param GeoDataFrame inputgeodf: input GeoDataFrame :param int cellsize: cell size used to transform the vector data :param string valfield: the field contains values for each cell in the output array :param int fillval: fill value for all areas not covered by the input geometries :return: numpy array, affine object, and extent of the original vector data """ extent = inputgeodf.total_bounds outshape = (int(round((extent[3] - extent[1]) / cellsize)), int(round((extent[2] - extent[0]) / cellsize))) trans = Affine(cellsize, 0, extent[0], 0, -cellsize, extent[3]) if valfield is None: arr = features.rasterize(inputgeodf[inputgeodf.geometry.name], out_shape=outshape, fill=fillval, transform=trans) else: arr = features.rasterize(tuple( zip(inputgeodf[inputgeodf.geometry.name], inputgeodf[valfield])), out_shape=outshape, fill=fillval, transform=trans) return arr, trans, extent
def _yield_downsampled_raster(raster): # https://gis.stackexchange.com/questions/329434/creating-an-in-memory-rasterio-dataset-from-numpy-array/329439#329439 max_n = np.product(MAX_LOAD_SHAPE) n = raster.height * raster.width scale = 1.0 if n > max_n: scale = max_n / n if scale == 1.0: yield raster return t = raster.transform # rescale the metadata transform = Affine(t.a / scale, t.b, t.c, t.d, t.e / scale, t.f) height = int(raster.height * scale) width = int(raster.width * scale) profile = raster.profile profile.update(transform=transform, height=height, width=width) data = raster.read( out_shape=(raster.count, height, width), resampling=Resampling.bilinear, ) with MemoryFile() as memfile: with memfile.open(**profile) as dataset: dataset.write(data) del data with memfile.open() as dataset: # Reopen as DatasetReader yield dataset # Note yield not return
def append(self, centr): """ Append raster or points. Raster needs to have the same resolution """ 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':Affine(self.meta['transform'][0], \ 0.0, left, 0.0, self.meta['transform'][4], top)} else: LOGGER.debug('Appending points') if not equal_crs(centr.geometry.crs, self.geometry.crs): LOGGER.error('Different CRS not accepted.') raise ValueError lat = np.append(self.lat, centr.lat) lon = np.append(self.lon, centr.lon) crs = self.geometry.crs self.__init__() self.set_lat_lon(lat, lon, crs)
def resample(self, dst_res=None, dst_shape=None, interpolation='nearest'): transform = self.transform if dst_res is None else Affine( dst_res[1], self.transform.b, self.transform.c, self.transform.d, -dst_res[0], self.transform.f) if dst_res is not None and dst_shape is None: target_height = int(self.height * self.res[0] / dst_res[0]) target_width = int(self.width * self.res[1] / dst_res[1]) elif dst_shape is not None: target_height = dst_shape[1] target_width = dst_shape[2] else: target_height = self.height target_width = self.width new_raster = np.empty(shape=(1, target_height, target_width), dtype=self.dtype) reproject(self._raster, new_raster, src_transform=self.transform, dst_transform=transform, src_crs=self.crs, dst_crs=self.crs, resampling=getattr(Resampling, interpolation)) return BandSample(self._name, new_raster, self.crs, transform, self.nodata)
def increase_resolution(raster_file_path: str, factor_increase: int): """ References: * mapbox.github.io/rasterio/topics/resampling.html#use-decimated-reads :param raster_file_path: :param factor_increase: :return: """ # this method need a integer factor resolution res = int(factor_increase) # alias with rasterio.open(raster_file_path) as src: image = src.read() image_new = np.empty( shape=( image.shape[0], # same number of bands round(image.shape[1] * res), # n times resolution round(image.shape[2] * res)), # n times resolution dtype=image.dtype) image = src.read(out=image_new).copy() meta = dict(src.profile) aff = copy(meta['affine']) meta['transform'] = Affine(aff.a / res, aff.b, aff.c, aff.d, aff.e / res, aff.f) meta['affine'] = meta['transform'] meta['width'] *= res meta['height'] *= res with rasterio.open(raster_file_path, "w", **meta) as dst: dst.write(image)
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 d_lon (float): longitude step 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': Affine(d_lon, 0.0, xo_lon, 0.0, d_lat, xf_lat) }
def rio_resample(srcpath, outpath, res_factor = 15): with rio.open(srcpath) as src: arr = src.read() newarr = np.empty(shape=(arr.shape[0], int(arr.shape[1] * res_factor), int(arr.shape[2] * res_factor))) # adjust the new affine transform to the 150% smaller cell size aff = src.transform newaff = Affine(aff.a / res_factor, aff.b, aff.c, aff.d, aff.e /res_factor, aff.f) kwargs = src.meta.copy() #kwargs['transform'] = newaff #kwargs['affine'] = newaff kwargs.update({ 'crs': src.crs, 'transform': newaff, 'affine': newaff, 'width': int(arr.shape[2] * res_factor), 'height': int(arr.shape[1] * res_factor) }) with rio.open(outpath, 'w', **kwargs) as dst: reproject( arr, newarr, src_transform = aff, dst_transform = newaff, src_crs = src.crs, dst_crs = src.crs, resample = Resampling.bilinear) dst.write(newarr[0].astype(rio.float32), indexes=1)
def test_get_transform(): dx = 5. height = 2 xll, yll = 0., 0. rotation = 30. xul = _xll_to_xul(xll, height * dx, rotation) yul = _yll_to_yul(yll, height * dx, rotation) transform = get_transform(xul=xul, yul=yul, dx=dx, dy=-dx, rotation=rotation) transform2 = Affine(dx, 0., xul, 0., -dx, yul) * \ Affine.rotation(rotation) assert transform == transform2
def array2coords(array, array_transform, nodata): ''' Parameters ---------- array : numpy.ndarray 2D Numpy array to be converted array_transform : affine.Affine The affine transformation needed. Can be derived from a rasterio.profile nodata : float Value to be ignored from output dataset Returns ------- pandas.DataFrame ''' T1 = array_transform * Affine.translation( 0.5, 0.5) # reference the pixel centre rc2xy = lambda r, c: (c, r) * T1 row, col = np.where(array != nodata) z = np.extract(array != nodata, array) df_coords = pd.DataFrame({'col': col, 'row': row, 'z': z}) df_coords['x'] = df_coords.apply(lambda row: rc2xy(row.row, row.col)[0], axis=1) df_coords['y'] = df_coords.apply(lambda row: rc2xy(row.row, row.col)[1], axis=1) return df_coords
def test_transform_raster_pass(self): meta, inten_ras = read_raster(HAZ_DEMO_FL, transform=Affine(0.009000000000000341, 0.0, -69.33714959699981, 0.0, -0.009000000000000341, 10.42822096697894), height=500, width=501) left = meta['transform'].xoff top = meta['transform'].yoff bottom = top + meta['transform'][4] * meta['height'] right = left + meta['transform'][0] * meta['width'] self.assertAlmostEqual(left, -69.33714959699981) self.assertAlmostEqual(bottom, 5.928220966978939) self.assertAlmostEqual(right, -64.82814959699981) self.assertAlmostEqual(top, 10.42822096697894) self.assertEqual(meta['width'], 501) self.assertEqual(meta['height'], 500) self.assertEqual(meta['crs'].to_epsg(), 4326) self.assertEqual(inten_ras.shape, (1, 500 * 501)) meta, inten_all = read_raster(HAZ_DEMO_FL, window=Window(0, 0, 501, 500)) self.assertTrue(np.array_equal(inten_all, inten_ras))
def sample(self, y, x, height, width, **kwargs): """ Read sample of the Band to memory. The sample is defined by its size and position in the raster, without respect to the georeference. In case if the sample coordinates spread out of the image boundaries, the image is padded with nodata value. Args: x: pixel horizontal coordinate of left top corner of the sample y: pixel vertical coordinate of left top corner of the sample width: spatial dimension of sample in pixels height: spatial dimension of sample in pixels Returns: a new :obj:`BandSample` containing the specified spatial subset of the band """ coord_x = self.transform.c + x * self.transform.a coord_y = self.transform.f + y * self.transform.e dst_crs = self.crs dst_name = os.path.basename(self.name) dst_nodata = self.nodata if self.nodata is not None else 0 dst_transform = Affine(self.transform.a, self.transform.b, coord_x, self.transform.d, self.transform.e, coord_y) dst_raster = self._band.read(window=((y, y + height), (x, x + width)), boundless=True, fill_value=dst_nodata) sample = BandSample(dst_name, dst_raster, dst_crs, dst_transform, dst_nodata) return sample
def rescale_transform(src_transform, src_width, src_height, scale): """Calculate the transform corresponding to a pixel size multiplied by a given scale factor. Parameters ---------- src_transform : Affine Source affine transform. src_width : int Source raster width. src_height : int Source raster height. scale : float Scale factor (e.g. 0.5 to reduce pixel size by half). Returns ------- dst_transform : Affine New affine transform. dst_width : int New raster width. dst_height : int New raster height. """ dst_transform = Affine(src_transform.a * scale, src_transform.b, src_transform.c, src_transform.d, src_transform.e * scale, src_transform.f) dst_width = int(src_width / scale) dst_height = int(src_height / scale) return dst_transform, dst_width, dst_height
def pix_to_coord( transform_array: Union[List, np.ndarray], row: Union[int, np.ndarray], col: Union[List, np.ndarray], ) -> Tuple[np.ndarray, np.ndarray]: """ Transform pixels to coordinates :param transform_array: Transform :type transform_array: List or np.ndarray :param row: row :type row: int or np.ndarray :param col: column :type col: List or np.ndarray :return: x,y :rtype: np.ndarray, np.ndarray """ transform = Affine.from_gdal( transform_array[0], transform_array[1], transform_array[2], transform_array[3], transform_array[4], transform_array[5], ) # Set the offset to ul (upper left) x, y = rasterio.transform.xy(transform, row, col, offset="ul") if not isinstance(x, int): x = np.array(x) y = np.array(y) return x, y
def setUp(self): self.arr = np.array([[4, 4, 3, 2], [4, 4, 1, 1], [1, 4, 0, 2]], dtype='uint8').reshape(3, 4, 1) self.masked_filled = np.array( [[4, 4, 0, 0], [4, 4, 0, 0], [0, 4, 0, 0]], dtype='uint8').reshape(3, 4, 1) self.arr4ch = np.array([[[4, 4, 3, 2], [4, 4, 1, 1], [1, 4, 0, 2]], [[4, 4, 3, 2], [4, 4, 1, 1], [1, 4, 0, 2]]], dtype='uint8') self.masked_filled4ch = np.array( [[[4, 4, 0, 0], [4, 4, 0, 0], [0, 4, 0, 0]], [[4, 4, 0, 0], [4, 4, 0, 0], [0, 4, 0, 0]]], dtype='uint8') self.meta = { 'driver': 'GTiff', 'dtype': 'uint8', 'nodata': None, 'width': 4, 'height': 3, 'count': 1, 'crs': CRS.from_epsg(32737), 'transform': Affine(10.0, 0.0, 199980.0, 0.0, -10.0, 9300040.0) }
def test_file_writer(): test_data = np.zeros((3, 256, 256), dtype=np.uint8) test_opts = { 'driver': 'PNG', 'dtype': 'uint8', 'height': 512, 'width': 512, 'count': 3, 'crs': 'EPSG:3857' } test_affine = Affine(1, 0, 0, 0, -1, 0) test_bytearray = _encode_as_png(test_data, test_opts, test_affine) assert len(test_bytearray) == 842 test_complex_data = test_data.copy() test_complex_data[0] += (np.random.rand(256, 256) * 255).astype(np.uint8) test_complex_data[1] += 10 test_bytearray_complex = _encode_as_png(test_complex_data, test_opts, test_affine) assert len(test_bytearray) < len(test_bytearray_complex)
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): 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 = ast.literal_eval(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] = 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()
class Img(object): def __enter__(self): return self def __exit__(self, type, value, tb): pass @staticmethod def read_masks(band: int = 0, window: Optional[Window] = None) -> np.ndarray: return np.array([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) @staticmethod def block_windows(idx: int): for i in range(0, 2): yield (0, i), Window(i, 0, 1, 1) profile: Dict[str, Any] = { "transform": Affine(0, 2, 0, 0, -2, 0), "width": 3, "height": 3, "crs": CRS.from_epsg(4326), "blockxsize": 16, "blockysize": 16, "dtype": np.dtype("uint"), } bounds: box = box(1, 1, 0, 0)
def __mask_to_polygons(mask): """[summary] Args: mask ([type]): [description] Returns: [type]: [description] """ # XXX: maybe this should be merged with __mask_to_polys() defined above import numpy as np from rasterio import features, Affine from shapely import geometry all_polygons = [] for shape, value in features.shapes(mask.astype(np.int16), mask=(mask > 0), transform=Affine(1.0, 0, 0, 0, 1.0, 0)): all_polygons.append(geometry.shape(shape)) all_polygons = geometry.MultiPolygon(all_polygons) 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 = geometry.MultiPolygon([all_polygons]) return all_polygons
def example_reproject(): import idfpy from matplotlib import pyplot as plt from rasterio import Affine from rasterio.crs import CRS from rasterio.warp import reproject, Resampling import numpy as np with idfpy.open('bxk1-d-ck.idf') as src: a = src.read(masked=True) nr, nc = src.header['nrow'], src.header['ncol'] dx, dy = src.header['dx'], src.header['dy'] src_transform = Affine.from_gdal(*src.geotransform) # define new grid transform (same extent, 10 times resolution) dst_transform = Affine.translation(src_transform.c, src_transform.f) dst_transform *= Affine.scale(dx / 10., -dy / 10.) # define coordinate system (here RD New) src_crs = CRS.from_epsg(28992) # initialize new data array b = np.empty((10*nr, 10*nc)) # reproject using Rasterio reproject( source=a, destination=b, src_transform=src_transform, dst_transform=dst_transform, src_crs=src_crs, dst_crs=src_crs, resampling=Resampling.bilinear, ) # result as masked array b = np.ma.masked_equal(b, a.fill_value) # plot images fig, axes = plt.subplots(nrows=2, ncols=1) axes[0].imshow(a.filled(np.nan)) axes[0].set_title('bxk1 original') axes[1].imshow(b.filled(np.nan)) axes[1].set_title('bxk1 resampled') plt.show()
def main(): for i in range(2): dat = nc.Dataset(innc[i]) print dat #sum monthly values for 2010 dat2010 = dat.variables[varname[i]][600:611,:,:].sum(0) cols = 720 rows = 360 d = 1/2.0 with rasterio.open(outras[i],'w', 'GTiff', width=cols, height=rows, dtype=dat2010.dtype, crs={'init': 'EPSG:4326'}, transform=A.translation(-cols*d/2, rows*d/2) * A.scale(d, -d), count=1) as dst: dst.write_band(1,dat2010)
def coordinates(fn=None, meta=None, numpy_array=None, input_crs=None, to_latlong=False): """ take a raster file as input and return the centroid coords for each of the grid cells as a pair of numpy 2d arrays (longitude, latitude) """ import rasterio import numpy as np from affine import Affine from pyproj import Proj, transform if fn: # Read raster with rasterio.open(fn) as r: T0 = r.affine # upper-left pixel corner affine transform p1 = Proj(r.crs) A = r.read(1) # pixel values elif (meta is not None) & (numpy_array is not None): A = numpy_array if input_crs != None: p1 = Proj(input_crs) T0 = meta["affine"] else: p1 = None T0 = meta["affine"] else: BaseException("check inputs") # All rows and columns cols, rows = np.meshgrid(np.arange(A.shape[1]), np.arange(A.shape[0])) # Get affine transform for pixel centres T1 = T0 * Affine.translation(0.5, 0.5) # Function to convert pixel row/column index (from 0) to easting/northing at centre rc2en = lambda r, c: (c, r) * T1 # All eastings and northings (there is probably a faster way to do this) eastings, northings = np.vectorize(rc2en, otypes=[np.float, np.float])(rows, cols) if to_latlong == False: return eastings, northings elif (to_latlong == True) & (input_crs != None): # Project all longitudes, latitudes longs, lats = transform(p1, p1.to_latlong(), eastings, northings) return longs, lats else: BaseException("cant reproject to latlong without an input_crs")
def to_raster(self, fp=None, epsg=28992, driver='AAIGrid'): """export Idf to a geotiff""" self.check_read() if fp is None: fp = self.filepath.replace('.idf', '.geotiff') logging.warning('no filepath was given, exported to {fp}'.format(fp=fp)) # set profile profile = { 'width': self.header['ncol'], 'height': self.header['nrow'], 'transform': Affine.from_gdal(*self.geotransform), 'nodata': self.header['nodata'], 'count': 1, 'dtype': rasterio.float64, 'driver': driver, 'crs': CRS.from_epsg(epsg), } logging.info('writing to {f:}'.format(f=fp)) with rasterio.open(fp, 'w', **profile) as dst: dst.write(self.masked_data.astype(profile['dtype']), 1)
def export_array(modelgrid, filename, a, nodata=-9999, fieldname='value', **kwargs): """Write a numpy array to Arc Ascii grid or shapefile with the model reference. Parameters ---------- filename : str Path of output file. Export format is determined by file extention. '.asc' Arc Ascii grid '.tif' GeoTIFF (requries rasterio package) '.shp' Shapefile a : 2D numpy.ndarray Array to export nodata : scalar Value to assign to np.nan entries (default -9999) fieldname : str Attribute field name for array values (shapefile export only). (default 'values') kwargs: keyword arguments to np.savetxt (ascii) rasterio.open (GeoTIFF) or flopy.export.shapefile_utils.write_grid_shapefile2 Notes ----- Rotated grids will be either be unrotated prior to export, using scipy.ndimage.rotate (Arc Ascii format) or rotation will be included in their transform property (GeoTiff format). In either case the pixels will be displayed in the (unrotated) projected geographic coordinate system, so the pixels will no longer align exactly with the model grid (as displayed from a shapefile, for example). A key difference between Arc Ascii and GeoTiff (besides disk usage) is that the unrotated Arc Ascii will have a different grid size, whereas the GeoTiff will have the same number of rows and pixels as the original. """ if filename.lower().endswith(".asc"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('Arc ascii arrays require a uniform grid.') xoffset, yoffset = modelgrid.xoffset, modelgrid.yoffset cellsize = modelgrid.delr[0] # * self.length_multiplier fmt = kwargs.get('fmt', '%.18e') a = a.copy() a[np.isnan(a)] = nodata if modelgrid.angrot != 0: try: from scipy.ndimage import rotate a = rotate(a, modelgrid.angrot, cval=nodata) height_rot, width_rot = a.shape xmin, ymin, xmax, ymax = modelgrid.extent dx = (xmax - xmin) / width_rot dy = (ymax - ymin) / height_rot cellsize = np.max((dx, dy)) # cellsize = np.cos(np.radians(self.rotation)) * cellsize xoffset, yoffset = xmin, ymin except ImportError: print('scipy package required to export rotated grid.') pass filename = '.'.join( filename.split('.')[:-1]) + '.asc' # enforce .asc ending nrow, ncol = a.shape a[np.isnan(a)] = nodata txt = 'ncols {:d}\n'.format(ncol) txt += 'nrows {:d}\n'.format(nrow) txt += 'xllcorner {:f}\n'.format(xoffset) txt += 'yllcorner {:f}\n'.format(yoffset) txt += 'cellsize {}\n'.format(cellsize) # ensure that nodata fmt consistent w values txt += 'NODATA_value {}\n'.format(fmt) % (nodata) with open(filename, 'w') as output: output.write(txt) with open(filename, 'ab') as output: np.savetxt(output, a, **kwargs) print('wrote {}'.format(filename)) elif filename.lower().endswith(".tif"): if len(np.unique(modelgrid.delr)) != len(np.unique(modelgrid.delc)) != 1 \ or modelgrid.delr[0] != modelgrid.delc[0]: raise ValueError('GeoTIFF export require a uniform grid.') try: import rasterio from rasterio import Affine except: print('GeoTIFF export requires the rasterio package.') return dxdy = modelgrid.delc[0] # * self.length_multiplier trans = Affine.translation(modelgrid.xoffset, modelgrid.yoffset) * \ Affine.rotation(modelgrid.angrot) * \ Affine.scale(dxdy, -dxdy) # third dimension is the number of bands a = a.copy() if len(a.shape) == 2: a = np.reshape(a, (1, a.shape[0], a.shape[1])) if a.dtype.name == 'int64': a = a.astype('int32') dtype = rasterio.int32 elif a.dtype.name == 'int32': dtype = rasterio.int32 elif a.dtype.name == 'float64': dtype = rasterio.float64 elif a.dtype.name == 'float32': dtype = rasterio.float32 else: msg = 'ERROR: invalid dtype "{}"'.format(a.dtype.name) raise TypeError(msg) meta = {'count': a.shape[0], 'width': a.shape[2], 'height': a.shape[1], 'nodata': nodata, 'dtype': dtype, 'driver': 'GTiff', 'crs': modelgrid.proj4, 'transform': trans } meta.update(kwargs) with rasterio.open(filename, 'w', **meta) as dst: dst.write(a) print('wrote {}'.format(filename)) elif filename.lower().endswith(".shp"): from ..export.shapefile_utils import write_grid_shapefile2 epsg = kwargs.get('epsg', None) prj = kwargs.get('prj', None) if epsg is None and prj is None: epsg = modelgrid.epsg write_grid_shapefile2(filename, modelgrid, array_dict={fieldname: a}, nan_val=nodata, epsg=epsg, prj=prj)
def _make_src_affine(src_data_array): src_bounds = _get_bounds(src_data_array) src_left, src_bottom, src_right, src_top = src_bounds src_resolution_x, src_resolution_y = _get_resolution(src_data_array, as_tuple=True) return Affine.translation(src_left, src_top) * Affine.scale(src_resolution_x, src_resolution_y)
def main(): # load and average netcdfs arr = None for f in NETCDFS: ds = nc.Dataset(f,'r') if arr is None: print ds.variables.keys() arr = np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) else: arr += np.asarray(ds.variables['lwe_thickness']) / len(NETCDFS) # multiply by scale factor ds = nc.Dataset(SCALER,'r') print ds.variables.keys() scaler = np.asarray(ds.variables['SCALE_FACTOR']) print scaler.shape arr = arr*scaler # extract error grids m_err = np.asarray(ds.variables['MEASUREMENT_ERROR']) l_err = np.asarray(ds.variables['LEAKAGE_ERROR']) t_err = np.sqrt(m_err*m_err + l_err*l_err) # compute slopes, coefficients print arr.shape slope_arr = np.zeros(arr.shape[1:]) r2_arr = np.zeros(arr.shape[1:]) p_arr = np.zeros(arr.shape[1:]) print slope_arr.shape time = np.arange(arr.shape[0]) print time.shape for i in range(arr.shape[1]): for j in range(arr.shape[2]): b1, b0, r2, p, sd = stats.linregress(arr[:,i,j], time) slope_arr[i,j]=b1 r2_arr[i,j]=r2 p_arr[i,j]=p # dump to csv np.savetxt(SLOPE,slope_arr,delimiter=',') np.savetxt(R2,r2_arr,delimiter=',') np.savetxt(P,p_arr,delimiter=',') np.savetxt(ERR,t_err,delimiter=',') # rescale to WGS84 and dump to tif bands rows = arr.shape[1] cols = arr.shape[2] d = 1 transform = A.translation(-cols*d/2,-rows*d/2) * A.scale(d,d) print transform slope_arr = np.roll(slope_arr.astype(rio.float64),180) r2_arr = np.roll(r2_arr.astype(rio.float64),180) p_arr = np.roll(p_arr.astype(rio.float64),180) t_err = np.roll(t_err.astype(rio.float64),180) with rio.open(OUT, 'w', 'GTiff', width=cols, height=rows, dtype=rio.float64, crs={'init': 'EPSG:4326'}, transform=transform, count=4) as out: out.write_band(1, slope_arr) out.write_band(2, r2_arr) out.write_band(3, p_arr) out.write_band(4, t_err)
import rasterio from rasterio import Affine as A from rasterio.warp import reproject, RESAMPLING tempdir = '/tmp' tiffname = os.path.join(tempdir, 'example.tif') with rasterio.drivers(): # Consider a 512 x 512 raster centered on 0 degrees E and 0 degrees N # with each pixel covering 15". rows, cols = src_shape = (512, 512) dpp = 1.0/240 # decimal degrees per pixel # The following is equivalent to # A(dpp, 0, -cols*dpp/2, 0, -dpp, rows*dpp/2). src_transform = A.translation(-cols*dpp/2, rows*dpp/2) * A.scale(dpp, -dpp) src_crs = {'init': 'EPSG:4326'} source = numpy.ones(src_shape, numpy.uint8)*255 # Prepare to reproject this rasters to a 1024 x 1024 dataset in # Web Mercator (EPSG:3857) with origin at -8928592, 2999585. dst_shape = (1024, 1024) dst_transform = A.from_gdal(-237481.5, 425.0, 0.0, 237536.4, 0.0, -425.0) dst_transform = dst_transform.to_gdal() dst_crs = {'init': 'EPSG:3857'} destination = numpy.zeros(dst_shape, numpy.uint8) reproject( source, destination, src_transform=src_transform,