class GeoRasterCropTest(TestCase): metric_affine = Affine(1, 0.0, 2653750, 0.0, -1, 4594461) metric_crs = CRS({'init': 'epsg:3857'}) geographic_affine = Affine(8.03258139076081e-06, 0.0, 23.83904185232179, 0.0, -8.03258139076081e-06, 38.10635414334363) geographic_crs = CRS({'init': 'epsg:4326'}) def metric_raster(cls): return GeoRaster2(np.random.uniform(0, 256, (3, 3911, 3708)), affine=cls.metric_affine, crs=cls.metric_crs) def geographic_raster(cls): return GeoRaster2(np.random.uniform(0, 256, (3, 4147, 4147)), affine=cls.geographic_affine, crs=cls.geographic_crs) def test_crop_in_memory_and_off_memory_without_resizing_are_the_same(self): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster2 = GeoRaster2.open(rf.name) off_memory_crop = raster2.crop(shape) # load the image data raster2.image in_memory_crop = raster2.crop(shape) self.assertEqual(off_memory_crop, in_memory_crop) @window_data def test_crop_and_get_tile_do_the_same(self): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster2 = GeoRaster2.open(rf.name) tile15 = raster2.get_tile(*tiles[15]) # load the image data raster2.image cropped15 = raster2.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) self.assertEqual(tile15, cropped15) @window_data def test_crop_and_get_tile_do_the_same_when_image_is_populated(self): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster = GeoRaster2.open(rf.name) tile15 = raster.get_tile(*tiles[15]) raster._populate_from_rasterio_object(read_image=True) cropped_15 = raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) self.assertEqual(tile15, cropped_15) @window_data def test_crop_image_from_and_get_win_do_the_same_with_resize(self): bounds = (2, 3, 4, 5) win = rasterio.windows.Window(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]) xsize = round((bounds[2] - bounds[0]) / 2) ysize = round((bounds[3] - bounds[1]) / 2) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster.save('area.tif', tags={'AREA_OR_POINT': 'Area'}) raster.save('point.tif', tags={'AREA_OR_POINT': 'Point'}) saved_raster = GeoRaster2.open(rf.name) cropped_win = saved_raster.get_window(win, xsize=xsize, ysize=ysize) saved_raster_area = GeoRaster2.open('area.tif') cropped_win_area = saved_raster_area.get_window(win, xsize=xsize, ysize=ysize) saved_raster_point = GeoRaster2.open('point.tif') cropped_win_point = saved_raster_point.get_window(win, xsize=xsize, ysize=ysize) cropped_image = raster._crop(bounds, xsize=xsize, ysize=ysize) print('cropped_win_area pixels\n', cropped_win_area.image) print('cropped_win_point pixels\n', cropped_win_point.image) print('cropped_win pixels\n', cropped_win.image) print('cropped_image pixels\n', cropped_image.image) if (cropped_win_point == cropped_win_area): print('point == area') if (cropped_image == cropped_win_area): print('image == area') if (cropped_image == cropped_win_point): print('image == point') if (cropped_win == cropped_win_area): print('win == area') if (cropped_win == cropped_win_point): print('win == point') self.assertEqual(cropped_image, cropped_win) @framing def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_high_zoom( self): coords = mercantile.xy_bounds(*tiles[17]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster = GeoRaster2.open(rf.name) raster._populate_from_rasterio_object(read_image=True) tile17 = raster.get_tile(*tiles[17]) cropped_17 = raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[17]) self.assertEqual(tile17, cropped_17) @framing def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_mid_zoom( self): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster = GeoRaster2.open(rf.name) raster._populate_from_rasterio_object(read_image=True) tile15 = raster.get_tile(*tiles[15]) cropped_15 = raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) self.assertEqual(tile15, cropped_15) @framing def test_crop_and_get_tile_do_the_same_when_image_is_populated_first_for_low_zoom( self): coords = mercantile.xy_bounds(*tiles[11]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster = GeoRaster2.open(rf.name) raster._populate_from_rasterio_object(read_image=True) tile11 = raster.get_tile(*tiles[11]) cropped_11 = raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[11]) self.assertEqual(tile11, cropped_11) def test_crop_image_from_and_get_win_do_the_same_full_resolution(self): bounds = (200, 130, 400, 150) win = rasterio.windows.Window(bounds[0], bounds[1], bounds[2] - bounds[0], bounds[3] - bounds[1]) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) saved_raster = GeoRaster2.open(rf.name) cropped_win = saved_raster.get_window(win) cropped_image = raster._crop(bounds) self.assertEqual(cropped_image, cropped_win) @patch.object(GeoRaster2, '_crop') def test_crop_use_crop_image_for_a_loaded_image(self, mock__crop): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) assert mock__crop.called_once @patch.object(GeoRaster2, 'get_window') def test_crop_use_get_window_for_a_not_loaded_image(self, mock_get_window): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() with NamedTemporaryFile(mode='w+b', suffix=".tif") as rf: raster.save(rf.name) raster = GeoRaster2.open(rf.name) raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) assert mock_get_window.called_once def test_crop_returns_full_resolution_as_default(self): coords = mercantile.xy_bounds(*tiles[17]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() _, win = raster._vector_to_raster_bounds(shape) cropped = raster.crop(shape) self.assertEqual( cropped.shape, (raster.num_bands, round(win.height), round(win.width))) self.assertEqual(cropped.affine[0], raster.affine[0]) def test_memory_crop_returns_resized_resolution(self): coords = mercantile.xy_bounds(*tiles[15]) shape = GeoVector(Polygon.from_bounds(*coords), WEB_MERCATOR_CRS) raster = self.metric_raster() cropped = raster.crop(shape, MERCATOR_RESOLUTION_MAPPING[15]) self.assertEqual(cropped.shape, (raster.num_bands, 256, 256)) self.assertAlmostEqual(cropped.affine[0], MERCATOR_RESOLUTION_MAPPING[15], 2) def test_geographic_crop(self): raster = self.geographic_raster() rhombus_on_image = Polygon([[0, 2], [1, 1], [2, 2], [1, 3]]) # in pixels rhombus_world = raster.to_world(rhombus_on_image) cropped = raster.crop(rhombus_world) r = raster[0:2, 1:3] assert cropped == r def test_geographic_crop_with_resize(self): coords = mercantile.xy_bounds(*tiles[17]) raster = self.geographic_raster() vector = GeoVector(Polygon.from_bounds(*coords), crs=self.metric_crs) x_ex_res, y_ex_res = convert_resolution_from_meters_to_deg( self.metric_affine[6], MERCATOR_RESOLUTION_MAPPING[17]) cropped = raster.crop(vector, (x_ex_res, y_ex_res)) self.assertAlmostEqual(cropped.affine[0], x_ex_res) self.assertAlmostEqual(abs(cropped.affine[4]), y_ex_res, 6) def test_crop_raises_error_for_impossible_transformation(self): raster = self.metric_raster() vector = GeoVector(Polygon.from_bounds(-180, -90, 180, 90), crs=self.geographic_crs) with self.assertRaises(GeoRaster2Error): raster.crop(vector) def test_crop_of_rasters_with_opposite_affine_and_data_return_the_same( self): array = np.arange(0, 20).reshape(1, 4, 5) array2 = np.arange(19, -1, -1).reshape(1, 4, 5) array2.sort() image1 = np.ma.array(array, mask=False) image2 = np.ma.array(array2, mask=False) aff2 = Affine.translation(0, -8) * Affine.scale(2, 2) aff = Affine.scale(2, -2) r1 = GeoRaster2(image=image1, affine=aff, crs=WEB_MERCATOR_CRS) r2 = GeoRaster2(image=image2, affine=aff2, crs=WEB_MERCATOR_CRS) # r1 == r2 # doesn't work, see https://github.com/satellogic/telluric/issues/79 roi = GeoVector(Polygon.from_bounds(0, 0, 3, -3), crs=WEB_MERCATOR_CRS) r1c = r1.crop(roi) r2c = r2.crop(roi) # r1c == r2c # doesn't work, see https://github.com/satellogic/telluric/issues/79 # currently this is the only way to test the result is the same assert r2c.to_png() == r1c.to_png()
def test_empty_crs_str(): """str(CRS()) should be empty string""" assert str(CRS()) == ''
def test_crs_constructor_keywords(): """Can create a CRS from keyword args, ignoring unknowns""" crs = CRS(init='epsg:3857', foo='bar') assert crs['init'] == 'epsg:3857' assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
def test_crs_OSR_equivalence(): crs1 = CRS.from_string('+proj=longlat +datum=WGS84 +no_defs') crs2 = CRS.from_string('+proj=latlong +datum=WGS84 +no_defs') crs3 = CRS({'init': 'epsg:4326'}) assert crs1 == crs2 assert crs1 == crs3
def test_environ_patch(gdalenv, monkeypatch): """PROJ_LIB is patched when rasterio._crs is imported""" monkeypatch.delenv('GDAL_DATA', raising=False) monkeypatch.delenv('PROJ_LIB', raising=False) with env_ctx_if_needed(): assert CRS.from_epsg(4326) != CRS(units='m', proj='aeqd', ellps='WGS84', datum='WGS84', lat_0=-17.0, lon_0=-44.0)
def test_repr(): assert repr(CRS({'init': 'epsg:4326'})).startswith("CRS.from_epsg(4326)")
def test_epsg_code_true(): assert CRS({'init': 'epsg:4326'}).is_epsg_code
def test_is_valid_false(): with pytest.raises(CRSError): CRS(init='EPSG:432600').is_valid
def test_is_valid(): assert CRS(init='EPSG:4326').is_valid
import pandas as pd import rasterio from rasterio.crs import CRS from rasterio.features import rasterize, shapes from rasterio.transform import from_origin from rasterio.warp import Resampling, reproject, transform_geom from scipy.ndimage import binary_closing, uniform_filter from shapely.geometry import Polygon, shape from skimage.morphology import label from sklearn.metrics import (f1_score, precision_score, recall_score, roc_auc_score) from config import DATA_DIR, DB_NAME, DB_USER, DB_PASS, DB_HOST, YEARS from maupp import CaseStudy, osm, reference, srtm WGS84 = CRS(init='EPSG:4326') def available(case_study): """List available results for a given case study.""" years_available = [] filenames = [] for year in YEARS: path = os.path.join(case_study.outputdir, str(year), 'probabilities.tif') if os.path.isfile(path): years_available.append(year) filenames.append(path) return filenames, years_available
def test_to_string(): assert CRS({'init': 'EPSG:4326'}).to_string() == "+init=EPSG:4326"
def project_coords(x, y, src_crs, dst_crs, return_as='1d', **kwargs): """ Projects coordinates to a new CRS Args: x (1d array-like): The x coordinates. y (1d array-like): The y coordinates. src_crs (str, dict, object): The source CRS. dst_crs (str, dict, object): The destination CRS. return_as (Optional[str]): How to return the coordinates. Choices are ['1d', '2d']. kwargs (Optional[dict]): Keyword arguments passed to ``rasterio.warp.reproject``. Returns: ``numpy.array``, ``numpy.array`` or ``xr.DataArray`` """ if return_as == '1d': df_tmp = gpd.GeoDataFrame(np.arange(0, x.shape[0]), geometry=gpd.points_from_xy(x, y), crs=src_crs) df_tmp = df_tmp.to_crs(dst_crs) return df_tmp.geometry.x.values, df_tmp.geometry.y.values else: if not isinstance(x, np.ndarray): x = np.array(x, dtype='float64') if not isinstance(y, np.ndarray): y = np.array(y, dtype='float64') yy = np.meshgrid(x, y)[1] latitudes = np.zeros(yy.shape, dtype='float64') src_transform = from_bounds(x[0], y[-1], x[-1], y[0], latitudes.shape[1], latitudes.shape[0]) west, south, east, north = transform_bounds(src_crs, CRS(dst_crs), x[0], y[-1], x[-1], y[0]) dst_transform = from_bounds(west, south, east, north, latitudes.shape[1], latitudes.shape[0]) latitudes = reproject(yy, destination=latitudes, src_transform=src_transform, dst_transform=dst_transform, src_crs=CRS.from_epsg(src_crs.split(':')[1]), dst_crs=CRS(dst_crs), **kwargs)[0] return xr.DataArray(data=da.from_array(latitudes[np.newaxis, :, :], chunks=(1, 512, 512)), dims=('band', 'y', 'x'), coords={ 'band': ['lat'], 'y': ('y', latitudes[:, 0]), 'x': ('x', np.arange(1, latitudes.shape[1] + 1)) })
import os import rasterio from rasterio.crs import CRS assert "GDAL_DATA" not in os.environ azeq_point = CRS({ "units": "m", "proj": "aeqd", "ellps": "WGS84", "datum": "WGS84", "lat_0": -17.0, "lon_0": -44.0, }) with rasterio.Env(): assert azeq_point == azeq_point wgs84 = CRS.from_epsg(4326) assert not azeq_point == wgs84 assert azeq_point == azeq_point wgs84 = CRS.from_epsg(4326) assert not azeq_point == wgs84 # Cached
def main(): parser = argparse.ArgumentParser() add_local_args(parser) args = parser.parse_args() # TODO we can probably get rid of this first = rasterio.open(args.inputs[0]) sources = [] for fname in args.inputs: sources.append(Dataset(fname)) lat, lng = [], [] for src in sources: lng.extend(src.variables['longitude'][:].tolist()) lat.extend(src.variables['latitude'][:].tolist()) lng = list(sorted(set(lng))) lat = list(sorted(set(lat))) dst_w, dst_s, dst_e, dst_n = min(lng), min(lat), max(lng), max(lat) # TODO is this safe? # creating a set from floats seems dangerous output_width = len(lng) output_height = len(lat) # frequent off-by-one errors #output_width = int(math.ceil((dst_e - dst_w) / first.res[0])+1) #output_height = int(math.ceil((dst_n - dst_s) / first.res[1])+1) log.debug("Output bounds: %r", (dst_w, dst_s, dst_e, dst_n)) output_transform = Affine.translation(dst_w, dst_n) log.debug("Output transform, before scaling: %r", output_transform) output_transform *= Affine.scale(first.res[0], -first.res[1]) # TODO the following line is close. check parameter order #output_transform *= Affine.scale(lat[1]-lat[0], lng[1]-lng[0]) log.debug("Output transform, after scaling: %r", output_transform) # Seems close #output_width = int(math.ceil((dst_e - dst_w) / first.res[0])+1) #output_height = int(math.ceil((dst_n - dst_s) / first.res[1])+1) # Adjust bounds to fit. dst_e, dst_s = output_transform * (output_width, output_height) log.debug("Output width: %d, height: %d", output_width, output_height) log.debug("Adjusted bounds: %r", (dst_w, dst_s, dst_e, dst_n)) profile = first.profile profile['driver'] = 'GTiff' profile['transform'] = output_transform profile['height'] = output_height profile['width'] = output_width profile['crs'] = CRS().from_string(sources[0].crs) profile['nodata'] = first.nodata band = np.zeros((profile['height'], profile['width']), dtype=first.dtypes[0]) if not args.separate: with rasterio.open(args.output, 'w', **profile) as dstrast: for i in range(dstrast.count): if not args.quiet and i % 10 == 0: sys.stderr.write('.') for src in sources: b = src.variables[args.varname][i, :, :] off_y = src.variables['latitude'][:].max() off_x = src.variables['longitude'][:].min() rowcol = dstrast.index(off_x, off_y) row, col = int(rowcol[0]), int(rowcol[1]) log.debug('upper-left: lat=%3.6f (%d), long=%3.6f (%d)', off_y, row, off_x, col) band[row:row + b.shape[0], col:col + b.shape[1]] = b dstrast.write(band, i + 1) if args.separate: timedim = sources[0].variables[args.timedim] #nodata=sources[0].variables[args.varname].missing_value) profile.update(count=1, blockxsize=256, blockysize=256, tiled='yes') del profile['crs'] for i in range(len(timedim)): if not args.quiet and i % 10 == 0: sys.stderr.write('.') filename, ext = os.path.splitext(args.output) output = '%s_%04d%s' % (filename, int(timedim[i]), ext) with rasterio.open(output, 'w', **profile) as dstrast: for src in sources: b = src.variables[args.varname][i, :, :] off_y = src.variables['latitude'][:].max() off_x = src.variables['longitude'][:].min() rowcol = dstrast.index(off_x, off_y) row, col = int(rowcol[0]), int(rowcol[1]) log.debug('upper-left: lat=%3.6f (%d), long=%3.6f (%d)', off_y, row, off_x, col) band[row:row + b.shape[0], col:col + b.shape[1]] = b dstrast.write(band, 1) sys.stderr.write('done\n')
def test_is_valid(): assert CRS(init='epsg:4326').is_valid
def test_repr(): assert repr(CRS({'init': 'EPSG:4326'})).startswith("CRS({'init'")
def test_has_wkt_property(): assert CRS({'init': 'epsg:4326'}).wkt.startswith('GEOGCS["WGS 84",DATUM')
def test_epsg_code(): assert CRS({'init': 'EPSG:4326'}).is_epsg_code assert not CRS({'proj': 'latlon'}).is_epsg_code
def test_dunder_str(): assert str(CRS({'init': 'epsg:4326'})) == CRS({'init': 'epsg:4326'}).to_string()
def test_is_geographic(proj, expected): assert CRS(proj).is_geographic is expected
def test_epsg(): assert CRS({'init': 'epsg:4326'}).to_epsg() == 4326 assert CRS.from_string('+proj=longlat +datum=WGS84 +no_defs').to_epsg() == 4326
def test_null_crs_equality(): assert CRS() == CRS() a = CRS() assert a == a assert not a != a
def test_to_esri_wkt_fix_datum(): """Morph to Esri form""" assert 'DATUM["D_North_American_1983"' in CRS(init='epsg:26913').to_wkt(morph_to_esri_dialect=True)
def test_null_and_valid_crs_equality(): assert (CRS() == CRS(init='epsg:4326')) is False
def test_capitalized_epsg_init(): """Ensure that old behavior is preserved""" assert CRS(init='EPSG:4326').to_epsg() == 4326
def test_to_string(): assert CRS({'init': 'epsg:4326'}).to_string() == "EPSG:4326"
def test_crs_constructor_dict(): """Can create a CRS from a dict""" crs = CRS({'init': 'epsg:3857'}) assert crs['init'] == 'epsg:3857' assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
def test_is_valid_false(): with Env(), pytest.raises(CRSError): CRS(init='epsg:432600').is_valid
def test_crs_constructor_crs_obj(): """Can create a CRS from a CRS obj""" crs = CRS(CRS(init='epsg:3857')) assert crs['init'] == 'epsg:3857' assert 'PROJCS["WGS 84 / Pseudo-Mercator"' in crs.wkt
def test_geo_bounding_tile(self): gr = self.raster_for_test() gv = gr.footprint().reproject(CRS({'init': 'epsg:4326'})) bounding_tile = mercantile.bounding_tile(*gv.get_shape(gv.crs).bounds) self.assertEqual(bounding_tile, (2319, 1578, 12))