def test_read_with_reproject(tmpdir): from datacube.testutils import mk_test_image from datacube.testutils.io import write_gtiff from pathlib import Path pp = Path(str(tmpdir)) xx = mk_test_image(128, 64, nodata=None) assert (xx != -999).all() tile = AlbersGS.tile_geobox((17, -40))[:64, :128] mm = write_gtiff(pp / 'tst-read-with-reproject-128x64-int16.tif', xx, crs=str(tile.crs), resolution=tile.resolution[::-1], offset=tile.transform * (0, 0), nodata=-999) assert mm.gbox == tile def _read(gbox, resampling='nearest', fallback_nodata=None, dst_nodata=-999): with RasterFileDataSource(mm.path, 1, nodata=fallback_nodata).open() as rdr: yy = np.full(gbox.shape, dst_nodata, dtype=rdr.dtype) roi = read_time_slice(rdr, yy, gbox, resampling, dst_nodata) return yy, roi gbox = gbx.pad(mm.gbox, 10) gbox = gbx.zoom_out(gbox, 0.873) yy, roi = _read(gbox) assert roi[0].start > 0 and roi[1].start > 0 assert (yy[0] == -999).all() yy_expect, _ = rio_slurp(mm.path, gbox) np.testing.assert_array_equal(yy, yy_expect) gbox = gbx.zoom_out(mm.gbox[3:-3, 10:-10], 2.1) yy, roi = _read(gbox) assert roi_shape(roi) == gbox.shape assert not (yy == -999).any() gbox = GeoBox.from_geopolygon(mm.gbox.extent.to_crs(epsg3857).buffer(50), resolution=mm.gbox.resolution) assert gbox.extent.contains(mm.gbox.extent.to_crs(epsg3857)) assert gbox.crs != mm.gbox.crs yy, roi = _read(gbox) assert roi[0].start > 0 and roi[1].start > 0 assert (yy[0] == -999).all() gbox = gbx.zoom_out(gbox, 4) yy, roi = _read(gbox, resampling='average') nvalid = (yy != -999).sum() nempty = (yy == -999).sum() assert nvalid > nempty
def gbox_reproject( geobox: GeoBox, crs: SomeCRS, resolution: Optional[Tuple[int, int]] = None, pad: int = 0, pad_wh: Union[int, Tuple[int, int]] = 16, ) -> GeoBox: """ Compute GeoBox in a given projection that fully encloses footprint of the source GeoBox. :param geobox: Source GeoBox :param crs: CRS of the output GeoBox :param resolution: Desired output resolution (defaults to source resolution, if source and destination projections share common units) :param pad: Padding in pixels of output GeoBox :param pad_wh: Expand output GeoBox some more such that (W%pad_wh) == 0 and (H%pad_wh) == 0 """ from datacube.utils.geometry import gbox crs = _norm_crs_or_error(crs) if resolution is None: if geobox.crs.units == crs.units: resolution = geobox.resolution else: raise NotImplementedError( "Source and destination projections have different units: have to supply desired output resolution" ) out = GeoBox.from_geopolygon(geobox.extent, resolution, crs) if pad > 0: out = gbox.pad(out, pad) if pad_wh: if isinstance(pad_wh, int): pad_wh = max(1, pad_wh) pad_wh = (pad_wh, pad_wh) out = gbox.pad_wh(out, *pad_wh) return out
def _load_with_native_transform_1( sources: xr.DataArray, bands: Tuple[str, ...], geobox: GeoBox, native_transform: Callable[[xr.Dataset], xr.Dataset], basis: Optional[str] = None, groupby: Optional[str] = None, fuser: Optional[Callable[[xr.Dataset], xr.Dataset]] = None, resampling: str = "nearest", chunks: Optional[Dict[str, int]] = None, load_chunks: Optional[Dict[str, int]] = None, pad: Optional[int] = None, ) -> xr.Dataset: if basis is None: basis = bands[0] if load_chunks is None: load_chunks = chunks (ds, ) = sources.data[0] load_geobox = compute_native_load_geobox(geobox, ds, basis) if pad is not None: load_geobox = gbox.pad(load_geobox, pad) mm = ds.type.lookup_measurements(bands) xx = Datacube.load_data(sources, load_geobox, mm, dask_chunks=load_chunks) xx = native_transform(xx) if groupby is not None: if fuser is None: fuser = _nodata_fuser # type: ignore xx = xx.groupby(groupby).map(fuser) _chunks = None if chunks is not None: _chunks = tuple(chunks.get(ax, -1) for ax in ("y", "x")) return xr_reproject(xx, geobox, chunks=_chunks, resampling=resampling) # type: ignore
def test_can_paste(): src = AlbersGS.tile_geobox((17, -40)) def check_true(dst, **kwargs): ok, reason = can_paste(compute_reproject_roi(src, dst), **kwargs) if not ok: assert ok is True, reason def check_false(dst, **kwargs): ok, reason = can_paste(compute_reproject_roi(src, dst), **kwargs) if ok: assert ok is False, "Expected can_paste to return False, but got True" check_true(gbx.pad(src, 100)) check_true(src[:10, :10]) check_true(gbx.translate_pix(src, 0.1, 0.3), ttol=0.5) check_true(gbx.translate_pix(src, 3, -4)) check_true(gbx.flipx(src)) check_true(gbx.flipy(src)) check_true(gbx.flipx(gbx.flipy(src))) check_true(gbx.zoom_out(src, 2)) check_true(gbx.zoom_out(src, 4)) check_true(gbx.zoom_out(src[:9, :9], 3)) # Check False code paths dst = GeoBox.from_geopolygon(src.extent.to_crs(epsg3857).buffer(10), resolution=src.resolution) check_false(dst) # non ST check_false(gbx.affine_transform_pix(src, Affine.rotation(1))) # non ST check_false(gbx.zoom_out(src, 1.9)) # non integer scale check_false(gbx.affine_transform_pix(src, Affine.scale(1, 2))) # sx != sy dst = gbx.translate_pix(src, -1, -1) dst = gbx.zoom_out(dst, 2) check_false(dst) # src_roi doesn't align for scale check_false(dst, stol=0.7) # src_roi/scale != dst_roi check_false(gbx.translate_pix(src, 0.3, 0.4)) # sub-pixel translation
def test_gbox_ops(): s = GeoBox(1000, 100, Affine(10, 0, 12340, 0, -10, 316770), epsg3857) assert s.shape == (100, 1000) d = gbx.flipy(s) assert d.shape == s.shape assert d.crs is s.crs assert d.resolution == (-s.resolution[0], s.resolution[1]) assert d.extent.contains(s.extent) with pytest.raises(ValueError): # flipped grid (s | d) with pytest.raises(ValueError): # flipped grid (s & d) d = gbx.flipx(s) assert d.shape == s.shape assert d.crs is s.crs assert d.resolution == (s.resolution[0], -s.resolution[1]) assert d.extent.contains(s.extent) assert gbx.flipy(gbx.flipy(s)).affine == s.affine assert gbx.flipx(gbx.flipx(s)).affine == s.affine d = gbx.zoom_out(s, 2) assert d.shape == (50, 500) assert d.crs is s.crs assert d.extent.contains(s.extent) assert d.resolution == (s.resolution[0]*2, s.resolution[1]*2) d = gbx.zoom_out(s, 2*max(s.shape)) assert d.shape == (1, 1) assert d.crs is s.crs assert d.extent.contains(s.extent) d = gbx.zoom_out(s, 1.33719) assert d.crs is s.crs assert d.extent.contains(s.extent) assert all(ds < ss for ds, ss in zip(d.shape, s.shape)) with pytest.raises(ValueError): # lower resolution grid (s | d) with pytest.raises(ValueError): # lower resolution grid (s & d) d = gbx.zoom_to(s, s.shape) assert d == s d = gbx.zoom_to(s, (1, 3)) assert d.shape == (1, 3) assert d.extent == s.extent d = gbx.zoom_to(s, (10000, 10000)) assert d.shape == (10000, 10000) assert d.extent == s.extent d = gbx.pad(s, 1) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent.contains(s.extent) assert s.extent.contains(d.extent) is False assert d[1:-1, 1:-1].affine == s.affine assert d[1:-1, 1:-1].shape == s.shape assert d == (s | d) assert s == (s & d) d = gbx.pad_wh(s, 10) assert d == s d = gbx.pad_wh(s, 100, 8) assert d.width == s.width assert d.height % 8 == 0 assert 0 < d.height - s.height < 8 assert d.affine == s.affine assert d.crs is s.crs d = gbx.pad_wh(s, 13, 17) assert d.affine == s.affine assert d.crs is s.crs assert d.height % 17 == 0 assert d.width % 13 == 0 assert 0 < d.height - s.height < 17 assert 0 < d.width - s.width < 13 d = gbx.translate_pix(s, 1, 2) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent != s.extent assert s[2:3, 1:2].extent == d[:1, :1].extent d = gbx.translate_pix(s, -10, -2) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent != s.extent assert s[:1, :1].extent == d[2:3, 10:11].extent d = gbx.translate_pix(s, 0.1, 0) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent != s.extent assert d.extent.contains(s[:, 1:].extent) d = gbx.translate_pix(s, 0, -0.5) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent != s.extent assert s.extent.contains(d[1:, :].extent) d = gbx.affine_transform_pix(s, Affine(1, 0, 0, 0, 1, 0)) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent == s.extent d = gbx.rotate(s, 180) assert d.crs is s.crs assert d.shape == s.shape assert d.extent != s.extent np.testing.assert_almost_equal(d.extent.area, s.extent.area, 1e-5) assert s[49:52, 499:502].extent.contains(d[50:51, 500:501].extent), "Check that center pixel hasn't moved"
def test_gbox_ops(): s = GeoBox(1000, 100, Affine(10, 0, 12340, 0, -10, 316770), epsg3857) assert s.shape == (100, 1000) d = gbx.flipy(s) assert d.shape == s.shape assert d.crs is s.crs assert d.resolution == (-s.resolution[0], s.resolution[1]) assert d.extent.contains(s.extent) d = gbx.flipx(s) assert d.shape == s.shape assert d.crs is s.crs assert d.resolution == (s.resolution[0], -s.resolution[1]) assert d.extent.contains(s.extent) assert gbx.flipy(gbx.flipy(s)).affine == s.affine assert gbx.flipx(gbx.flipx(s)).affine == s.affine d = gbx.zoom_out(s, 2) assert d.shape == (50, 500) assert d.crs is s.crs assert d.extent.contains(s.extent) assert d.resolution == (s.resolution[0] * 2, s.resolution[1] * 2) d = gbx.zoom_out(s, 2 * max(s.shape)) assert d.shape == (1, 1) assert d.crs is s.crs assert d.extent.contains(s.extent) d = gbx.zoom_out(s, 1.33719) assert d.crs is s.crs assert d.extent.contains(s.extent) assert all(ds < ss for ds, ss in zip(d.shape, s.shape)) d = gbx.zoom_to(s, s.shape) assert d == s d = gbx.zoom_to(s, (1, 3)) assert d.shape == (1, 3) assert d.extent == s.extent d = gbx.zoom_to(s, (10000, 10000)) assert d.shape == (10000, 10000) assert d.extent == s.extent d = gbx.pad(s, 1) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent.contains(s.extent) assert s.extent.contains(d.extent) is False assert d[1:-1, 1:-1].affine == s.affine assert d[1:-1, 1:-1].shape == s.shape d = gbx.translate_pix(s, 1, 2) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent != s.extent assert s[2:3, 1:2].extent == d[:1, :1].extent d = gbx.translate_pix(s, -10, -2) assert d.crs is s.crs assert d.resolution == s.resolution assert d.extent != s.extent assert s[:1, :1].extent == d[2:3, 10:11].extent d = gbx.translate_pix(s, 0.1, 0) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent != s.extent assert d.extent.contains(s[:, 1:].extent) d = gbx.translate_pix(s, 0, -0.5) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent != s.extent assert s.extent.contains(d[1:, :].extent) d = gbx.affine_transform_pix(s, Affine(1, 0, 0, 0, 1, 0)) assert d.crs is s.crs assert d.shape == s.shape assert d.resolution == s.resolution assert d.extent == s.extent d = gbx.affine_transform_pix(s, Affine.rotation(10)) assert d.crs is s.crs assert d.shape == s.shape assert d.extent != s.extent for deg in (33, -33, 20, 90, 180): d = gbx.rotate(s, 33) assert d.crs is s.crs assert d.shape == s.shape assert d.extent != s.extent np.testing.assert_almost_equal(d.extent.area, s.extent.area, 1e-5) assert s[49:52, 499:502].extent.contains( d[50:51, 500:501].extent), "Check that center pixel hasn't moved"