Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decimation base as input to cog_translate #285

Merged
merged 2 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/docs/Advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ print(overviews)
[2, 4, 8]
```

### Decimation Base

As described above, a decimation base of 2 is used by default. However you can provide a custom base, N > 1, with *--decimation-base N*. Optimal overviews are computed assuming a base 2 is used, so using *--decimation-base* also requires that *--overview-level* is provided. Similar to the default example, here are the overviews for base 3:

```python
overview_level = 3
decimation_base = 3
overviews = [decimation_base ** j for j in range(1, overview_level + 1)]
print(overviews)
[3, 9, 27]
```

This is primarily useful when working with [custom TileMatrixSets](https://developmentseed.org/morecantile/usage/#define-custom-grid) that also use a non-default decimation base.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

## Band metadata
By default rio cogeo DO NOT forward **band** metadata (e.g statistics) to the output dataset.

Expand Down
16 changes: 15 additions & 1 deletion rio_cogeo/cogeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def cog_translate( # noqa: C901
colormap: Optional[Dict] = None,
additional_cog_metadata: Optional[Dict] = None,
use_cog_driver: bool = False,
decimation_base: int = 2,
):
"""
Create Cloud Optimized Geotiff.
Expand Down Expand Up @@ -171,6 +172,10 @@ def cog_translate( # noqa: C901
Additional dataset metadata to add to the COG.
use_cog_driver: bool, optional (default: False)
Use GDAL COG driver if set to True. COG driver is available starting with GDAL 3.1.
decimation_base: int, default: 2
How overviews are divided at each zoom level (default is 2). Must be greater than 1.
Also requires that `overview_level` is provided for `decimation_base` values greater
than 2.

.. deprecated:: 5.1.2
`web_optimized` is deprecated in favor of `tms`.
Expand All @@ -187,6 +192,15 @@ def cog_translate( # noqa: C901
)
tms = tms or morecantile.tms.get("WebMercatorQuad")

if decimation_base <= 1:
raise ValueError(
"Decimation base must be greater than 1 for building overviews."
)
elif decimation_base > 2 and overview_level is None:
raise ValueError(
"Decimation base values greater than 2 require that overview_level is defined."
)

dst_kwargs = dst_kwargs.copy()

if isinstance(indexes, int):
Expand Down Expand Up @@ -343,7 +357,7 @@ def cog_translate( # noqa: C901
if not quiet and overview_level:
click.echo("Adding overviews...", err=True)

overviews = [2**j for j in range(1, overview_level + 1)]
overviews = [decimation_base**j for j in range(1, overview_level + 1)]
tmp_dst.build_overviews(overviews, ResamplingEnums[overview_resampling])

if not quiet:
Expand Down
10 changes: 10 additions & 0 deletions rio_cogeo/scripts/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ def cogeo():
"selected until the smallest overview is smaller than the value of the "
"internal blocksize)",
)
@click.option(
"--decimation-base",
type=int,
help="Decimation base, how to sub-divide a raster for each overview level. "
"Also requires that --overview-level is provided.",
default=2,
show_default=True,
)
@click.option(
"--overview-resampling",
help="Overview creation resampling algorithm.",
Expand Down Expand Up @@ -230,6 +238,7 @@ def create(
add_mask,
blocksize,
overview_level,
decimation_base,
overview_resampling,
overview_blocksize,
web_optimized,
Expand Down Expand Up @@ -318,6 +327,7 @@ def create(
tms=tilematrixset,
use_cog_driver=use_cog_driver,
quiet=quiet,
decimation_base=decimation_base,
)


Expand Down
22 changes: 22 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,28 @@ def test_cogeo_validOvrOption(runner):
assert src.overviews(1) == [2, 4]


def test_cogeo_decimation_base_option(runner):
"""Should work as expected."""
with runner.isolated_filesystem():
result = runner.invoke(
cogeo,
[
"create",
raster_path_rgb,
"output.tif",
"--decimation-base",
3,
"--overview-level",
6,
],
)
assert not result.exception
assert result.exit_code == 0
with rasterio.open("output.tif") as src:
assert len(src.overviews(1)) == 6
assert src.overviews(1)[0] == 3


def test_cogeo_overviewTilesize(monkeypatch, runner):
"""Should work as expected."""
with runner.isolated_filesystem():
Expand Down
20 changes: 20 additions & 0 deletions tests/test_cogeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,3 +724,23 @@ def test_cog_translate_forward_ns_metadata(runner):
with rasterio.open("cogeo.tif") as src:
assert src.tags(ns="IMD")
assert src.tags(ns="RPC")


def test_cog_translate_decimation_base(runner):
"""Should create proper overviews when using custom decimation base."""
with runner.isolated_filesystem():

base_level_pairs = [(3, 6), (4, 5), (5, 4)]

for decimation_base, overview_level in base_level_pairs:
cog_translate(
raster_path_rgb,
"cogeo.tif",
cog_profiles.get("deflate"),
decimation_base=decimation_base,
overview_level=overview_level,
quiet=True,
)

with rasterio.open("cogeo.tif") as src:
assert src.overviews(1)[0] == decimation_base
Loading