Strange output when using "min" resampling method with WarpedVRT


Sean Gillies
 

Hi Daniel,

Yes, please do create an issue. One with some code that will reproduce the problem would be perfect.

On Wed, Sep 8, 2021 at 11:35 AM <daniel.mannarino@...> wrote:
Hi folks,

I'm wondering what my next steps should be for this. I tried the script I posted a week ago after installing GDAL 3.3.2 and Python 3.9.7 via Homebrew (GDAL 3.3.2 is not yet in the tree for Homebrew but I edited the recipe to point to 3.3.2 and it built without difficulty), then rasterio 1.2.7, pyproj, and affine via pip. The results are still incorrect (there are values of 1 in channels which should all be masked 0s and the value selected for the minimum is not actually the smallest). Should I create a Github issue at this point?
Thanks,
Daniel Mannarino
_,_._,

--
Sean Gillies


daniel.mannarino@...
 

Hi folks,

I'm wondering what my next steps should be for this. I tried the script I posted a week ago after installing GDAL 3.3.2 and Python 3.9.7 via Homebrew (GDAL 3.3.2 is not yet in the tree for Homebrew but I edited the recipe to point to 3.3.2 and it built without difficulty), then rasterio 1.2.7, pyproj, and affine via pip. The results are still incorrect (there are values of 1 in channels which should all be masked 0s and the value selected for the minimum is not actually the smallest). Should I create a Github issue at this point?
Thanks,
Daniel Mannarino


daniel.mannarino@...
 

Oops, I mangled my message a bit during editing. To clarify, "the problem [with 1s appearing in the other channel] surfaced even when just using rasterio.warp.reproject. Further, [when reading from a WarpedVRT] the min algorithm seems to have selected 10000 from a masked 0, 10000, 2500, and 5000"


daniel.mannarino@...
 

Hi Sean,

Thanks for taking a look! It doesn't sound to ME like that bug would account for the behavior I'm seeing (at least not the anomalous data in the previously all-zero bands), but I'm not sure. Just in case, I decided to build and install GDAL HEAD and rasterio 1.2.6 against it to test, but it doesn't seem to have solved my problem. In fact when I tried to make it easier to observe by writing a script with synthetic data rather than just the interactive session output, the problem surfaced even when just using rasterio.warp.reproject. Further, the min algorithm seems to have selected 10000 from a masked 0, 10000, 2500, and 5000! But perhaps you can spy a mistake I made. Here's the script and the output I obtain when using git GDAL from a few days ago. Note that I decided to use smaller sample data and fewer channels just to cut down on the output. Oh, and this is with Python 3.9.6 on MacOS 10.15.7 (Catalina):

# begin resampling-test.py:
import subprocess
 
import numpy as np
import rasterio
from affine import Affine
from pyproj import CRS
from rasterio.enums import Resampling
from rasterio.profiles import DefaultGTiffProfile
from rasterio.vrt import WarpedVRT
from rasterio.warp import reproject
 
 
synthetic_data = np.zeros((2, 8, 8), dtype="uint16")
synthetic_data[0][0][1] = 2500
synthetic_data[0][1][0] = 5000
synthetic_data[0][1][1] = 10000
 
print("Original synthetic data:")
print(synthetic_data)
 
crs = CRS.from_epsg(3857)
transform = Affine(
    10.0,  # a: width of a pixel
    0.0,   # b: row rotation
    -40.0, # c: x-coord of the upper-left corner of the upper-left pixel
    0.0,   # d: column rotation
    -10.0, # e: height of a pixel (typically negative)
    40.0   # y-coord of the of the upper-left corner of the upper-left pixel
)
 
synthetic_data_profile = {
    **DefaultGTiffProfile(count=synthetic_data.shape[0]),
    "crs": crs,
    "dtype": "uint16",
    "height": synthetic_data.shape[1],
    "width": synthetic_data.shape[2],
    "transform": transform
}
 
print(f"Synthetic file profile:")
print(synthetic_data_profile)
 
with rasterio.open('synthetic_data.tif', 'w', **synthetic_data_profile) as dst:
    dst.write(synthetic_data)
 
with rasterio.open('synthetic_data.tif') as src:
    synthetic_data_saved = src.read([1,2], masked=True)
 
print(
    "Synthetic data written and re-read (should be identical to original "
    "except now 0s are masked):"
)
print(synthetic_data_saved)
 
print("Now let's scale it using rasterio.warp.reproject")
 
reprojection_dst = np.zeros((2, 4, 4), dtype="uint16")
 
reproject(
    synthetic_data_saved,
    reprojection_dst,
    src_transform=transform,
    src_crs=crs.to_dict(),
    dst_crs=crs.to_dict(),
    resampling=Resampling.min,
    src_no_data=0
)
 
print("Resulting data:")
print(reprojection_dst)
 
 
print(
    "Now let's try reading through a VRT. First through a regular VRT, "
    "then through a WarpedVRT without scaling, and finally through a "
    "WarpedVRT into an out_shape that implicitly causes scaling"
)
 
print("Creating the VRT")
subprocess.run(
    ["gdalbuildvrt", "synthetic_data.vrt", "synthetic_data.tif"],
    capture_output=True
)
 
print(f"Data as read through plain VRT:")
with rasterio.open('synthetic_data.vrt') as vrt_src:
    synthetic_data_vrt = vrt_src.read([1,2], masked=True)
print(synthetic_data_vrt)
 
print(
    "Now the data as read through a WarpedVRT with Resampling mode nearest "
    "but no out_shape specified:")
with rasterio.open('synthetic_data.vrt') as vrt_src:
    with WarpedVRT(vrt_src, resampling=Resampling.nearest) as warped_vrt:
        synthetic_data_warped_nearest = warped_vrt.read([1,2], masked=True)
print(synthetic_data_warped_nearest)
 
print(
    "Now the data as read through a WarpedVRT with Resampling mode min "
    "but no out_shape specified:")
with rasterio.open('synthetic_data.vrt') as vrt_src:
    with WarpedVRT(vrt_src, resampling=Resampling.min) as warped_vrt:
        synthetic_data_warped_min = warped_vrt.read([1,2], masked=True)
print(synthetic_data_warped_min)
 
print(
    "Finally the data as read through a WarpedVRT with Resampling mode min "
    "and an out_shape that causes implicit scaling by a factor of 0.5:")
with rasterio.open('synthetic_data.vrt') as vrt_src:
    with WarpedVRT(vrt_src, resampling=Resampling.min) as warped_vrt:
        synthetic_data_warped_min_scaled = warped_vrt.read(
            [1,2], out_shape=(2, 4, 4), masked=True
        )
print(synthetic_data_warped_min_scaled)
# end resampling-test.py:

Output when I run it locally:

daniel.mannarino$ PATH=$PATH:/usr/local/Cellar/gdal/HEAD-a0ba563_3/bin/ python resampling_test.py 

Original synthetic data:

[[[    0  2500     0     0     0     0     0     0]

  [ 5000 10000     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]]

 

 [[    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]

  [    0     0     0     0     0     0     0     0]]]

Synthetic file profile:

{'driver': 'GTiff', 'interleave': 'band', 'tiled': True, 'blockxsize': 256, 'blockysize': 256, 'compress': 'lzw', 'nodata': 0, 'dtype': 'uint16', 'count': 2, 'crs': <Projected CRS: EPSG:3857>

Name: WGS 84 / Pseudo-Mercator

Axis Info [cartesian]:

- X[east]: Easting (metre)

- Y[north]: Northing (metre)

Area of Use:

- name: World between 85.06°S and 85.06°N.

- bounds: (-180.0, -85.06, 180.0, 85.06)

Coordinate Operation:

- name: Popular Visualisation Pseudo-Mercator

- method: Popular Visualisation Pseudo Mercator

Datum: World Geodetic System 1984 ensemble

- Ellipsoid: WGS 84

- Prime Meridian: Greenwich

, 'height': 8, 'width': 8, 'transform': Affine(10.0, 0.0, -40.0,

       0.0, -10.0, 40.0)}

Synthetic data written and re-read (should be identical to original except now 0s are masked):

[[[-- 2500 -- -- -- -- -- --]

  [5000 10000 -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]]

Now let's scale it using rasterio.warp.reproject

/Users/daniel.mannarino/Sandbox/gdal_git/venv/lib/python3.9/site-packages/pyproj/crs/crs.py:1216: UserWarning: You will likely lose important projection information when converting to a PROJ string from another format. See: https://proj.org/faq.html#what-is-the-best-format-for-describing-coordinate-reference-systems

  return self._crs.to_proj4(version=version)

Resulting data:

[[[2500    0    0    0]

  [   0    0    0    0]

  [   0    0    0    0]

  [   0    0    0    0]]

 

 [[   1    0    0    0]

  [   0    0    0    0]

  [   0    0    0    0]

  [   0    0    0    0]]]

Now let's try reading through a VRT. First through a regular VRT, then through a WarpedVRT without scaling, and finally through a WarpedVRT into an out_shape that implicitly causes scaling

Creating the VRT

Data as read through plain VRT:

[[[-- 2500 -- -- -- -- -- --]

  [5000 10000 -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]]

Now the data as read through a WarpedVRT with Resampling mode nearest but no out_shape specified:

[[[-- 2500 -- -- -- -- -- --]

  [5000 10000 -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]]

Now the data as read through a WarpedVRT with Resampling mode min but no out_shape specified:

[[[-- 2500 -- -- -- -- -- --]

  [5000 10000 -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- 1 -- -- -- -- -- --]

  [1 1 -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]]]

Finally the data as read through a WarpedVRT with Resampling mode min and an out_shape that causes implicit scaling by a factor of 0.5:

[[[10000 -- -- --]

  [-- -- -- --]

  [-- -- -- --]

  [-- -- -- --]]

 

 [[1 -- -- --]

  [-- -- -- --]

  [-- -- -- --]

  [-- -- -- --]]]

Thanks for any help!
Daniel


Sean Gillies
 

Hi Daniel,

There was a bug recently reported at https://github.com/OSGeo/gdal/issues/4098 which might be related. I'll see about reproducing what you see. Could you read the GDAL ticket and see if anything in it is relevant?

On Tue, Aug 24, 2021 at 10:23 AM <daniel.mannarino@...> wrote:
Hi folks!

I have a 16x16 TIFF with 3 uint16 bands and no-data values of 0. There are a few non-no-data values in band 1, but bands 2 and 3 are all 0s (no-data). When I explicitly scale by 0.5 (i.e. effectively "zooming out" one zoom level) with rasterio.warp.reproject using either the "nearest" or "min" resampling method, the result is as expected. But when I implicitly scale by reading from a WarpedVRT with shape_out=(3, 8, 8) and resampling method "min", unexpected values of 1 appear in the the resulting bands 2 and 3. After further testing, it seems that they appear even when NOT scaling, reading into a shape_out of (3, 16, 16). This problem does not occur with a WarpedVRT and a resampling method of "nearest". Am I using the WarpedVRT incorrectly, or is this a bug?
The anomalous data was initially noticed in Linux with GDAL 3.2.0 but confirmed on MacOS Catalina with GDAL 3.2.0, 3.2.3 and 3.3.1 using rasterio 1.1.8, 1.2.3 and 1.2.6. Some commands and their output (performed with GDAL 3.3.1, rasterio 1.2.6 and Python 3.8.11):

In [1]: import rasterio

 

In [2]: res_file_16 = rasterio.open('resampled_2048th_min.tif')

 

In [3]: res_data_16 = res_file_16.read([1, 2, 3], masked=True)

 

In [4]: print(res_data_16)

[[[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2202 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 2202 2202]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2330 3258 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]]


In [6]: print(res_file_16.profile)

{'driver': 'GTiff', 'dtype': 'uint16', 'nodata': 0.0, 'width': 16, 'height': 16, 'count': 3, 'crs': CRS.from_epsg(3857), 'transform': Affine(39135.75848225398, 0.0, -2504688.542848654,

       0.0, -39135.75848225398, 3757032.814319771), 'blockxsize': 16, 'blockysize': 16, 'tiled': True, 'interleave': 'pixel'}


Now let's use reproject with resampling method "min" to scale by 0.5:

In [8]: import numpy as np

In [9]: from affine import Affine

In [10]: from rasterio.enums import Resampling

In [11]: from rasterio.warp import reproject

In [12]: dst = np.zeros((3, 8, 8))

    ...: dst_transform = res_file_16.transform * Affine.scale(0.5)

    ...: reproject(

    ...:     res_data_16,

    ...:     dst,

    ...:     src_transform=res_file_16.transform,

    ...:     src_crs=res_file_16.crs,

    ...:     dst_crs=res_file_16.crs,

    ...:     resampling=Resampling.min,

    ...:     src_nodata=0

    ...: )

Out[12]: 

(array([[[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0., 2202.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0., 2330., 2202.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]],

 

        [[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]],

 

        [[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]]]),

 Affine(78271.51696450796, 0.0, -2504688.542848654,

        0.0, -78271.51696450796, 3757032.814319771))

Looks good! Exactly what I would hope for. A cluster of three 2202 values became one 2202, a cluster of two of them became one 2202, and the min of 
2330 and 3258 became 2330. And of course everything in bands 2 and 3 is still masked.
Now let's try making a VRT, creating a WarpedVRT on top of it, and reading into an out_shape of (3, 8, 8) to implicitly scale it:

daniel.mannarino$ gdalbuildvrt resampled_2048th_min.vrt resampled_2048th_min.tif

0...10...20...30...40...50...60...70...80...90...100 - done.


In [15]: from rasterio.vrt import WarpedVRT

In [16]: with rasterio.open("resampled_2048th_min.vrt") as src:

    ...:     with WarpedVRT(src, resampling=Resampling.min) as vrt:

    ...:         res_vrt_8 = vrt.read([1, 2, 3], out_shape=(3, 8, 8), masked=True)

    ...: 

 

In [17]: print(res_vrt_8)

[[[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 2202 --]

  [-- -- -- -- -- -- 3258 --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- -- --]]]

Oye! What are those 1s doing in bands 2 and 3? Also, where is the other value of 2202 (relative to the reproject output)?
Let's see what comes out if we read from the VRT WITHOUT scaling, for the heck of it:

In [18]: with rasterio.open("resampled_2048th_min.vrt") as src:

    ...:     with WarpedVRT(src, resampling=Resampling.min) as vrt:

    ...:         res_vrt_16 = vrt.read([1, 2, 3], out_shape=(3, 16, 16), masked=True)

    ...: print(res_vrt_16)

[[[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2202 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 2202 2202]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2330 3258 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 1 1]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 1 1]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

 

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]]

The band 1 output looks fine, but bands 2 and 3 have those values of 1! Where did they come from?
Here is some further info for debugging:

 

daniel.mannarino$ gdalinfo -stats resampled_2048th_min.tif

Driver: GTiff/GeoTIFF

Files: resampled_2048th_min.tif

       resampled_2048th_min.tif.aux.xml

Size is 16, 16

Coordinate System is:

PROJCRS["WGS 84 / Pseudo-Mercator",

    BASEGEOGCRS["WGS 84",

        DATUM["World Geodetic System 1984",

            ELLIPSOID["WGS 84",6378137,298.257223563,

                LENGTHUNIT["metre",1]]],

        PRIMEM["Greenwich",0,

            ANGLEUNIT["degree",0.0174532925199433]],

        ID["EPSG",4326]],

    CONVERSION["Popular Visualisation Pseudo-Mercator",

        METHOD["Popular Visualisation Pseudo Mercator",

            ID["EPSG",1024]],

        PARAMETER["Latitude of natural origin",0,

            ANGLEUNIT["degree",0.0174532925199433],

            ID["EPSG",8801]],

        PARAMETER["Longitude of natural origin",0,

            ANGLEUNIT["degree",0.0174532925199433],

            ID["EPSG",8802]],

        PARAMETER["False easting",0,

            LENGTHUNIT["metre",1],

            ID["EPSG",8806]],

        PARAMETER["False northing",0,

            LENGTHUNIT["metre",1],

            ID["EPSG",8807]]],

    CS[Cartesian,2],

        AXIS["easting (X)",east,

            ORDER[1],

            LENGTHUNIT["metre",1]],

        AXIS["northing (Y)",north,

            ORDER[2],

            LENGTHUNIT["metre",1]],

    USAGE[

        SCOPE["Web mapping and visualisation."],

        AREA["World between 85.06°S and 85.06°N."],

        BBOX[-85.06,-180,85.06,180]],

    ID["EPSG",3857]]

Data axis to CRS axis mapping: 1,2

Origin = (-2504688.542848654091358,3757032.814319770783186)

Pixel Size = (39135.758482253979309,-39135.758482253979309)

Metadata:

  AREA_OR_POINT=Area

Image Structure Metadata:

  INTERLEAVE=PIXEL

Corner Coordinates:

Upper Left  (-2504688.543, 3757032.814) ( 22d30' 0.00"W, 31d57' 7.78"N)

Lower Left  (-2504688.543, 3130860.679) ( 22d30' 0.00"W, 27d 3'32.85"N)

Upper Right (-1878516.407, 3757032.814) ( 16d52'30.00"W, 31d57' 7.78"N)

Lower Right (-1878516.407, 3130860.679) ( 16d52'30.00"W, 27d 3'32.85"N)

Center      (-2191602.475, 3443946.746) ( 19d41'15.00"W, 29d32' 6.83"N)

Band 1 Block=16x16 Type=UInt16, ColorInterp=Gray

  Min=2202.000 Max=3258.000 

  Minimum=2202.000, Maximum=3258.000, Mean=2371.143, StdDev=364.742

  NoData Value=0

  Metadata:

    STATISTICS_MAXIMUM=3258

    STATISTICS_MEAN=2371.1428571429

    STATISTICS_MINIMUM=2202

    STATISTICS_STDDEV=364.74156352583

    STATISTICS_VALID_PERCENT=2.734

Band 2 Block=16x16 Type=UInt16, ColorInterp=Undefined

ERROR 1: resampled_2048th_min.tif, band 2: Failed to compute statistics, no valid pixels found in sampling.

  NoData Value=0

  Metadata:

    STATISTICS_VALID_PERCENT=0

Band 3 Block=16x16 Type=UInt16, ColorInterp=Undefined

ERROR 1: resampled_2048th_min.tif, band 3: Failed to compute statistics, no valid pixels found in sampling.

  NoData Value=0

  Metadata:

    STATISTICS_VALID_PERCENT=0

Any ideas? Happy to file a Github Issue or similar if people think it's a bug.
Thanks,
Daniel Mannarino



--
Sean Gillies


daniel.mannarino@...
 

Hi folks!

I have a 16x16 TIFF with 3 uint16 bands and no-data values of 0. There are a few non-no-data values in band 1, but bands 2 and 3 are all 0s (no-data). When I explicitly scale by 0.5 (i.e. effectively "zooming out" one zoom level) with rasterio.warp.reproject using either the "nearest" or "min" resampling method, the result is as expected. But when I implicitly scale by reading from a WarpedVRT with shape_out=(3, 8, 8) and resampling method "min", unexpected values of 1 appear in the the resulting bands 2 and 3. After further testing, it seems that they appear even when NOT scaling, reading into a shape_out of (3, 16, 16). This problem does not occur with a WarpedVRT and a resampling method of "nearest". Am I using the WarpedVRT incorrectly, or is this a bug?
The anomalous data was initially noticed in Linux with GDAL 3.2.0 but confirmed on MacOS Catalina with GDAL 3.2.0, 3.2.3 and 3.3.1 using rasterio 1.1.8, 1.2.3 and 1.2.6. Some commands and their output (performed with GDAL 3.3.1, rasterio 1.2.6 and Python 3.8.11):

In [1]: import rasterio

 

In [2]: res_file_16 = rasterio.open('resampled_2048th_min.tif')

 

In [3]: res_data_16 = res_file_16.read([1, 2, 3], masked=True)

 

In [4]: print(res_data_16)

[[[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2202 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 2202 2202]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2330 3258 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]]


In [6]: print(res_file_16.profile)

{'driver': 'GTiff', 'dtype': 'uint16', 'nodata': 0.0, 'width': 16, 'height': 16, 'count': 3, 'crs': CRS.from_epsg(3857), 'transform': Affine(39135.75848225398, 0.0, -2504688.542848654,

       0.0, -39135.75848225398, 3757032.814319771), 'blockxsize': 16, 'blockysize': 16, 'tiled': True, 'interleave': 'pixel'}


Now let's use reproject with resampling method "min" to scale by 0.5:

In [8]: import numpy as np

In [9]: from affine import Affine

In [10]: from rasterio.enums import Resampling

In [11]: from rasterio.warp import reproject

In [12]: dst = np.zeros((3, 8, 8))

    ...: dst_transform = res_file_16.transform * Affine.scale(0.5)

    ...: reproject(

    ...:     res_data_16,

    ...:     dst,

    ...:     src_transform=res_file_16.transform,

    ...:     src_crs=res_file_16.crs,

    ...:     dst_crs=res_file_16.crs,

    ...:     resampling=Resampling.min,

    ...:     src_nodata=0

    ...: )

Out[12]: 

(array([[[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0., 2202.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0., 2330., 2202.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]],

 

        [[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]],

 

        [[   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.],

         [   0.,    0.,    0.,    0.,    0.,    0.,    0.,    0.]]]),

 Affine(78271.51696450796, 0.0, -2504688.542848654,

        0.0, -78271.51696450796, 3757032.814319771))

Looks good! Exactly what I would hope for. A cluster of three 2202 values became one 2202, a cluster of two of them became one 2202, and the min of 
2330 and 3258 became 2330. And of course everything in bands 2 and 3 is still masked.
Now let's try making a VRT, creating a WarpedVRT on top of it, and reading into an out_shape of (3, 8, 8) to implicitly scale it:

daniel.mannarino$ gdalbuildvrt resampled_2048th_min.vrt resampled_2048th_min.tif

0...10...20...30...40...50...60...70...80...90...100 - done.


In [15]: from rasterio.vrt import WarpedVRT

In [16]: with rasterio.open("resampled_2048th_min.vrt") as src:

    ...:     with WarpedVRT(src, resampling=Resampling.min) as vrt:

    ...:         res_vrt_8 = vrt.read([1, 2, 3], out_shape=(3, 8, 8), masked=True)

    ...: 

 

In [17]: print(res_vrt_8)

[[[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 2202 --]

  [-- -- -- -- -- -- 3258 --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- 1 --]

  [-- -- -- -- -- -- -- --]]]

Oye! What are those 1s doing in bands 2 and 3? Also, where is the other value of 2202 (relative to the reproject output)?
Let's see what comes out if we read from the VRT WITHOUT scaling, for the heck of it:

In [18]: with rasterio.open("resampled_2048th_min.vrt") as src:

    ...:     with WarpedVRT(src, resampling=Resampling.min) as vrt:

    ...:         res_vrt_16 = vrt.read([1, 2, 3], out_shape=(3, 16, 16), masked=True)

    ...: print(res_vrt_16)

[[[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2202 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 2202 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 2202 2202]

  [-- -- -- -- -- -- -- -- -- -- -- -- 2330 3258 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 1 1]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]

 

 [[-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- 1 1]

  [-- -- -- -- -- -- -- -- -- -- -- -- 1 1 -- --]

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]

 

  [-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --]]]

The band 1 output looks fine, but bands 2 and 3 have those values of 1! Where did they come from?
Here is some further info for debugging:

 

daniel.mannarino$ gdalinfo -stats resampled_2048th_min.tif

Driver: GTiff/GeoTIFF

Files: resampled_2048th_min.tif

       resampled_2048th_min.tif.aux.xml

Size is 16, 16

Coordinate System is:

PROJCRS["WGS 84 / Pseudo-Mercator",

    BASEGEOGCRS["WGS 84",

        DATUM["World Geodetic System 1984",

            ELLIPSOID["WGS 84",6378137,298.257223563,

                LENGTHUNIT["metre",1]]],

        PRIMEM["Greenwich",0,

            ANGLEUNIT["degree",0.0174532925199433]],

        ID["EPSG",4326]],

    CONVERSION["Popular Visualisation Pseudo-Mercator",

        METHOD["Popular Visualisation Pseudo Mercator",

            ID["EPSG",1024]],

        PARAMETER["Latitude of natural origin",0,

            ANGLEUNIT["degree",0.0174532925199433],

            ID["EPSG",8801]],

        PARAMETER["Longitude of natural origin",0,

            ANGLEUNIT["degree",0.0174532925199433],

            ID["EPSG",8802]],

        PARAMETER["False easting",0,

            LENGTHUNIT["metre",1],

            ID["EPSG",8806]],

        PARAMETER["False northing",0,

            LENGTHUNIT["metre",1],

            ID["EPSG",8807]]],

    CS[Cartesian,2],

        AXIS["easting (X)",east,

            ORDER[1],

            LENGTHUNIT["metre",1]],

        AXIS["northing (Y)",north,

            ORDER[2],

            LENGTHUNIT["metre",1]],

    USAGE[

        SCOPE["Web mapping and visualisation."],

        AREA["World between 85.06°S and 85.06°N."],

        BBOX[-85.06,-180,85.06,180]],

    ID["EPSG",3857]]

Data axis to CRS axis mapping: 1,2

Origin = (-2504688.542848654091358,3757032.814319770783186)

Pixel Size = (39135.758482253979309,-39135.758482253979309)

Metadata:

  AREA_OR_POINT=Area

Image Structure Metadata:

  INTERLEAVE=PIXEL

Corner Coordinates:

Upper Left  (-2504688.543, 3757032.814) ( 22d30' 0.00"W, 31d57' 7.78"N)

Lower Left  (-2504688.543, 3130860.679) ( 22d30' 0.00"W, 27d 3'32.85"N)

Upper Right (-1878516.407, 3757032.814) ( 16d52'30.00"W, 31d57' 7.78"N)

Lower Right (-1878516.407, 3130860.679) ( 16d52'30.00"W, 27d 3'32.85"N)

Center      (-2191602.475, 3443946.746) ( 19d41'15.00"W, 29d32' 6.83"N)

Band 1 Block=16x16 Type=UInt16, ColorInterp=Gray

  Min=2202.000 Max=3258.000 

  Minimum=2202.000, Maximum=3258.000, Mean=2371.143, StdDev=364.742

  NoData Value=0

  Metadata:

    STATISTICS_MAXIMUM=3258

    STATISTICS_MEAN=2371.1428571429

    STATISTICS_MINIMUM=2202

    STATISTICS_STDDEV=364.74156352583

    STATISTICS_VALID_PERCENT=2.734

Band 2 Block=16x16 Type=UInt16, ColorInterp=Undefined

ERROR 1: resampled_2048th_min.tif, band 2: Failed to compute statistics, no valid pixels found in sampling.

  NoData Value=0

  Metadata:

    STATISTICS_VALID_PERCENT=0

Band 3 Block=16x16 Type=UInt16, ColorInterp=Undefined

ERROR 1: resampled_2048th_min.tif, band 3: Failed to compute statistics, no valid pixels found in sampling.

  NoData Value=0

  Metadata:

    STATISTICS_VALID_PERCENT=0

Any ideas? Happy to file a Github Issue or similar if people think it's a bug.
Thanks,
Daniel Mannarino