From 19d3a6f3080945b1209bf14f4e5501b655f3fa45 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 16 Jun 2022 22:04:18 -0500 Subject: [PATCH 1/7] Extend cogify --- CHANGELOG.md | 2 + src/stactools/core/utils/convert.py | 96 ++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba3c1609..fbe6a8d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Modified stactools.core.utils.convert with functions to export subdatasets from HDF files as separate COGs and +single bands from multiband files ([#224](https://github.com/stac-utils/stactools/issues/224)) - Modified stactools.core.utils.antimeridian.fix_item to return the item and updated 2 unit tests ([#309](https://github.com/stac-utils/stactools/issues/309)) - Relaxed typing for cmd parameter for the CliTestCase.run_command in cli_test.py ([#306](https://github.com/stac-utils/stactools/issues/306)) - Cleaned up API documentation ([#315](https://github.com/stac-utils/stactools/pull/315)) diff --git a/src/stactools/core/utils/convert.py b/src/stactools/core/utils/convert.py index c58906b3..08afdc31 100644 --- a/src/stactools/core/utils/convert.py +++ b/src/stactools/core/utils/convert.py @@ -1,6 +1,7 @@ """Format conversion utilities.""" -from typing import Any, Dict, Optional +import os +from typing import Any, Dict, List, Optional, Tuple, cast import rasterio import rasterio.shutil @@ -16,25 +17,102 @@ """The default profile to use when writing Cloud-Optimized GeoTIFFs (COGs).""" -def cogify(infile: str, outfile: str, profile: Optional[Dict[str, Any]] = None) -> None: - """Creates a Cloud-Optimized GeoTIFF (COG) from a GDAL-readable file. +def check_gdal_driver() -> None: + if not utils.gdal_driver_is_enabled("COG"): + raise DriverRegistrationError( + "GDAL's COG driver is not enabled, make sure you're using GDAL >= 3.1" + ) + + +def cogify( + infile: str, + outfile: str, + band: Optional[int] = None, + profile: Optional[Dict[str, Any]] = None, +) -> None: + """Creates a Cloud-Optimized GeoTIFF (COG) from a GDAL-readable file + without subdatasets (non-HDF files). A band number can optionally be + provided to extract a single band from a multiband file. Uses :py:meth:`rasterio.shutil.copy`. Args: infile (str): The input file. outfile (str): The output COG to be written. + band (Optional[int]): The band number in the input file to extract. profile (Optional[dict[str, Any]]): An optional profile to use on the output file. If not provided, :py:const:`stactools.core.utils.convert.DEFAULT_PROFILE` will be used. """ - if not utils.gdal_driver_is_enabled("COG"): - raise DriverRegistrationError( - "GDAL's COG driver is not enabled, make sure you're using GDAL >= 3.1" - ) - destination_profile = DEFAULT_PROFILE.copy() + check_gdal_driver() + + src = rasterio.open(infile) + dest_profile = DEFAULT_PROFILE.copy() + dest_profile.update( + { + "dtype": rasterio.uint8, + "width": src.width, + "height": src.height, + "crs": src.crs, + "transform": src.transform, + } + ) + if profile: - destination_profile.update(profile) + dest_profile.update(profile) + + # If a band number was provided, create a single-band COG + if band: + single_band = src.read(band) + dest_profile.update({"count": 1}) + with rasterio.open(outfile, "w", **dest_profile) as dest: + dest.write(single_band, 1) + # If no band numbers were provided, create a multi-band COG + else: + dest_profile.update({"count": src.count}) + rasterio.shutil.copy(infile, outfile, **dest_profile) + + +def cogify_subdataset(infile: str, outfile: str) -> None: + """Exports a Cloud-Optimized GeoTIFF (COG) from a subdataset within an HDF file. + Uses :py:meth:`rasterio.shutil.copy`. + Args: + infile (str): The input file. + outfile (str): The output COG to be written. + """ + check_gdal_driver() + destination_profile = DEFAULT_PROFILE.copy() rasterio.shutil.copy(infile, outfile, **destination_profile) + + +def list_subdataset(infile: str, outdir: str) -> Tuple[List[str], List[str]]: + """Generates lists of output paths and subdataset names for COGs created from an HDF file. + This is then used to call the cogify_subdataset() function to export out COG files. + Args: + infile (str): The input HDF file + outdir (str): The output directory where the HDF files will be created + Returns: + Tuple[List[str], List[str]]: A two tuple (paths, names): + - The first element is a list of the output tiff paths + - The second element is a list of subdataset names + """ + + with rasterio.open(infile) as dataset: + subdatasets = cast(List[str], dataset.subdatasets) + base_file_name = os.path.splitext(os.path.basename(infile))[0] + paths = [] + subdataset_names = [] + for subdataset in subdatasets: + parts = subdataset.split(":") + subdataset_name = parts[-1] + sanitized_subdataset_name = subdataset_name.replace(" ", "_").replace( + "/", "_" + ) + subdataset_names.append(sanitized_subdataset_name) + file_name = f"{base_file_name}_{sanitized_subdataset_name}.tif" + outfile = os.path.join(outdir, file_name) + cogify_subdataset(subdataset, outfile) + paths.append(outfile) + return (paths, subdataset_names) From 81281e6b4741fe25c79804fa97c8cef39cc2ea31 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Tue, 21 Jun 2022 15:00:27 -0500 Subject: [PATCH 2/7] Updated to reflect review --- CHANGELOG.md | 8 ++-- src/stactools/core/utils/convert.py | 71 ++++++++++++++--------------- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbe6a8d7..1adbcbf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Modified stactools.core.utils.convert with functions to export subdatasets from HDF files as separate COGs and -single bands from multiband files ([#224](https://github.com/stac-utils/stactools/issues/224)) -- Modified stactools.core.utils.antimeridian.fix_item to return the item and updated 2 unit tests ([#309](https://github.com/stac-utils/stactools/issues/309)) -- Relaxed typing for cmd parameter for the CliTestCase.run_command in cli_test.py ([#306](https://github.com/stac-utils/stactools/issues/306)) +single bands from multiband files ([#318](https://github.com/stac-utils/stactools/pull/318)) +- Modified stactools.core.utils.antimeridian.fix_item to return the item and updated 2 unit tests ([#317](https://github.com/stac-utils/stactools/pull/317)) +- Relaxed typing for cmd parameter for the CliTestCase.run_command in cli_test.py ([#312](https://github.com/stac-utils/stactools/pull/312)) - Cleaned up API documentation ([#315](https://github.com/stac-utils/stactools/pull/315)) ### Removed @@ -25,7 +25,7 @@ single bands from multiband files ([#224](https://github.com/stac-utils/stactool ### Removed -- Dropped support for Python 3.7 ([#223](https://github.com/stac-utils/stactools/issues/223)) +- Dropped support for Python 3.7 ([#313](https://github.com/stac-utils/stactools/pull/313)) ## [v0.3.1] diff --git a/src/stactools/core/utils/convert.py b/src/stactools/core/utils/convert.py index 08afdc31..1885c17d 100644 --- a/src/stactools/core/utils/convert.py +++ b/src/stactools/core/utils/convert.py @@ -17,7 +17,7 @@ """The default profile to use when writing Cloud-Optimized GeoTIFFs (COGs).""" -def check_gdal_driver() -> None: +def assert_cog_driver_is_enabled() -> None: if not utils.gdal_driver_is_enabled("COG"): raise DriverRegistrationError( "GDAL's COG driver is not enabled, make sure you're using GDAL >= 3.1" @@ -30,29 +30,28 @@ def cogify( band: Optional[int] = None, profile: Optional[Dict[str, Any]] = None, ) -> None: - """Creates a Cloud-Optimized GeoTIFF (COG) from a GDAL-readable file - without subdatasets (non-HDF files). A band number can optionally be - provided to extract a single band from a multiband file. - - Uses :py:meth:`rasterio.shutil.copy`. + """Creates a Cloud-Optimized GeoTIFF (COG) from a GDAL-readable file. + A band number can optionally be provided to extract a single band from a + multiband file. To create COGs from subdatasets, use + :py:meth:`stactools.core.utils.convert.cogify_subdatasets`. Args: infile (str): The input file. outfile (str): The output COG to be written. band (Optional[int]): The band number in the input file to extract. + If not provided, a multi-band COG will be created. profile (Optional[dict[str, Any]]): An optional profile to use on the output file. If not provided, :py:const:`stactools.core.utils.convert.DEFAULT_PROFILE` will be used. """ - check_gdal_driver() + assert_cog_driver_is_enabled() src = rasterio.open(infile) dest_profile = DEFAULT_PROFILE.copy() dest_profile.update( { - "dtype": rasterio.uint8, "width": src.width, "height": src.height, "crs": src.crs, @@ -66,53 +65,53 @@ def cogify( # If a band number was provided, create a single-band COG if band: single_band = src.read(band) - dest_profile.update({"count": 1}) + dest_profile.update({"count": 1, "dtype": single_band.dtype}) with rasterio.open(outfile, "w", **dest_profile) as dest: dest.write(single_band, 1) # If no band numbers were provided, create a multi-band COG else: - dest_profile.update({"count": src.count}) + dest_profile.update({"count": src.count, "dtype": src.dtypes[0]}) rasterio.shutil.copy(infile, outfile, **dest_profile) -def cogify_subdataset(infile: str, outfile: str) -> None: - """Exports a Cloud-Optimized GeoTIFF (COG) from a subdataset within an HDF file. - Uses :py:meth:`rasterio.shutil.copy`. - Args: - infile (str): The input file. - outfile (str): The output COG to be written. - """ - check_gdal_driver() - destination_profile = DEFAULT_PROFILE.copy() - rasterio.shutil.copy(infile, outfile, **destination_profile) - - -def list_subdataset(infile: str, outdir: str) -> Tuple[List[str], List[str]]: - """Generates lists of output paths and subdataset names for COGs created from an HDF file. - This is then used to call the cogify_subdataset() function to export out COG files. - Args: - infile (str): The input HDF file - outdir (str): The output directory where the HDF files will be created - Returns: - Tuple[List[str], List[str]]: A two tuple (paths, names): - - The first element is a list of the output tiff paths - - The second element is a list of subdataset names +def cogify_subdatasets( + infile: str, outdir: str, subdataset_names: Optional[List[str]] = None +) -> Tuple[List[str], List[str]]: + """Creates Cloud-Optimized GeoTIFFs for all subdatasets in a multi-dataset raster file. + The created files will be named the same as the source file, with a ``_SUBDATASET`` suffix. + E.g. if the source file is named ``foo.hdf`` and the subdataset is named ``bar``, the output + COG will be named ``foo_bar.tif``. + Args: + infile (str): The input file containing subdatasets. + outdir (str): The output directory where the COGs will be created. + Returns: + Tuple[List[str], List[str]]: + A two tuple (paths, names): + - The first element is a list of the output COG paths + - The second element is a list of subdataset names """ with rasterio.open(infile) as dataset: + assert_cog_driver_is_enabled() subdatasets = cast(List[str], dataset.subdatasets) base_file_name = os.path.splitext(os.path.basename(infile))[0] paths = [] - subdataset_names = [] + names = [] for subdataset in subdatasets: + subd = rasterio.open(subdataset) + if len(subd.shape) != 2: + continue parts = subdataset.split(":") subdataset_name = parts[-1] + if subdataset_names and subdataset_name not in subdataset_names: + continue sanitized_subdataset_name = subdataset_name.replace(" ", "_").replace( "/", "_" ) - subdataset_names.append(sanitized_subdataset_name) + names.append(sanitized_subdataset_name) file_name = f"{base_file_name}_{sanitized_subdataset_name}.tif" outfile = os.path.join(outdir, file_name) - cogify_subdataset(subdataset, outfile) + destination_profile = DEFAULT_PROFILE.copy() + rasterio.shutil.copy(subdataset, outfile, **destination_profile) paths.append(outfile) - return (paths, subdataset_names) + return (paths, names) From ab797d0fc6755090f0fdc5893ad5ea700db56090 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 23 Jun 2022 11:06:05 -0500 Subject: [PATCH 3/7] updated for review 3 --- src/stactools/core/utils/convert.py | 11 ++++++---- tests/core/utils/test_convert.py | 20 +++++++++++++++++- .../hdf/AMSR_E_L3_RainGrid_B05_200707.h5 | Bin 0 -> 63269 bytes 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tests/data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5 diff --git a/src/stactools/core/utils/convert.py b/src/stactools/core/utils/convert.py index 1885c17d..cbc56dfd 100644 --- a/src/stactools/core/utils/convert.py +++ b/src/stactools/core/utils/convert.py @@ -31,6 +31,7 @@ def cogify( profile: Optional[Dict[str, Any]] = None, ) -> None: """Creates a Cloud-Optimized GeoTIFF (COG) from a GDAL-readable file. + A band number can optionally be provided to extract a single band from a multiband file. To create COGs from subdatasets, use :py:meth:`stactools.core.utils.convert.cogify_subdatasets`. @@ -78,21 +79,23 @@ def cogify_subdatasets( infile: str, outdir: str, subdataset_names: Optional[List[str]] = None ) -> Tuple[List[str], List[str]]: """Creates Cloud-Optimized GeoTIFFs for all subdatasets in a multi-dataset raster file. + The created files will be named the same as the source file, with a ``_SUBDATASET`` suffix. E.g. if the source file is named ``foo.hdf`` and the subdataset is named ``bar``, the output - COG will be named ``foo_bar.tif``. - Args: + COG will be named ``foo_bar.tif``. Only 2D (and not 3D) subdatasets are supported. + + Args: infile (str): The input file containing subdatasets. outdir (str): The output directory where the COGs will be created. - Returns: + Returns: Tuple[List[str], List[str]]: A two tuple (paths, names): - The first element is a list of the output COG paths - The second element is a list of subdataset names """ + assert_cog_driver_is_enabled() with rasterio.open(infile) as dataset: - assert_cog_driver_is_enabled() subdatasets = cast(List[str], dataset.subdatasets) base_file_name = os.path.splitext(os.path.basename(infile))[0] paths = [] diff --git a/tests/core/utils/test_convert.py b/tests/core/utils/test_convert.py index 3fff00e9..9c4eda91 100644 --- a/tests/core/utils/test_convert.py +++ b/tests/core/utils/test_convert.py @@ -5,7 +5,7 @@ import rasterio -from stactools.core.utils.convert import cogify +from src.stactools.core.utils.convert import cogify, cogify_subdatasets from tests import test_data @@ -31,3 +31,21 @@ def test_profile(self): self.assertTrue(os.path.exists(outfile)) with rasterio.open(outfile) as dataset: self.assertEqual(dataset.compression, rasterio.enums.Compression.lzw) + + def test_subdataset(self): + infile = test_data.get_path("data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5") + with TemporaryDirectory() as directory: + paths, names = cogify_subdatasets(infile, directory) + self.assertEqual( + names, + [ + "__MonthlyRainTotal_GeoGrid_Data_Fields_RrLandRain", + "__MonthlyRainTotal_GeoGrid_Data_Fields_TbOceanRain", + ], + ) + for path in paths: + self.assertTrue(os.path.exists(path)) + with rasterio.open(path) as dataset: + self.assertEqual( + dataset.compression, rasterio.enums.Compression.deflate + ) diff --git a/tests/data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5 b/tests/data-files/hdf/AMSR_E_L3_RainGrid_B05_200707.h5 new file mode 100644 index 0000000000000000000000000000000000000000..a2971286da875101c46df3cf57a0bf90a4780d5f GIT binary patch literal 63269 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 H{h$8_pQu;w literal 0 HcmV?d00001 From 946e2c3940607a8cc00628ea669d9f04ff7162f8 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 23 Jun 2022 11:50:01 -0500 Subject: [PATCH 4/7] fixed import --- tests/core/utils/test_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core/utils/test_convert.py b/tests/core/utils/test_convert.py index 9c4eda91..69aa0dce 100644 --- a/tests/core/utils/test_convert.py +++ b/tests/core/utils/test_convert.py @@ -5,7 +5,7 @@ import rasterio -from src.stactools.core.utils.convert import cogify, cogify_subdatasets +from stactools.core.utils.convert import cogify, cogify_subdatasets from tests import test_data From b671887c9b1fe1f9ecb75703f2255661140924d8 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 23 Jun 2022 12:30:59 -0500 Subject: [PATCH 5/7] file open syntax --- src/stactools/core/utils/convert.py | 33 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/stactools/core/utils/convert.py b/src/stactools/core/utils/convert.py index cbc56dfd..3cd39bec 100644 --- a/src/stactools/core/utils/convert.py +++ b/src/stactools/core/utils/convert.py @@ -101,20 +101,21 @@ def cogify_subdatasets( paths = [] names = [] for subdataset in subdatasets: - subd = rasterio.open(subdataset) - if len(subd.shape) != 2: - continue - parts = subdataset.split(":") - subdataset_name = parts[-1] - if subdataset_names and subdataset_name not in subdataset_names: - continue - sanitized_subdataset_name = subdataset_name.replace(" ", "_").replace( - "/", "_" - ) - names.append(sanitized_subdataset_name) - file_name = f"{base_file_name}_{sanitized_subdataset_name}.tif" - outfile = os.path.join(outdir, file_name) - destination_profile = DEFAULT_PROFILE.copy() - rasterio.shutil.copy(subdataset, outfile, **destination_profile) - paths.append(outfile) + with rasterio.open(subdataset) as subd: + if len(subd.shape) != 2: + continue + parts = subdataset.split(":") + subdataset_name = parts[-1] + if subdataset_names and subdataset_name not in subdataset_names: + continue + sanitized_subdataset_name = subdataset_name.replace(" ", "_").replace( + "/", "_" + ) + names.append(sanitized_subdataset_name) + file_name = f"{base_file_name}_{sanitized_subdataset_name}.tif" + outfile = os.path.join(outdir, file_name) + destination_profile = DEFAULT_PROFILE.copy() + rasterio.shutil.copy(subdataset, outfile, **destination_profile) + paths.append(outfile) + subd.close() return (paths, names) From 10fe9903aac9ffe5baf302d22c9504ad095c2cf8 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 23 Jun 2022 14:01:15 -0500 Subject: [PATCH 6/7] remove close --- src/stactools/core/utils/convert.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stactools/core/utils/convert.py b/src/stactools/core/utils/convert.py index 3cd39bec..ac54a74c 100644 --- a/src/stactools/core/utils/convert.py +++ b/src/stactools/core/utils/convert.py @@ -117,5 +117,4 @@ def cogify_subdatasets( destination_profile = DEFAULT_PROFILE.copy() rasterio.shutil.copy(subdataset, outfile, **destination_profile) paths.append(outfile) - subd.close() return (paths, names) From 29044abe18d0eb46530f2947518298b0ee0a4826 Mon Sep 17 00:00:00 2001 From: Neeraj Sirdeshmukh Date: Thu, 23 Jun 2022 14:50:39 -0500 Subject: [PATCH 7/7] fixed changelog --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7362b8ba..96f87dc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,6 @@ single bands from multiband files ([#318](https://github.com/stac-utils/stactool ### Removed - Unnecessary and incorrect `args` and `kwargs` from `StacIO` subclass ([#315](https://github.com/stac-utils/stactools/pull/315)) - -### Removed - - Dropped support for Python 3.7 ([#313](https://github.com/stac-utils/stactools/pull/313)) ## [v0.3.1]