def test_rotation_matrix_pivot(): """A rotation matrix with pivot has expected elements""" rot = Affine.rotation(90.0, pivot=(1.0, 1.0)) exp = (Affine.translation(1.0, 1.0) * Affine.rotation(90.0) * Affine.translation(-1.0, -1.0)) for r, e in zip(rot, exp): assert round(r, 15) == round(e, 15)
def test_inverse(self): seq_almost_equal(~Affine.identity(), Affine.identity()) seq_almost_equal( ~Affine.translation(2, -3), Affine.translation(-2, 3)) seq_almost_equal( ~Affine.rotation(-33.3), Affine.rotation(33.3)) t = Affine(1, 2, 3, 4, 5, 6) seq_almost_equal(~t * t, Affine.identity())
def test_roundtrip(): point = (12, 5) trans = Affine.translation(3, 4) rot37 = Affine.rotation(37.) point_prime = (trans * rot37) * point roundtrip_point = ~(trans * rot37) * point_prime seq_almost_equal(point, roundtrip_point)
def chop(bands, dst_transform, size, output_file, photometric): for y in range(0, bands.shape[1], size): for x in range(0, bands.shape[2], size): # crop a grid square ('patch') patch_affine = Affine(*dst_transform) * Affine.translation(x, y) patch = numpy.zeros((bands.shape[0], size, size), dtype=rasterio.uint16) my = min(y + size, bands.shape[1]) mx = min(x + size, bands.shape[2]) for i, band in enumerate(bands): patch[i, 0:my-y, 0:mx-x] = band[y:my, x:mx] if(numpy.max(patch) > 0): out = output_file.replace('{x}', str(x)).replace('{y}', str(y)) with rasterio.open(out, mode='w', driver='GTiff', width=patch.shape[2], height=patch.shape[1], count=patch.shape[0], dtype=numpy.uint8, nodata=0, photometric=photometric, transform=patch_affine, crs=projection) as dst: for i, band in enumerate(patch): dst.write_band(i + 1, band.astype(rasterio.uint8))
def coordinates( fn ): ''' 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 # Read raster with rasterio.open(fn) as r: T0 = r.affine # upper-left pixel corner affine transform p1 = Proj(r.crs) A = r.read_band(1) # pixel values # 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) # Project all longitudes, latitudes # longs, lats = transform(p1, p1.to_latlong(), eastings, northings) # return longs, lats return eastings, northings
def test_rotation_angle(): assert Affine.identity().rotation_angle == 0.0 assert Affine.scale(2).rotation_angle == 0.0 assert Affine.scale(2, 1).rotation_angle == 0.0 assert Affine.translation(32, -47).rotation_angle == pytest.approx(0.0) assert Affine.rotation(30).rotation_angle == pytest.approx(30) assert Affine.rotation(-150).rotation_angle == pytest.approx(-150)
def __init__(self, gzx, gzy, yld, ff, wind, wd, shear, tob=0, dunits='km', wunits='km/h', shearunits='m/s-km', yunits='kT'): self.translation = ~Affine.translation(convert_units(gzx, dunits, 'mi'), convert_units(gzy, dunits, 'mi')) # translate coordinates relative to GZ (st. mi) self.wd = wd # wind direction in degrees (0=N, 90=E, etc.) self.yld = convert_units(yld, yunits, 'MT') # yield (MT) self.ff = ff # fission fraction, 0 < ff <= 1.0 self.wind = convert_units(wind, wunits, 'mph') # wind speed (mi/hr) self.shear = convert_units(shear, shearunits, 'mph/kilofoot') # wind shear in mi/hr-kilofoot self.tob = tob # time of burst (hrs) # FORTRAN is ugly in any language # Store these values in the WSEG10 object to avoid recalculating them d = np.log(self.yld) + 2.42 # physically meaningless, but occurs twice # According to Hanifen, "The cloud is initially formed because the nuclear # fireball vaporizes both the surface of the earth at ground zero and the # weapon itself. The activity contained in the cloud is both neutron induced # and fission. After formation, the fireball rises and begins to cool at its # outer edges faster than the center thereby creating the typical torroidal # currents associated with the nuclear cloud. WSEG arbitrarily assumes that # the cloud will rise to a maximum center height within fifteen minutes and # then stabilize." self.H_c = 44 + 6.1 * np.log(yld) - 0.205 * abs(d) * d # cloud center height lnyield = np.log(self.yld) self.s_0 = np.exp(0.7 + lnyield / 3 - 3.25 / (4.0 + (lnyield + 5.4)**2)) #sigma_0 self.s_02 = self.s_0**2 self.s_h = 0.18 * self.H_c # sigma_h self.T_c = 1.0573203 * (12 * (self.H_c / 60) - 2.5 * (self.H_c / 60)**2) * (1 - 0.5 * np.exp(-1 * (self.H_c / 25)**2)) # time constant self.L_0 = wind * self.T_c # L_0, used by g(x) self.L_02 = self.L_0**2 self.s_x2 = self.s_02 * (self.L_02 + 8 * self.s_02) / (self.L_02 + 2 * self.s_02) self.s_x = np.sqrt(self.s_x2) # sigma_x self.L_2 = self.L_02 + 2 * self.s_x2 self.L = np.sqrt(self.L_2) # L self.n = (ff * self.L_02 + self.s_x2) / (self.L_02 + 0.5 * self.s_x2) # n self.a_1 = 1 / (1 + ((0.001 * self.H_c * wind) / self.s_0)) # alpha_1
def test_is_rectilinear(self): assert Affine.identity().is_rectilinear assert Affine.scale(2.5, 6.1).is_rectilinear assert Affine.translation(4, -1).is_rectilinear assert Affine.rotation(90).is_rectilinear assert not Affine.shear(4, -1).is_rectilinear assert not Affine.rotation(-26).is_rectilinear
def from_geopolygon(cls, geopolygon, resolution, crs=None, align=None): """ :type geopolygon: GeoPolygon :param resolution: (x_resolution, y_resolution) :param CRS crs: CRS to use, if different from the geopolygon :param (float,float) align: Alight geobox such that point 'align' lies on the pixel boundary. :rtype: GeoBox """ # TODO: currently only flipped Y-axis data is supported assert resolution[1] > 0 assert resolution[0] < 0 align = align or (0.0, 0.0) assert 0.0 <= align[1] <= abs(resolution[1]) assert 0.0 <= align[0] <= abs(resolution[0]) if crs is None: crs = geopolygon.crs else: geopolygon = geopolygon.to_crs(crs) def align_pix(val, res, off): return math.floor((val-off)/res) * res + off bounding_box = geopolygon.boundingbox left = align_pix(bounding_box.left, resolution[1], align[1]) top = align_pix(bounding_box.top, resolution[0], align[0]) affine = (Affine.translation(left, top) * Affine.scale(resolution[1], resolution[0])) return GeoBox(crs=crs, affine=affine, width=int(math.ceil((bounding_box.right-left)/resolution[1])), height=int(math.ceil((bounding_box.bottom-top)/resolution[0])))
def test_is_conformal(self): assert Affine.identity().is_conformal assert Affine.scale(2.5, 6.1).is_conformal assert Affine.translation(4, -1).is_conformal assert Affine.rotation(90).is_conformal assert Affine.rotation(-26).is_conformal assert not Affine.shear(4, -1).is_conformal
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) User must give either: fn = path to the rasterio readable raster OR meta & numpy ndarray (usually obtained by rasterio.open(fn).read( 1 )) where: meta = a rasterio style metadata dictionary ( rasterio.open(fn).meta ) numpy_array = 2d numpy array representing a raster described by the meta input_crs = rasterio style proj4 dict, example: { 'init':'epsg:3338' } to_latlong = boolean. If True all coordinates will be returned as EPSG:4326 If False all coordinates will be returned in input_crs returns: meshgrid of longitudes and latitudes borrowed from here: https://gis.stackexchange.com/a/129857 ''' 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 -- this is much faster than np.apply_along_axis 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 test_rotation_constructor_with_pivot(self): assert_equal(tuple(Affine.rotation(60)), tuple(Affine.rotation(60, pivot=(0, 0)))) rot = Affine.rotation(27, pivot=(2, -4)) r = math.radians(27) s, c = math.sin(r), math.cos(r) assert_equal( tuple(rot), (c, -s, 2 - 2 * c - 4 * s, s, c, -4 - 2 * s + 4 * c, 0, 0, 1)) assert_equal(tuple(Affine.rotation(0, (-3, 2))), tuple(Affine.identity())) rot_pivot = Affine.rotation(27, pivot=(2, -4)) trans_rot_trans = (Affine.translation(2, -4) * Affine.rotation(27) * Affine.translation(-2, 4)) seq_almost_equal(tuple(rot_pivot), tuple(trans_rot_trans))
def transform_from_latlon( lat, lon ): ''' simple way to make an affine transform from lats and lons coords ''' from affine import Affine lat = np.asarray( lat ) lon = np.asarray(lon) trans = Affine.translation(lon[0], lat[0]) scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0]) return trans * scale
def test_translation_constructor(self): trans = Affine.translation(2, -5) assert isinstance(trans, Affine) assert_equal( tuple(trans), (1, 0, 2, 0, 1, -5, 0, 0, 1))
def test_associative(): point = (12, 5) trans = Affine.translation(-10., -5.) rot90 = Affine.rotation(90.) result1 = rot90 * (trans * point) result2 = (rot90 * trans) * point seq_almost_equal(result1, (0., 2.)) seq_almost_equal(result1, result2)
def from_origin(west, north, xsize, ysize): """Return an Affine transformation given upper left and pixel sizes. Return an Affine transformation for a georeferenced raster given the coordinates of its upper left corner `west`, `north` and pixel sizes `xsize`, `ysize`. """ return Affine.translation(west, north) * Affine.scale(xsize, -ysize)
def test_determinant(self): assert_equal(Affine.identity().determinant, 1) assert_equal(Affine.scale(2).determinant, 4) assert_equal(Affine.scale(0).determinant, 0) assert_equal(Affine.scale(5, 1).determinant, 5) assert_equal(Affine.scale(-1, 1).determinant, -1) assert_equal(Affine.scale(-1, 0).determinant, 0) assert_almost_equal(Affine.rotation(77).determinant, 1) assert_almost_equal(Affine.translation(32, -47).determinant, 1)
def from_bounds(west, south, east, north, width, height): """Return an Affine transformation given bounds, width and height. Return an Affine transformation for a georeferenced raster given its bounds `west`, `south`, `east`, `north` and its `width` and `height` in number of pixels. """ return Affine.translation(west, north) * Affine.scale( (east - west) / width, (south - north) / height)
def test_determinant(self): assert Affine.identity().determinant == 1 assert Affine.scale(2).determinant == 4 assert Affine.scale(0).determinant == 0 assert Affine.scale(5, 1).determinant == 5 assert Affine.scale(-1, 1).determinant == -1 assert Affine.scale(-1, 0).determinant == 0 assert Affine.rotation(77).determinant == pytest.approx(1) assert Affine.translation(32, -47).determinant == pytest.approx(1)
def affine(self, pixelbuffer=0): """ Return an Affine object of tile. - pixelbuffer: tile buffer in pixels """ left = self.bounds(pixelbuffer=pixelbuffer)[0] top = self.bounds(pixelbuffer=pixelbuffer)[3] return Affine.translation(left, top) * Affine.scale( self.pixel_x_size, -self.pixel_y_size)
def test_eccentricity_complex(): assert \ (Affine.scale(2, 3) * Affine.rotation(77)).eccentricity == \ pytest.approx(math.sqrt(5) / 3) assert \ (Affine.rotation(77) * Affine.scale(2, 3)).eccentricity == \ pytest.approx(math.sqrt(5) / 3) assert \ (Affine.translation(32, -47) * Affine.rotation(77) * Affine.scale(2, 3)).eccentricity == \ pytest.approx(math.sqrt(5) / 3)
def test_eccentricity(): assert Affine.identity().eccentricity == 0.0 assert Affine.scale(2).eccentricity == 0.0 #assert_equal(Affine.scale(0).eccentricity, ?) assert Affine.scale(2, 1).eccentricity == pytest.approx(math.sqrt(3) / 2) assert Affine.scale(2, 3).eccentricity == pytest.approx(math.sqrt(5) / 3) assert Affine.scale(1, 0).eccentricity == 1.0 assert Affine.rotation(77).eccentricity == pytest.approx(0.0) assert Affine.translation(32, -47).eccentricity == pytest.approx(0.0) assert Affine.scale(-1, 1).eccentricity == pytest.approx(0.0)
def test_is_degenerate(self): assert not Affine.identity().is_degenerate assert not Affine.translation(2, -1).is_degenerate assert not Affine.shear(0, -22.5).is_degenerate assert not Affine.rotation(88.7).is_degenerate assert not Affine.scale(0.5).is_degenerate assert Affine.scale(0).is_degenerate assert Affine.scale(-10, 0).is_degenerate assert Affine.scale(0, 300).is_degenerate assert Affine.scale(0).is_degenerate assert Affine.scale(0).is_degenerate
def test_is_eo3(sample_doc, sample_doc_180): identity = list(Affine.translation(0, 0)) assert is_doc_eo3(sample_doc) is True assert is_doc_eo3(sample_doc_180) is True # If there's no schema field at all, it's treated as legacy eo. assert is_doc_eo3({}) is False assert is_doc_eo3({'crs': 'EPSG:4326'}) is False assert is_doc_eo3({'crs': 'EPSG:4326', 'grids': {}}) is False with pytest.raises(ValueError, match="Unsupported dataset schema.*"): is_doc_eo3({'$schema': 'https://schemas.opendatacube.org/eo4'})
def make_test_raster(value=0, band_names=None, height=3, width=4, dtype=np.uint16, crs=WEB_MERCATOR_CRS, affine=None, image=None): band_names = band_names or [] if affine is None: affine = Affine.translation(10, 12) * Affine.scale(1, -1) if image is None: shape = [len(band_names), height, width] array = np.full(shape, value, dtype=dtype) mask = np.full(shape, False, dtype=bool) image = np.ma.array(data=array, mask=mask) raster = tl.GeoRaster2(image=image, affine=affine, crs=crs, band_names=band_names) return raster
def test_empty_raster_from_roi_affine_3_bands_high(): affine = Affine.translation(10, 12) * Affine.scale(2, -2) raster = make_test_raster(88, [1, 3, 2], affine=affine, height=1301, width=4) empty = GeoRaster2.empty_from_roi(band_names=raster.band_names, roi=raster.footprint(), resolution=2) assert (affine.almost_equals(empty.affine)) assert (raster.crs == empty.crs) assert (raster.shape == empty.shape)
def __getitem__(self, item): indexes = [slice(index.start or 0, index.stop or size, index.step or 1) for size, index in zip(self.shape, item)] for index in indexes: if index.step != 1: raise NotImplementedError('scaling not implemented, yet') affine = self.affine * Affine.translation(indexes[1].start, indexes[0].start) return GeoBox(width=indexes[1].stop - indexes[1].start, height=indexes[0].stop - indexes[0].start, affine=affine, crs=self.crs)
def __py_resample( self, resolution: Union[Tuple[float, float], List[float], float] ) -> "Raster": """ Resample raster using nearest neighbor Parameters ------- resolution: tuple, list spatial resolution target Returns ------- Raster Resampled """ warnings.warn("this function will be removed in v1.0", DeprecationWarning) if isinstance(resolution, (float, int)): resampled_x_resolution = float(resolution) resampled_y_resolution = float(resolution) else: resampled_x_resolution = resolution[0] resampled_y_resolution = resolution[1] resampled_rows = round(self.y_extent / resampled_y_resolution) resampled_cols = round(self.x_extent / resampled_x_resolution) resampled_shape: Tuple[int, ...] = (resampled_rows, resampled_cols, self.layers) if self.layers == 1: resampled_shape = (resampled_rows, resampled_cols) resampled_array = np.zeros( resampled_rows * resampled_cols * self.layers, dtype=self.dtype ).reshape(resampled_shape) resampled_affine = Affine.translation(self.x_min, self.y_min) * Affine.scale( resampled_x_resolution, -resampled_y_resolution ) for row in range(resampled_rows): for col in range(resampled_cols): x, y = rowcol2xy((row, col), resampled_affine) resampled_array[row, col] = self.xy_value( x + (resampled_x_resolution / 2), y + (resampled_y_resolution / 2) ) return Raster( resampled_array, (resampled_x_resolution, resampled_y_resolution), self.x_min, self.y_max, epsg=self.epsg, )
def buffered(self, ybuff, xbuff) -> 'GeoBox': """ Produce a tile buffered by ybuff, xbuff (in CRS units) """ by, bx = (_round_to_res(buf, res) for buf, res in zip((ybuff, xbuff), self.resolution)) affine = self.affine * Affine.translation(-bx, -by) return GeoBox(width=self.width + 2 * bx, height=self.height + 2 * by, affine=affine, crs=self.crs)
def affine(self): if self.size.x is None: self.scale_axis("x", 1.0) if self.size.y is None: self.scale_axis("y", 1.0) x_scale = (self.max.x - self.min.x) / self.size.x # Y axis is reversed: image coordinate conventions y_scale = (self.min.y - self.max.y) / self.size.y trans_aff = Affine.translation(self.min.x, self.max.y) scale_aff = Affine.scale(x_scale, y_scale) return trans_aff * scale_aff
def test_patch_affine(): eps = 1e-100 assert(GeoRaster2._patch_affine(Affine.identity()) == Affine.translation(eps, eps)) assert(GeoRaster2._patch_affine(Affine.translation(2 * eps, 3 * eps)) == Affine.translation(2 * eps, 3 * eps)) assert(GeoRaster2._patch_affine(Affine.translation(2, 3)) == Affine.translation(2, 3)) assert(GeoRaster2._patch_affine(Affine.scale(1.0, -1)) == Affine.translation(eps, -eps) * Affine.scale(1, -1)) assert(GeoRaster2._patch_affine(Affine.scale(-1, 1)) == Affine.translation(-eps, eps) * Affine.scale(-1, 1)) assert(GeoRaster2._patch_affine(Affine.scale(-1, -1)) == Affine.translation(-eps, -eps) * Affine.scale(-1, -1)) assert(GeoRaster2._patch_affine(Affine.scale(1.1, -1)) == Affine.scale(1.1, -1)) assert(GeoRaster2._patch_affine(Affine.scale(1, -1.1)) == Affine.scale(1, -1.1))
def test_warp(): src = np.zeros((128, 256), dtype='int16') src[10:20, 30:50] = 33 dst = np.zeros_like(src) dst_ = warp_affine(src, dst, Affine.translation(+30, +10), resampling='nearest') assert dst_ is dst assert (dst[:10, :20] == 33).all() assert (dst[10:, :] == 0).all() assert (dst[:, 20:] == 0).all() # check GDAL int8 limitation work-around src = src.astype('int8') dst = np.zeros_like(src) dst_ = warp_affine(src, dst, Affine.translation(+30, +10), resampling='nearest') assert dst_ is dst assert (dst[:10, :20] == 33).all() assert (dst[10:, :] == 0).all() assert (dst[:, 20:] == 0).all() # check GDAL int8 limitation work-around, with no-data src = src.astype('int8') dst = np.zeros_like(src) dst_ = warp_affine(src, dst, Affine.translation(+30, +10), resampling='nearest', src_nodata=0, dst_nodata=-3) assert dst_ is dst assert (dst[:10, :20] == 33).all() assert (dst[10:, :] == -3).all() assert (dst[:, 20:] == -3).all()
def test_merge_all_non_overlapping_has_correct_metadata(): # See https://github.com/satellogic/telluric/issues/65 affine = Affine.translation(0, 2) * Affine.scale(1, -1) rs1 = GeoRaster2( image=np.array([[[100, 0], [100, 0]]], dtype=np.uint8), affine=affine, crs=WGS84_CRS, band_names=['red'], nodata=0, ) rs2 = GeoRaster2( image=np.array([[[110, 0], [110, 0]]], dtype=np.uint8), affine=affine, crs=WGS84_CRS, band_names=['green'], nodata=0, ) rs3 = GeoRaster2( image=np.array([[[0, 200], [0, 200]]], dtype=np.uint8), affine=affine, crs=WGS84_CRS, band_names=['red'], nodata=0, ) rs4 = GeoRaster2( image=np.array([[[0, 210], [0, 210]]], dtype=np.uint8), affine=affine, crs=WGS84_CRS, band_names=['green'], nodata=0, ) expected_metadata = GeoRaster2(image=np.ma.masked_array([[ [0, 2], [0, 2], ], [ [1, 3], [1, 3], ]], np.ma.nomask), affine=affine, crs=WGS84_CRS, band_names=['red', 'green']) metadata = merge_all([rs1, rs2, rs3, rs4], rs1.footprint(), pixel_strategy=PixelStrategy.INDEX) assert metadata == expected_metadata
def test_is_degenerate(self): from affine import EPSILON assert not Affine.identity().is_degenerate assert not Affine.translation(2, -1).is_degenerate assert not Affine.shear(0, -22.5).is_degenerate assert not Affine.rotation(88.7).is_degenerate assert not Affine.scale(0.5).is_degenerate assert Affine.scale(0).is_degenerate assert Affine.scale(-10, 0).is_degenerate assert Affine.scale(0, 300).is_degenerate assert Affine.scale(0).is_degenerate assert Affine.scale(0).is_degenerate assert Affine.scale(EPSILON).is_degenerate
def geobox_union_conservative(geoboxes: List[GeoBox]) -> GeoBox: """ Union of geoboxes. Fails whenever incompatible grids are encountered. """ if len(geoboxes) == 0: raise ValueError("No geoboxes supplied") reference, *_ = geoboxes bbox = bbox_union(bounding_box_in_pixel_domain(geobox, reference=reference) for geobox in geoboxes) affine = reference.affine * Affine.translation(*bbox[:2]) return GeoBox(width=bbox.width, height=bbox.height, affine=affine, crs=reference.crs)
def gtif_toGPS(gtiffFile): with rasterio.open(gtiffFile) as r: T0 = r.affine # upper-left pixel corner affine transform p1 = Proj(r.crs) A = r.read(1) # pixel values cols, rows = np.meshgrid(np.arange(A.shape[1]), np.arange(A.shape[0])) T1 = T0 * Affine.translation(0.5, 0.5) rc2en = lambda r, c: (c, r) * T1 eastings, northings = np.vectorize(rc2en, otypes=[np.float, np.float])(rows, cols) p2 = Proj(proj='latlong',datum='WGS84') longs, lats = transform(p1, p2, eastings, northings) return (longs,lats)
def transform(self, recalc=False): """Determine the affine of the `xarray.DataArray`""" if not recalc: try: # get affine from xarray rasterio return Affine(*self._obj.attrs["transform"][:6]) except KeyError: pass src_bounds = self.bounds(recalc=recalc) src_left, _, _, src_top = src_bounds src_resolution_x, src_resolution_y = self.resolution(recalc=recalc) return Affine.translation(src_left, src_top) * Affine.scale( src_resolution_x, src_resolution_y)
def test_from_bounds_rotation(): """Get correct window when transform is rotated""" sqrt2 = math.sqrt(2.0) # An 8 unit square rotated cw 45 degrees around (0, 0). height = 4 width = 4 transform = (Affine.rotation(-45.0) * Affine.translation(-sqrt2, sqrt2) * Affine.scale(sqrt2 / 2.0, -sqrt2 / 2.0)) win = from_bounds(-2.0, -2.0, 2.0, 2.0, transform=transform) assert win.col_off == pytest.approx(-2.0) assert win.row_off == pytest.approx(-2.0) assert win.width == pytest.approx(2.0 * width) assert win.height == pytest.approx(2.0 * height)
def convert_geo(dtm, points): """ Function that converts pixel coordinates to geographic coordinates """ res = [] T0 = dtm.transform T1 = T0 * Affine.translation(0.5, 0.5) for point in points: row1, col1, row2, col2 = point x1y1 = (row1, col1) * T1 x2y2 = (row2, col2) * T1 res.append(x1y1 + x2y2) return res
def _inspect_coords(y, x, center=True, assume_unique=True): # returns transform, bounds, shape y_ = np.atleast_1d(y) x_ = np.atleast_1d(x) if not assume_unique: logger.warning('Computing unique values of coordinates...') y_ = np.unique(y_) x_ = np.unique(x_) minmax_y = y_[0], y_[-1] minmax_x = x_[0], x_[-1] if minmax_y[0] > minmax_y[1]: logger.warning('Unreversing y coordinate min/max') minmax_y = (minmax_y[1], minmax_y[0]) # If spacing is not equal we guess from `(max - min) / n` dy = _check_spacing(y_) if dy is False: warnings.warn('"y" coordinate does not have equal spacing') ny = len(y_) dy = (minmax_y[0] - minmax_y[1]) / (ny - 1) else: ny = (minmax_y[0] - minmax_y[1]) / dy # np.unique returns sorted y so dy is negative, but not if unsorted if not assume_unique: dy *= -1 dx = _check_spacing(x_) if dx is False: warnings.warn('"x" coordinate does not have equal spacing') nx = len(x_) dx = (minmax_x[1] - minmax_x[0]) / (nx - 1) else: nx = (minmax_x[1] - minmax_x[0]) / dx transform = Affine(dx, 0.0, minmax_x[0], 0., dy, minmax_y[1]) if center: # affine transform is relative to upper-left, not pixel center transform = transform * Affine.translation(-0.5, -0.5) # create bounds that cover pixel area bounds = BoundingBox(minmax_x[0] - dx / 2, minmax_y[0] + dy / 2, minmax_x[1] + dx / 2, minmax_y[1] - dy / 2) else: # create bounds that cover pixel area bounds = BoundingBox(minmax_x[0], minmax_y[0] + dy, minmax_x[1] + dx, minmax_y[1]) return transform, bounds, (nx, ny)
def test_read_with_rasterfiledatasource(self, make_sample_geotiff, dst_nodata): sample_geotiff_path, geobox, written_data = make_sample_geotiff( dst_nodata) source = RasterFileDataSource(str(sample_geotiff_path), 1) dest = np.zeros_like(written_data) dst_transform = geobox.transform dst_projection = epsg3577 dst_resampling = Resampling.nearest # Read exactly the hunk of data that we wrote _read_from_source(source, dest, dst_transform, dst_nodata, dst_projection, dst_resampling) assert np.all(written_data == dest) # Try reading from partially outside of our area xoff = 50 offset_transform = dst_transform * Affine.translation(xoff, 0) dest = np.zeros_like(written_data) _read_from_source(source, dest, offset_transform, dst_nodata, dst_projection, dst_resampling) assert np.all(written_data[:, xoff:] == dest[:, :xoff]) # Try reading from complete outside of our area, should return nodata xoff = 300 offset_transform = dst_transform * Affine.translation(xoff, 0) dest = np.zeros_like(written_data) _read_from_source(source, dest, offset_transform, dst_nodata, dst_projection, dst_resampling) if np.isnan(dst_nodata): assert np.all(np.isnan(dest)) else: assert np.all(dst_nodata == dest)
def __init__(self, raster): # load metadata self.gt = raster.GetGeoTransform() self.proj = raster.GetProjection() self.cols = raster.RasterXSize self.rows = raster.RasterYSize self.band = raster.GetRasterBand(1) self.no_data = self.band.GetNoDataValue() # get affine transformation self.T0 = Affine.from_gdal(*raster.GetGeoTransform()) # cell-centered affine transformation self.T1 = self.T0 * Affine.translation(0.5, 0.5) # load data self.data = np.array(raster.ReadAsArray())
def test_transformation(): tf = Affine.translation(1, 2) # when src_affine==dst_affine should transform to itself: transformed_shape = projections.transform(source_shape, source_crs, src_affine=tf, dst_affine=tf) assert transformed_shape == source_shape transformed_shape = projections.transform(source_shape, source_crs, src_affine=tf) assert transformed_shape == Point(-1, -2)
def __init__( self, array: np.ndarray, resolution: Union[None, Tuple[float, float], List[float], Tuple[float, ...], float] = None, x_min: Optional[float] = None, y_min: Optional[float] = None, x_max: Optional[float] = None, y_max: Optional[float] = None, epsg: int = 4326, ): if (resolution is None and x_min is None and y_min is None and x_max is None and y_max is None): raise ValueError( "Please define resolution and at least x minimum and y minimum" ) if resolution is not None and x_min is None and y_min is None: raise ValueError("Please at least define x_min and y_min") if isinstance(resolution, float): self.resolution: Tuple[float, float] = ( resolution, resolution, ) elif resolution is not None and isinstance(resolution, Iterable): self.resolution = (resolution[0], resolution[1]) if resolution is not None and x_min is not None and y_min is not None: self.x_min: float = x_min self.y_min: float = y_min self.x_max: float = x_min + (self.resolution[0] * array.shape[1]) self.y_max: float = y_min + (self.resolution[1] * array.shape[0]) elif (resolution is None and x_min is not None and y_min is not None and x_max is not None and y_max is not None): self.resolution = ( (x_max - x_min) / array.shape[1], (y_max - y_min) / array.shape[0], ) self.x_min = x_min self.y_min = y_min self.x_max = x_max self.y_max = y_max self.array = array self.epsg = epsg self.transform = Affine.translation( self.x_min, self.y_min) * Affine.scale(self.resolution[0], -self.resolution[1]) self.crs = CRS.from_epsg(epsg)
def _transform_from_latlon(lon, lat): """perform an affine tranformation to the latitude/longitude coordinates""" from affine import Affine lat = np.asarray(lat) lon = np.asarray(lon) d_lon = lon[1] - lon[0] d_lat = lat[1] - lat[0] trans = Affine.translation(lon[0] - d_lon / 2, lat[0] - d_lat / 2) scale = Affine.scale(d_lon, d_lat) return trans * scale
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 clip_raster_to_valid_extent(ras): import numpy as np from affine import Affine # test if ras is path or raster_object if isinstance(ras, str): ras_in = ras ras = raster_load(ras_in) elif not isinstance(ras, rasterObj): raise Exception( 'ras is not an instance of rasterObj or str (filepath), raster_to_pd() aborted.' ) if ras.band_count > 1: # unstack data data = np.full((ras.rows, ras.cols, ras.band_count), ras.no_data) for ii in range(0, ras.band_count): data[:, :, ii] = ras.data[ii] valid = np.where(np.any(data != ras.no_data, axis=2)) else: # nest data in list ras.data = [ras.data] valid = np.where(ras.data != ras.no_data) yc_min, xc_min = np.min(valid, axis=1) yc_max, xc_max = np.max(valid, axis=1) x_min, y_min = ras.T0 * (xc_min, yc_min) ras.gt = (x_min, ras.gt[1], ras.gt[2], y_min, ras.gt[4], ras.gt[5]) new_data = [] for ii in range(0, ras.band_count): band = np.full((yc_max - yc_min + 1, xc_max - xc_min + 1), ras.no_data) band[(valid[0] - yc_min, valid[1] - xc_min)] = ras.data[ii][valid] new_data.append(band) ras.data = new_data ras.rows, ras.cols = ras.data[0].shape if ras.band_count == 1: ras.data = ras.data[0] ras.T0 = Affine.from_gdal(*ras.gt) # cell-centered affine transformation ras.T1 = ras.T0 * Affine.translation(0.5, 0.5) return ras
def shift_images(input_directory_path, output_directory_path): """ Shift the images' coordinates. This function shifts the image coordinates and removes the 4th Alpha band from the photograph. It is used to center photographs from distant locations to a central location for manual digitizing for purposes of training an image classifier. Parameters ---------- input_directory_path: string string representing filesystem directory where the photographs are located. output_directory_path: string string representing the filesystem directory where the output photographs will be written to disk. Returns ------- NADA """ x_coord = 476703 y_coord = 1952787 x_increment = 350 y_increment = 350 x_count = 0 y_count = 0 training_data = utility.get_training_data() for key in training_data: y_shift = y_count * y_increment for f in training_data[key]: with rasterio.open(input_directory_path + f + ".tif") as src: x_shift = x_count * x_increment af = src.transform meta = src.meta meta['count'] = 3 meta['transform'] = Affine.translation( x_coord + x_shift, y_coord - y_shift) * Affine.scale( af[0], af[4]) with rasterio.open( output_directory_path + "training_" + f + ".tif", "w", **meta) as dst: dst.write(src.read((1, 2, 3))) x_count += 1 y_count += 1 x_count = 0
def __init__(self, surface, *al, **ad): self._renderer = self._dwg = surface self._bounds = Extents() self._padding = PADDING self._stack = [] self._m = Affine.translation(0, 0) self._xy = (0, 0) self._mxy = self._m * self._xy self._lw = 0 self._rgb = (0, 0, 0) self._ff = "sans-serif" self._fs = 10 self._last_path = None
def transform_from_latlon(lat, lon): """ input 1D array of lat / lon and output an Affine transformation Arguments: --------- : lat (list, np.array) list of lat values : lon (list, np.array) list of lon values """ lat = np.asarray(lat) lon = np.asarray(lon) trans = Affine.translation(lon[0], lat[0]) scale = Affine.scale(lon[1] - lon[0], lat[1] - lat[0]) return trans * scale
def prediction_dataset(raster_path, fn): srcImage = gdal.Open(raster_path) geoTrans = srcImage.GetGeoTransform() mylist1 = list() T0 = Affine.from_gdal(*srcImage.GetGeoTransform()) cols = srcImage.RasterYSize rows = srcImage.RasterXSize T1 = T0 * Affine.translation(0.5, 0.5) rc2xy = lambda r, c: (c, r ) * T1 # Convert row and column to xy coordinates pointlist = [] for i in range(cols): for j in range(rows): pointlist.append(rc2xy(i, j)) # Convert the layer extent to image pixel coordinates # mylist = list() # typelist = list() polylist = pointWithinPolygon.poly_contain() for feat in pointlist: mylist = list() # point = ogr.Geometry(ogr.wkbPoint) # point.AddPoint(feat[0],feat[1]) # point.ExportToWkb() # for poly in polylist: #if poly.Contains(point): for band in range(1, 4): rb = srcImage.GetRasterBand(band) geom = feat # print geom if geom != None: mx, my = geom[0], geom[1] # print mx,my ulX, ulY = world2Pixel(geoTrans, mx, my) # print ulX, ulY while ulY < srcImage.RasterYSize: intval = rb.ReadAsArray(ulX, ulY, 1, 1) mylist.extend(intval[0]) # print feat break mylist1.append(mylist) df = pd.DataFrame(mylist1) # df = df.transpose() df.columns = ['R', 'G', 'B'] df[fn + ' RGB'] = getRGB(df, fn) df = df.drop(['R', 'G', 'B'], axis=1) return df, pointlist
def from_geopolygon(cls, geopolygon, resolution, crs=None, align=True): """ :type geopolygon: datacube.model.GeoPolygon :param resolution: (x_resolution, y_resolution) :param crs: CRS to use, if different from the geopolygon :param align: Should the geobox be aligned to pixels of the given resolution. This assumes an origin of (0,0). :type align: boolean :rtype: GeoBox """ # TODO: currently only flipped Y-axis data is supported assert resolution[1] > 0 assert resolution[0] < 0 if crs is None: crs = geopolygon.crs else: geopolygon = geopolygon.to_crs(crs) bounding_box = geopolygon.boundingbox # print(bounding_box) # print("~~~") left, top = float(bounding_box.left), float(bounding_box.top) if align: left = math.floor(left / resolution[1]) * resolution[1] top = math.floor(top / resolution[0]) * resolution[0] # print(left) #print(top) #print(Affine.translation(left, top)) #print(Affine.scale(resolution[1], resolution[0])) affine = (Affine.translation(left, top) * Affine.scale(resolution[1], resolution[0])) # print(affine) right, bottom = float(bounding_box.right), float(bounding_box.bottom) width, height = ~affine * (right, bottom) # print(right) # print(width) #width = 198 #height = 288 #print(height) if align: width = math.ceil(width) height = math.ceil(height) return GeoBox(crs=crs, affine=affine, width=int(width), height=int(height))
def transform(window, transform): """Construct an affine transform matrix relative to a window. Parameters ---------- window : a Window or window tuple The input window. transform: Affine an affine transform matrix. Returns ------- Affine The affine transform matrix for the given window """ (r, _), (c, _) = window return transform * Affine.translation(c or 0, r or 0)
def compute_transform(tiepoints, affine=False): """ Takes an array of (old, new) position tuples and returns a translation matrix between the two configurations. """ arr = lambda x: N.array([N.asarray(i) for i in x]) old, new = (arr(i) for i in zip(*tiepoints)) if affine: # Currently not working old_ = add_ones(old) trans_matrix, residuals = N.linalg.lstsq(old_,new)[:2] return Affine(*trans_matrix.transpose().flatten()) else: offsets = N.mean(new-old,axis=0) return Affine.translation(*offsets)
def extract_area(geom, dem, **kwargs): # RasterIO's image-reading algorithm uses the location # of polygon centers to determine the extent of polygons msk = geometry_mask( (mapping(geom),), dem.shape, dem.transform, invert=True) # shrink mask to the minimal area for efficient extraction offset, msk = offset_mask(msk) window = tuple((o,o+s) for o,s in zip(offset,msk.shape)) # Currently just for a single band # We could generalize to multiple # bands if desired z = dem.read(1, window=window, masked=True) # mask out unused area z[msk == False] = N.ma.masked # Make vectors of rows and columns rows, cols = (N.arange(first,last,1) for first,last in window) # 2d arrays of x,y,z z = z.flatten() xyz = [i.flatten() for i in N.meshgrid(cols,rows)] + [z] x,y,z = tuple(i[z.mask == False] for i in xyz) # Transform into 3xn matrix of # flattened coordinate values coords = N.vstack((x,y,N.ones(z.shape))) # Get affine transform for pixel centers affine = dem.transform * Affine.translation(0.5, 0.5) # Transform coordinates to DEM's reference _ = N.array(affine).reshape((3,3)) coords = N.dot(_,coords) coords[2] = z return coords.transpose()
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_band( 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 setup_geo(): raster = Raster(paths.mask) mask_arr = raster.as_bool_array # get raster to provide geo data (need one that is not "Byte") root = paths.initial_inputs name = tiff_list(root)[0] raster = Raster(name, root=root) geo = raster.geo startc, endc, startr, endr = bounding_box(mask_arr) geo['rows'] = endr - startr geo['cols'] = endc - startc transform = get_tiff_transform(paths.mask) transform *= Affine.translation(startc, startr) geo['geotransform'] = transform.to_gdal() return geo, (startc, endc, startr, endr)