diff --git a/geoarray/baseclasses.py b/geoarray/baseclasses.py index c99d0197c51617a8b6a323804f0f871380ee8a6b..d877797d214d633b1dd75fcaf37205020406d8a6 100644 --- a/geoarray/baseclasses.py +++ b/geoarray/baseclasses.py @@ -22,7 +22,7 @@ try: except ImportError: import gdal import gdalnumeric -from geopandas import GeoDataFrame, GeoSeries +from geopandas import GeoDataFrame from pandas import DataFrame from py_tools_ds.convenience.object_oriented import alias_property from py_tools_ds.geo.coord_calc import get_corner_coordinates @@ -180,7 +180,7 @@ class GeoArray(object): def bandnames(self): self._bandnames = OrderedDict(('B%s' % band, i) for i, band in enumerate(range(1, self.bands + 1))) if self._metadata is not None: - self.metadata.loc['band_name', :] = list(self._bandnames.keys()) + self.metadata.band_meta['band_names'] = list(self._bandnames.keys()) @property def is_inmem(self): @@ -894,15 +894,21 @@ class GeoArray(object): ds_out = driver.CreateCopy(out_path, ds_inmem, options=creationOptions if creationOptions else []) del ds_inmem - # set metadata + ################ + # set metadata # + ################ + # NOTE: The dataset has to be written BEFORE metadata are added. Otherwise, metadata are not written. + + # ENVI # + ######## if fmt == 'ENVI': ds_out.SetMetadata(envi_metadict, 'ENVI') if 'band_names' in envi_metadict: for bidx in range(self.bands): band = ds_out.GetRasterBand(bidx + 1) - band.SetDescription(self.metadata.band_meta['band_names'][bidx]) + band.SetDescription(self.metadata.band_meta['band_names'][bidx].strip()) del band if 'description' in envi_metadict: @@ -926,7 +932,7 @@ class GeoArray(object): band.SetMetadata(meta2write) if 'band_names' in envi_metadict: - band.SetDescription(self.metadata.band_meta['band_names'][bidx]) + band.SetDescription(self.metadata.band_meta['band_names'][bidx].strip()) band.FlushCache() del band diff --git a/geoarray/metadata.py b/geoarray/metadata.py index 54dceb0f36061d56a3e05a34870d3a87dee72310..9a44e0341f25ea0251c81b415d03d76ce64efe0d 100644 --- a/geoarray/metadata.py +++ b/geoarray/metadata.py @@ -67,9 +67,6 @@ class GDAL_Metadata(object): @property def global_meta(self): - if not self._global_meta: - pass - return self._global_meta @global_meta.setter @@ -77,18 +74,25 @@ class GDAL_Metadata(object): if not isinstance(meta_dict, dict): raise TypeError("Expected type 'dict', received '%s'." % type(meta_dict)) - self._global_meta = meta_dict + self._global_meta = meta_dict # TODO convert strings to useful types @property def band_meta(self): - if not self._band_meta: - pass - return self._band_meta @band_meta.setter - def band_meta(self, value): - pass + def band_meta(self, meta_dict): + if not isinstance(meta_dict, dict): + raise TypeError("Expected type 'dict', received '%s'." % type(meta_dict)) + + for k, v in meta_dict.items(): + if not isinstance(v, list): + raise TypeError('The values of the given dictionary must be lists. Received %s for %s.' % (type(v), k)) + if len(v) != self.bands: + raise ValueError("The length of the given lists must be equal to the number of bands. " + "Received a list with %d items for '%s'." % (len(v), k)) + + self._band_meta = meta_dict # TODO convert strings to useful types @property def all_meta(self): @@ -118,7 +122,7 @@ class GDAL_Metadata(object): return '%f' % param_value elif isinstance(param_value, list): - return '{ ' + ', '.join([self._convert_param_to_ENVI_str(i) for i in param_value]) + ' }' + return '{ ' + ',\n'.join([self._convert_param_to_ENVI_str(i) for i in param_value]) + ' }' else: return param_value diff --git a/tests/data/subset_metadata.bsq b/tests/data/subset_metadata.bsq new file mode 100644 index 0000000000000000000000000000000000000000..6152d302f50701274774237fa944c639251a5814 Binary files /dev/null and b/tests/data/subset_metadata.bsq differ diff --git a/tests/data/subset_metadata.hdr b/tests/data/subset_metadata.hdr new file mode 100644 index 0000000000000000000000000000000000000000..2516f5a249e24f73fbf91058ae4baf50b967c977 --- /dev/null +++ b/tests/data/subset_metadata.hdr @@ -0,0 +1,40 @@ +ENVI +description = { + File Resize Result, x resize factor: 1.000000, y resize factor: 1.000000. + [Wed Aug 08 13:35:48 2018]} +samples = 5 +lines = 5 +bands = 10 +header offset = 0 +file type = ENVI Standard +data type = 2 +interleave = bsq +sensor type = Unknown +byte order = 0 +x start = 350 +y start = 10500 +map info = {UTM, 1.000, 1.000, 287232.433, 4080098.314, 1.4200000000e+001, 1.4200000000e+001, 11, North, WGS-84, units=Meters, rotation=-12.00000000} +coordinate system string = {PROJCS["UTM_Zone_11N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-117.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]} +wavelength units = Nanometers +band names = { + Resize (Band 5:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 6:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 7:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 8:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 9:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 10:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 11:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 12:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 13:f141006t01p00r16_refl_BSQ.bsq), + Resize (Band 14:f141006t01p00r16_refl_BSQ.bsq)} +wavelength = { + 404.596649, 414.278656, 423.964661, 433.654663, 443.349670, 453.049652, + 462.752655, 472.460663, 482.173645, 491.890656} +fwhm = { + 9.645100, 9.599000, 9.555200, 9.513600, 9.474300, 9.437300, 9.402500, + 9.370000, 9.339700, 9.311700} +bbl = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} +correction factors = { + 1.10059, 1.08712, 1.0534, 0.99914, 0.98411, 0.99055, 0.96899, 0.98119, + 0.9779, 0.97234} diff --git a/tests/test_metadata.py b/tests/test_metadata.py index e6bb385b731295586b1afc8615370ffa8f021a84..af7ee35cb7a13314d649d3736abbe9d1bfa01842 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -2,23 +2,56 @@ # -*- coding: utf-8 -*- from unittest import TestCase +import os +import numpy as np +import tempfile from geoarray.metadata import GDAL_Metadata from geoarray import GeoArray +import geoarray + + +tests_path = os.path.abspath(os.path.join(geoarray.__path__[0], "..", "tests")) class Test_GDAL_Metadata(TestCase): - def setUp(self): - self.test_filePath = '/home/gfz-fe/scheffler/temp/SPECHOM/ORIG_DATA/' \ - 'f130502t01p00r09_refl_master_calibration_Aviris.bsq' # FIXME - self.test_outfilePath = '/home/gfz-fe/scheffler/temp/SPECHOM_py/debugging/' \ - 'f130502t01p00r09_refl_master_calibration_Aviris_out.bsq' # FIXME + @classmethod + def setUp(cls): + cls.test_filePath = os.path.join(tests_path, 'data', 'subset_metadata.bsq') + cls.tmpOutdir = tempfile.TemporaryDirectory() + + @classmethod + def tearDownClass(cls): + cls.tmpOutdir.cleanup() def test_init(self): meta = GDAL_Metadata(self.test_filePath) self.assertIsInstance(meta, GDAL_Metadata) def test_save(self): + outPath = os.path.join(self.tmpOutdir.name, 'save_bandnames_from_file.bsq') + gA = GeoArray(self.test_filePath) gA.to_mem() - gA.save(self.test_outfilePath) + gA.bandnames = ['test_%s' % i for i in range(1, gA.bands + 1)] + gA.save(outPath) + + with open(os.path.splitext(outPath)[0] + '.hdr', 'r') as inF: + content = inF.read() + + for bN in gA.bandnames.keys(): + self.assertTrue(bN in content, msg="The band name '%s' is not in the written header." % bN) + + def test_save_bandnames(self): + outPath = os.path.join(self.tmpOutdir.name, 'save_bandnames_from_numpy.bsq') + + gA = GeoArray(np.random.randint(1, 10, (5, 5, 3))) + gA.bandnames = ['test1', 'band_2', 'layer 3'] + gA.save(outPath) + + with open(os.path.splitext(outPath)[0] + '.hdr', 'r') as inF: + content = inF.read() + + for bN in gA.bandnames.keys(): + self.assertTrue(bN in content, msg="The band name '%s' is not in the written header. " + "Header contains: \n\n%s" % (bN, content))