def test_gdal_tile_untile(self): img = np.arange(0., 100.).reshape((10, 10)) path = os.path.join(os.getcwd(), "test_gdal_retile.tif") tile_folder = os.path.join(os.getcwd(), "tiled") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) # Add parasitic file - It should not cause problems path_parasite = os.path.join(tile_folder, "tile_01_01.tif") FileSystem.create_directory(tile_folder) ImageIO.write_geotiff(img, path_parasite, self.projection, self.coordinates) ds_in = GDalDatasetWrapper.from_file(path) self.assertTrue(os.path.exists(path)) tiles = ImageTools.gdal_retile(ds_in, tile_folder, TileWidth=2, TileHeight=2, Overlap=1) self.assertTrue(os.path.isdir(tile_folder)) self.assertEqual(len(tiles), 81) img_read = np.array(ImageIO.tiff_to_array(tiles[-1])) expected = np.array([[88, 89], [98, 99]]) # Some gdal_retile versions are producing the following image: # [[87, 89], [97, 99]]. np.testing.assert_allclose(expected, img_read, atol=1) # Untile ds_untiled = ImageTools.gdal_buildvrt(*tiles) np.testing.assert_allclose(img, ds_untiled.array, atol=1) FileSystem.remove_file(path) FileSystem.remove_directory(tile_folder)
def test_write_read_geotiff_kwoptions(self): img = np.ones((self.height, self.width), np.int16) nodata = 42 path = os.path.join(os.getcwd(), "test_write_read_geotiff.tif") ImageIO.gdal_write("GTiff", img, path, self.projection, self.coordinates, options=["COMPRESS=DEFLATE"], nodata=nodata) self.assertTrue(os.path.exists(path)) arr, ds = ImageIO.tiff_to_array(path, array_only=False) self.assertTrue((arr == img).all()) self.assertEqual( nodata, gdal.Info(ds, format="json")["bands"][0]["noDataValue"]) self.assertEqual( gdal.Info( ds, format="json")["metadata"]["IMAGE_STRUCTURE"]["COMPRESSION"], "DEFLATE") self.assertEqual(ds.GetGeoTransform(), self.coordinates) # Compare projections by removing all spaces cause of multiline string self.assertEqual(ds.GetProjection().replace(" ", ""), self.projection.replace(" ", "")) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_get_s2_epsg_code(self): epsg_ref = 32631 projection = 'PROJCS["WGS 84 / UTM zone 31N",\ GEOGCS["WGS 84",DATUM["WGS_1984",\ SPHEROID["WGS 84",6378137,298.257223563,\ AUTHORITY["EPSG","7030"]],\ AUTHORITY["EPSG","6326"]],\ PRIMEM["Greenwich",0,\ AUTHORITY["EPSG","8901"]],\ UNIT["degree",0.0174532925199433,\ AUTHORITY["EPSG","9122"]],\ AUTHORITY["EPSG","4326"]],\ PROJECTION["Transverse_Mercator"],\ PARAMETER["latitude_of_origin",0],\ PARAMETER["central_meridian",3],\ PARAMETER["scale_factor",0.9996],\ PARAMETER["false_easting",500000],\ PARAMETER["false_northing",0],\ UNIT["metre",1,AUTHORITY["EPSG","9001"]],\ AXIS["Easting",EAST],AXIS["Northing",NORTH],\ AUTHORITY["EPSG","%s"]]' % epsg_ref img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_epsg.tif") ImageIO.write_geotiff(img, path, projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) epsg_new = ds.epsg self.assertEqual(epsg_new, epsg_ref) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_override_array(self): img = np.ones((self.height, self.width), np.int16) img_new = np.array(np.arange(0, 40200).reshape(201, 200), dtype=np.uint8) path = os.path.join(os.getcwd(), "test_write_read_geotiff.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) self.assertTrue((ds.array == img).all()) self.assertEqual(ds.geotransform, self.coordinates) self.assertEqual(ds.projection.replace(" ", ""), self.projection.replace(" ", "")) self.assertIsNone(ds.nodata_value) self.assertEqual(ds.epsg, 32631) ds_new = GDalDatasetWrapper(ds=ds.get_ds(), array=img_new, nodata_value=123) FileSystem.remove_file(path) np.testing.assert_almost_equal(img_new, ds_new.array) self.assertEqual(ds_new.geotransform, self.coordinates) self.assertEqual(ds_new.projection.replace(" ", ""), self.projection.replace(" ", "")) self.assertEqual(ds_new.nodata_value, 123) self.assertEqual(ds_new.epsg, 32631) self.assertFalse(os.path.exists(path))
def test_gdal_buildvrt_concatenate(self): from StartMaja.Common import FileSystem paths = [] for i in range(1, 3, 1): img = np.ones((i, i, 2), np.int16) * i path = os.path.join(os.getcwd(), "test_gdal_merge_%s.tif" % i) ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) paths.append(path) empty = os.path.join(os.getcwd(), "empty.vrt") driver = ImageTools.gdal_buildvrt(*paths, dst=empty, separate=True, srcnodata=0) expected = np.array([[[1, 0], [0, 0]], [[2, 2], [2, 2]]], dtype=np.int16) np.testing.assert_almost_equal(driver.array, expected) self.assertEqual(driver.nodata_value, 0) self.assertEqual(driver.epsg, 32631) [FileSystem.remove_file(path) for path in paths] FileSystem.remove_file(empty) [self.assertFalse(os.path.exists(path)) for path in paths] self.assertFalse(os.path.exists(empty))
def lonlat_minmax(self): """ Get lat and lon min and max values :return: latmin, latmax, lonmin, lonmax of the current sites """ ul_lonlat = ImageIO.transform_point(self.ul, self.epsg, new_epsg=4326) lr_lonlat = ImageIO.transform_point(self.lr, self.epsg, new_epsg=4326) return ul_lonlat, lr_lonlat
def test_get_nodata(self): expected_nodata = 42.0 img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_get_nodata_init.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) ds = ImageTools.gdal_buildvrt(path, VRTNodata=expected_nodata) self.assertEqual(expected_nodata, ds.nodata_value) np.testing.assert_almost_equal(ds.nodata_mask, np.ones_like(img)) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_get_utm_description(self): img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_get_utm_description.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) utm = ds.utm_description utm_expected = "WGS 84 / UTM zone 31N" self.assertEqual(utm_expected, utm) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_gdal_buildvrt(self): path = os.path.join(os.getcwd(), "test_gdal_buildvrt.tif") vrt = os.path.join(os.getcwd(), "test_vrt.vrt") img = np.arange(-4, 5).reshape(3, 3) / 5 ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) driver = ImageTools.gdal_buildvrt(path, dst=vrt) self.assertTrue(os.path.exists(vrt)) np.testing.assert_almost_equal(driver.array, img) FileSystem.remove_file(vrt) FileSystem.remove_file(path)
def test_get_resolution(self): img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_get_resolution.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) res_expected = (self.coordinates[1], self.coordinates[-1]) self.assertEqual(res_expected, ds.resolution) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_get_ul_lr(self): img = np.ones((1000, 1000), np.int16) path = os.path.join(os.getcwd(), "test_get_ul_lr.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) ulx, uly, lrx, lry = ds.ul_lr self.assertEqual((ulx, uly), (300000.0, 4900020.0)) self.assertEqual((lrx, lry), (310000.0, 4890020.0)) self.assertEqual(ds.extent, (300000.0, 4890020.0, 310000.0, 4900020.0)) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_write_read_geotiff(self): img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_write_read_geotiff.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) arr, ds = ImageIO.tiff_to_array(path, array_only=False) self.assertTrue((arr == img).all()) self.assertEqual(ds.GetGeoTransform(), self.coordinates) # Compare projections by removing all spaces cause of multiline string self.assertEqual(ds.GetProjection().replace(" ", ""), self.projection.replace(" ", "")) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_faulty_geotransform_projection(self): coordinates = (652594.9112913811, 10.00887639510383, 0, 5072876.717295351, 0) # Missing one value projection = '' # Empty height = 200 width = 100 img = np.ones((height, width), np.int16) path = os.path.join(os.getcwd(), "test_faulty_geotransform_projection.tif") # Check geotransform wrong: with self.assertRaises(TypeError): ImageIO.write_geotiff(img, path, projection, coordinates) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_gdal_translate(self): img = np.ones((self.height, self.width, 2), np.int16) path = os.path.join(os.getcwd(), "test_gdal_translate.tif") scaled = os.path.join(os.getcwd(), "scaled.tif") out_resolution = (20, -20) ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = ImageTools.gdal_translate(path, scaled, tr=" ".join([str(i) for i in out_resolution]), scale="0 1 0 255") self.assertEqual(ds.resolution, out_resolution) self.assertEqual(ds.array.shape, (self.height // 2, self.width // 2, 2)) np.testing.assert_almost_equal(ds.array, 255) FileSystem.remove_file(path) FileSystem.remove_file(scaled)
def get_synthetic_band(self, synthetic_band, **kwargs): wdir = kwargs.get("wdir", self.fpath) output_folder = os.path.join(wdir, self.base) output_bname = "_".join( [self.base.split(".")[0], synthetic_band.upper() + ".tif"]) output_filename = kwargs.get("output_filename", os.path.join(output_folder, output_bname)) max_value = kwargs.get("max_value", 10000.) # Skip existing: if os.path.exists(output_filename): return output_filename if synthetic_band.lower() == "ndvi": FileSystem.create_directory(output_folder) b4 = self.find_file(pattern=r"*B0?4(_10m)?.jp2$")[0] b8 = self.find_file(pattern=r"*B0?8(_10m)?.jp2$")[0] ds_red = GDalDatasetWrapper.from_file(b4) ds_nir = GDalDatasetWrapper.from_file(b8) ds_ndvi = ImageApps.get_ndvi(ds_red, ds_nir, vrange=(0, max_value), dtype=np.int16) ds_ndvi.write(output_filename, options=["COMPRESS=DEFLATE"]) elif synthetic_band.lower() == "ndsi": FileSystem.create_directory(output_folder) b3 = self.find_file(pattern=r"*B0?3(_10m)?.jp2$")[0] b11 = self.find_file(pattern=r"*B11(_20m)?.jp2$")[0] ds_green = ImageTools.gdal_translate(b3, tr="20 20", r="cubic") ds_swir = GDalDatasetWrapper.from_file(b11) ds_ndsi = ImageApps.get_ndsi(ds_green, ds_swir, vrange=(0, max_value), dtype=np.int16) ds_ndsi.write(output_filename, options=["COMPRESS=DEFLATE"]) elif synthetic_band.lower() == "mca_sim": FileSystem.create_directory(output_folder) b4 = self.find_file(pattern=r"*B0?4(_10m)?.jp2$")[0] b3 = self.find_file(pattern=r"*B0?3(_10m)?.jp2$")[0] img_red, drv = ImageIO.tiff_to_array(b4, array_only=False) img_green = ImageIO.tiff_to_array(b3) img_mcasim = (img_red + img_green) / 2 ImageIO.write_geotiff_existing(img_mcasim, output_filename, drv, options=["COMPRESS=DEFLATE"]) else: raise ValueError("Unknown synthetic band %s" % synthetic_band) return output_filename
def test_transform_point_lat_lon(self): center = (653095.355, 5071879.228) lon_lat_expected = (4.9694934619557145, 45.78349724618419) lon_lat_calc = ImageIO.transform_point(center, old_epsg=32631, new_epsg=4326) np.testing.assert_almost_equal(lon_lat_calc, lon_lat_expected)
def test_write_read_geotiff(self): img = np.ones((self.height, self.width), np.int16) path = os.path.join(os.getcwd(), "test_write_read_geotiff.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = GDalDatasetWrapper.from_file(path) self.assertTrue((ds.array == img).all()) self.assertEqual(ds.geotransform, self.coordinates) # Compare projections by removing all spaces cause of multiline string self.assertEqual(ds.projection.replace(" ", ""), self.projection.replace(" ", "")) self.assertIsNone(ds.nodata_value) self.assertEqual(ds.epsg, 32631) FileSystem.remove_file(path) self.assertFalse(os.path.exists(path))
def test_gdal_warp(self): img = np.ones((self.height, self.width, 2), np.int16) img_rescaled = np.ones((int(self.height/2), int(self.width/2), 2), np.int16) out_resolution = (20, -20) path = os.path.join(os.getcwd(), "test_gdal_warp.tif") scaled = os.path.join(os.getcwd(), "res_changed.tif") ImageIO.write_geotiff(img, path, self.projection, self.coordinates) self.assertTrue(os.path.exists(path)) ds = ImageTools.gdal_warp(path, scaled, tr=" ".join(str(e) for e in out_resolution), r="max", q=True) self.assertTrue(os.path.isfile(scaled)) self.assertEqual(ds.resolution, out_resolution) self.assertEqual(ds.array.shape, (self.height // 2, self.width // 2, 2)) np.testing.assert_almost_equal(ds.array, img_rescaled) FileSystem.remove_file(path) FileSystem.remove_file(scaled)
def test_merge_then_translate(self): datasets = [] init = np.zeros((2, 2), np.int16) path = os.path.join(os.getcwd(), "test_gdal_merge.tif") ImageIO.write_geotiff(init, path, self.projection, self.coordinates) ds_in = GDalDatasetWrapper.from_file(path) for i in range(1, 3, 1): img = np.ones((i*2, i*2), np.int16) * i ds_n = GDalDatasetWrapper(ds=ds_in.get_ds(), array=img) self.assertTrue(os.path.exists(path)) datasets.append(ds_n) ds_merged = ImageTools.gdal_merge(*datasets, dst="out.tif", separate=True, q=True, a_nodata=0) # Array of shape (4, 4, 2): expected = np.array([[[1, 2], [1, 2], [0, 2], [0, 2]], [[1, 2], [1, 2], [0, 2], [0, 2]], [[0, 2], [0, 2], [0, 2], [0, 2]], [[0, 2], [0, 2], [0, 2], [0, 2]]], dtype=np.int16) FileSystem.remove_file("out.tif") np.testing.assert_equal(expected.dtype, ds_merged.array.dtype) np.testing.assert_almost_equal(expected, ds_merged.array) self.assertEqual(ds_merged.nodata_value, 0) self.assertEqual(ds_merged.epsg, 32631) ds_translate = ImageTools.gdal_translate(ds_merged, a_nodata=0) FileSystem.remove_file(path) np.testing.assert_equal(expected.dtype, ds_translate.array.dtype) np.testing.assert_almost_equal(ds_translate.array, expected) self.assertEqual(ds_translate.nodata_value, 0) self.assertEqual(ds_translate.epsg, 32631)
def from_file(cls, p_in): """ Create a :class:`GDalDatasetWrapper` from a file :param p_in: The path to the geo-referenced file :return: A GDalDatasetWrapper object """ ds = ImageIO.open_tiff(p_in) return cls(ds=ds, p_in=p_in)
def test_gdal_merge_optfile(self): datasets, written = [], [] init = np.zeros((2, 2), np.int16) path = os.path.join(os.getcwd(), "test_gdal_merge_optfile.tif") ImageIO.write_geotiff(init, path, self.projection, self.coordinates) ds_in = GDalDatasetWrapper.from_file(path) for i in range(1, 3, 1): img = np.ones((i*2, i*2), np.int16) * i ds_n = GDalDatasetWrapper(ds=ds_in.get_ds(), array=img) p_out = "test_gdal_merge_optfile_%s.tif" % i ImageIO.write_geotiff_existing(img, p_out, ds_in.get_ds()) self.assertTrue(os.path.exists(path)) datasets.append(ds_n) written.append(p_out) optfile = "test_gdal_merge_optfile.txt" with open(optfile, 'w') as file_handler: for item in written: file_handler.write("{}\n".format(item)) ds_merged = ImageTools.gdal_merge(*datasets, q=True, a_nodata=0) ds_optfile = ImageTools.gdal_merge(optfile=optfile, q=True, a_nodata=0) # Array of shape (4, 4): expected = np.array([[2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2]], dtype=np.int16) FileSystem.remove_file(path) [FileSystem.remove_file(p) for p in written] FileSystem.remove_file(optfile) np.testing.assert_equal(expected.dtype, ds_merged.array.dtype) np.testing.assert_almost_equal(expected, ds_merged.array) self.assertEqual(ds_merged.nodata_value, 0) self.assertEqual(ds_merged.epsg, 32631) np.testing.assert_equal(expected.dtype, ds_optfile.array.dtype) np.testing.assert_almost_equal(expected, ds_optfile.array) self.assertEqual(ds_optfile.nodata_value, 0) self.assertEqual(ds_optfile.epsg, 32631)
def get_eudem_codes(site): """ Get the list of EuDEM files for a given site. :return: The list of filenames needed in order to cover to whole site. """ grid_step = 10 from StartMaja.Common import ImageIO ur_etrs89 = ImageIO.transform_point( (site.lr_lonlat[0], site.ul_lonlat[1]), old_epsg=4326, new_epsg=3035) ll_etrs89 = ImageIO.transform_point( (site.ul_lonlat[0], site.lr_lonlat[1]), old_epsg=4326, new_epsg=3035) def myfloor(val, base=grid_step): return base * math.floor(val / base) lon_min = myfloor(ll_etrs89[0] / 100000) lon_max = myfloor(ur_etrs89[0] / 100000) lat_min = myfloor(ll_etrs89[1] / 100000) lat_max = myfloor(ur_etrs89[1] / 100000) lat_codes = list(range(lat_min, lat_max + grid_step, grid_step)) lon_codes = list(range(lon_min, lon_max + grid_step, grid_step)) eudem_granules = [] for x in lon_codes: for y in lat_codes: code_lat = "S" if y < 0 else "N" code_lon = "W" if x < 0 else "E" eudem_code = "eu_dem_v11_%s%s%s%s" % (code_lon, x, code_lat, y) if eudem_code not in eudem_archives: raise ValueError( "Cannot process this product with EuDEM." "(Partially) out of region:" "%s -> [%s, %s]" % (eudem_code, site.lr_lonlat, site.ul_lonlat)) eudem_granules.append(eudem_code) return eudem_granules
def test_write_read_memory(self): img = np.ones((self.height, self.width), np.int16) path = "/vsimem/test_write_read_memory.tif" ds = ImageIO.write_to_memory(img, path, self.projection, self.coordinates) arr = ds.ReadAsArray() self.assertTrue((arr == img).all()) self.assertEqual(ds.GetGeoTransform(), self.coordinates) # Compare projections by removing all spaces cause of multiline string self.assertEqual(ds.GetProjection().replace(" ", ""), self.projection.replace(" ", "")) ds = None # Always remember to dereference :) FileSystem.remove_file(path)
def get_ds(self): """ Return a new copy of a :class:`gdal.Dataset`. :return: A gdal dataset object """ p_out = "/vsimem/" + uuid.uuid4().hex try: nodata = self.nodata_value except AttributeError: nodata = None return ImageIO.write_to_memory(self.array, p_out, self.projection, self.geotransform, nodata=nodata)
def write(self, p_out, **kwargs): """ Write the array to a given location :param p_out: Location to write to, overrides internal `self._p_out` parameter :keyword kwargs: Optional gdal keyword arguments. :return: Writes array to given location """ nodata = kwargs.pop("nodata", self.nodata_value) driver = kwargs.pop("driver", "GTiff") return ImageIO.gdal_write(driver, self.array, p_out, self.projection, self.geotransform, nodata=nodata, **kwargs)
def s2_epsg_code(self): """ Get the Sentinel-2 EPSG Code for the current dataset The codes range from 32601..60 and 32701..60 :return: The EPSG-Code as int. E.g. '32630' :rtype: int """ ul, lr = self.ul_lr epsg_old = self.epsg if epsg_old != 4326: lon, lat = ImageIO.transform_point(ul, epsg_old) else: lat, lon = ul lon_mod = int(lon / 6) lon_code = str(30 + lon_mod if lon < 0 else 31 - lon_mod).zfill(2) epsg = "327" if lat < 0 else "326" return int(epsg + lon_code)