Repository: rasterio/rasterio

Issue:
Missing `RMS` support in build_overviews
https://github.com/mapbox/rasterio/blob/3c630f8a30d31ceb61aa52ad3ab96f4fc25f2ecd/rasterio/_io.pyx#L1794-L1801

>  @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS", "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST", "NONE"
 
https://github.com/OSGeo/gdal/blob/3d32de21b79ab7e09024f55a0e6740f00318dd3e/gdal/gcore/gdaldataset.cpp#L1908-L1909


Discussion:
@vincentsarago add it if you want it for 1.2.3.
@sgillies I'm kinda unhappy with how the available resampling values for overviews is stored in a dict within the `build_overviews` method, which then leads to https://github.com/mapbox/rasterio/blob/3c630f8a30d31ceb61aa52ad3ab96f4fc25f2ecd/rasterio/rio/overview.py#L74

What do you think about creating a specific enum for the Overview specific Resampling values? (which could then be referenced in the rio cli)
@vincentsarago yes, for sure, let's do better. It's not immediately clear to me that another enum makes this situation better. It might, though. Worth a draft PR, for sure.

Resolving patch:
diff --git a/rasterio/enums.py b/rasterio/enums.py
--- a/rasterio/enums.py
+++ b/rasterio/enums.py
@@ -60,6 +60,30 @@ class Resampling(IntEnum):
     rms = 14
 
 
+class OverviewResampling(IntEnum):
+    """Available Overview resampling algorithms.
+
+    The first 8, 'nearest', 'bilinear', 'cubic', 'cubic_spline',
+    'lanczos', 'average', 'mode', and 'gauss', are available for making
+    dataset overviews.
+
+    'nearest', 'bilinear', 'cubic', 'cubic_spline', 'lanczos',
+    'average', 'mode' are always available (GDAL >= 1.10).
+
+    'rms' is only supported in GDAL >= 3.3.
+
+    """
+    nearest = 0
+    bilinear = 1
+    cubic = 2
+    cubic_spline = 3
+    lanczos = 4
+    average = 5
+    mode = 6
+    gauss = 7
+    rms = 14
+
+
 class Compression(Enum):
     """Available compression algorithms."""
     jpeg = 'JPEG'
diff --git a/rasterio/rio/overview.py b/rasterio/rio/overview.py
--- a/rasterio/rio/overview.py
+++ b/rasterio/rio/overview.py
@@ -9,7 +9,7 @@
 
 from . import options
 import rasterio
-from rasterio.enums import Resampling
+from rasterio.enums import OverviewResampling
 
 
 def build_handler(ctx, param, value):
@@ -70,8 +70,7 @@ def get_maximum_overview_level(width, height, minsize=256):
 @click.option('--rebuild', help="Reconstruct existing overviews.",
               is_flag=True, default=False)
 @click.option('--resampling', help="Resampling algorithm.",
-              type=click.Choice(
-                  [it.name for it in Resampling if it.value in [0, 1, 2, 3, 4, 5, 6, 7]]),
+              type=click.Choice([it.name for it in OverviewResampling]),
               default='nearest', show_default=True)
 @click.pass_context
 def overview(ctx, input, build, ls, rebuild, resampling):
@@ -126,14 +125,14 @@ def overview(ctx, input, build, ls, rebuild, resampling):
                     ns='rio_overview').get('resampling') or resampling
 
                 dst.build_overviews(
-                    list(factors), Resampling[resampling_method])
+                    list(factors), OverviewResampling[resampling_method])
 
         elif build:
             with rasterio.open(input, 'r+') as dst:
                 if build == "auto":
                     overview_level = get_maximum_overview_level(dst.width, dst.height)
                     build = [2 ** j for j in range(1, overview_level + 1)]
-                dst.build_overviews(build, Resampling[resampling])
+                dst.build_overviews(build, OverviewResampling[resampling])
 
                 # Save the resampling method to a tag.
                 dst.update_tags(ns='rio_overview', resampling=resampling)


Test patch:
diff --git a/tests/test_enums.py b/tests/test_enums.py
--- a/tests/test_enums.py
+++ b/tests/test_enums.py
@@ -1,5 +1,7 @@
 """Enum tests"""
 
+import pytest
+
 from rasterio import enums
 
 
@@ -11,3 +13,9 @@ def test_grey_gray():
 def test_gray_gray():
     """Name of ColorInterp.gray is 'gray'"""
     assert enums.ColorInterp.gray.name == "gray"
+
+
+@pytest.mark.parametrize("resamp", enums.OverviewResampling)
+def test_resampling(resamp):
+    """Make sure that resampling value are the same."""
+    assert resamp.value == enums.Resampling[resamp.name].value
diff --git a/tests/test_overviews.py b/tests/test_overviews.py
--- a/tests/test_overviews.py
+++ b/tests/test_overviews.py
@@ -7,7 +7,7 @@
 from .conftest import requires_gdal2, requires_gdal33
 
 import rasterio
-from rasterio.enums import Resampling
+from rasterio.enums import OverviewResampling, Resampling
 from rasterio.env import GDALVersion
 from rasterio.errors import OverviewCreationError
 
@@ -24,7 +24,7 @@ def test_build_overviews_one(data):
     inputfile = str(data.join('RGB.byte.tif'))
     with rasterio.open(inputfile, 'r+') as src:
         overview_factors = [2]
-        src.build_overviews(overview_factors, resampling=Resampling.nearest)
+        src.build_overviews(overview_factors, resampling=OverviewResampling.nearest)
         assert src.overviews(1) == [2]
         assert src.overviews(2) == [2]
         assert src.overviews(3) == [2]
@@ -34,7 +34,7 @@ def test_build_overviews_two(data):
     inputfile = str(data.join('RGB.byte.tif'))
     with rasterio.open(inputfile, 'r+') as src:
         overview_factors = [2, 4]
-        src.build_overviews(overview_factors, resampling=Resampling.nearest)
+        src.build_overviews(overview_factors, resampling=OverviewResampling.nearest)
         assert src.overviews(1) == [2, 4]
         assert src.overviews(2) == [2, 4]
         assert src.overviews(3) == [2, 4]
@@ -48,7 +48,7 @@ def test_build_overviews_bilinear(data):
     inputfile = str(data.join('RGB.byte.tif'))
     with rasterio.open(inputfile, 'r+') as src:
         overview_factors = [2, 4]
-        src.build_overviews(overview_factors, resampling=Resampling.bilinear)
+        src.build_overviews(overview_factors, resampling=OverviewResampling.bilinear)
         assert src.overviews(1) == [2, 4]
         assert src.overviews(2) == [2, 4]
         assert src.overviews(3) == [2, 4]
@@ -58,7 +58,7 @@ def test_build_overviews_average(data):
     inputfile = str(data.join('RGB.byte.tif'))
     with rasterio.open(inputfile, 'r+') as src:
         overview_factors = [2, 4]
-        src.build_overviews(overview_factors, resampling=Resampling.average)
+        src.build_overviews(overview_factors, resampling=OverviewResampling.average)
         assert src.overviews(1) == [2, 4]
         assert src.overviews(2) == [2, 4]
         assert src.overviews(3) == [2, 4]
@@ -68,7 +68,7 @@ def test_build_overviews_gauss(data):
     inputfile = str(data.join('RGB.byte.tif'))
     with rasterio.open(inputfile, 'r+') as src:
         overview_factors = [2, 4]
-        src.build_overviews(overview_factors, resampling=Resampling.gauss)
+        src.build_overviews(overview_factors, resampling=OverviewResampling.gauss)
         assert src.overviews(1) == [2, 4]
         assert src.overviews(2) == [2, 4]
         assert src.overviews(3) == [2, 4]
@@ -89,7 +89,7 @@ def test_issue1333(data):
         with rasterio.open(inputfile, 'r+') as src:
             overview_factors = [1024, 2048]
             src.build_overviews(
-                overview_factors, resampling=Resampling.average)
+                overview_factors, resampling=OverviewResampling.average)
 
 
 @requires_gdal2
@@ -101,7 +101,7 @@ def test_build_overviews_new_file(tmpdir, path_rgb_byte_tif):
             dst.write(src.read())
             overview_factors = [2, 4]
             dst.build_overviews(
-                overview_factors, resampling=Resampling.nearest)
+                overview_factors, resampling=OverviewResampling.nearest)
 
     with rasterio.open(dst_file, overview_level=1) as src:
         data = src.read()
@@ -145,3 +145,15 @@ def test_decimated_no_use_overview(red_green):
     with rasterio.open(str(red_green.join("red.tif")), OVERVIEW_LEVEL="NONE") as src:
         decimated_data = src.read(2, out_shape=ovr_shape)
         assert not np.array_equal(ovr_data, decimated_data)
+
+
+@requires_gdal33
+def test_build_overviews_rms(data):
+    """Make sure RMS resampling works with gdal3.3."""
+    inputfile = str(data.join('RGB.byte.tif'))
+    with rasterio.open(inputfile, 'r+') as src:
+        overview_factors = [2, 4]
+        src.build_overviews(overview_factors, resampling=OverviewResampling.rms)
+        assert src.overviews(1) == [2, 4]
+        assert src.overviews(2) == [2, 4]
+        assert src.overviews(3) == [2, 4]