#!/usr/bin/env pytest # -*- coding: utf-8 -*- ############################################################################### # $Id$ # # Project: GDAL/OGR Test Suite # Purpose: Test core numeric operations and statistics calculations # Author: Mateusz Loskot # ############################################################################### # Copyright (c) 2007, Mateusz Loskot # Copyright (c) 2009-2012, Even Rouault # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. ############################################################################### import math import os import shutil import struct import gdaltest import pytest from osgeo import gdal ############################################################################### # Test handling NaN with GDT_Float32 data def test_stats_nan_1(): gdaltest.gtiff_drv = gdal.GetDriverByName("GTiff") if gdaltest.gtiff_drv is None: pytest.skip() stats = (50.0, 58.0, 54.0, 2.5819888974716) shutil.copyfile("data/nan32.tif", "tmp/nan32.tif") t = gdaltest.GDALTest("GTiff", "tmp/nan32.tif", 1, 874, filename_absolute=1) ret = t.testOpen(check_approx_stat=stats, check_stat=stats) gdal.GetDriverByName("GTiff").Delete("tmp/nan32.tif") return ret ############################################################################### # Test handling NaN with GDT_Float64 data def test_stats_nan_2(): if gdaltest.gtiff_drv is None: pytest.skip() stats = (50.0, 58.0, 54.0, 2.5819888974716) shutil.copyfile("data/nan64.tif", "tmp/nan64.tif") t = gdaltest.GDALTest("GTiff", "tmp/nan64.tif", 1, 4414, filename_absolute=1) ret = t.testOpen(check_approx_stat=stats, check_stat=stats) gdal.GetDriverByName("GTiff").Delete("tmp/nan64.tif") return ret ############################################################################### # Test stats on signed byte (#3151) def test_stats_signedbyte(): if gdaltest.gtiff_drv is None: pytest.skip() stats = (-128.0, 127.0, -0.2, 80.64) shutil.copyfile("data/stats_signed_byte.img", "tmp/stats_signed_byte.img") t = gdaltest.GDALTest( "HFA", "tmp/stats_signed_byte.img", 1, 11, filename_absolute=1 ) ret = t.testOpen(check_approx_stat=stats, check_stat=stats, skip_checksum=1) gdal.GetDriverByName("HFA").Delete("tmp/stats_signed_byte.img") return ret ############################################################################### # Test return of GetStatistics() when we don't have stats and don't # force their computation (#3572) def test_stats_dont_force(): if os.path.exists("data/byte.tif.aux.xml"): gdal.Unlink("data/byte.tif.aux.xml") ds = gdal.Open("data/byte.tif") stats = ds.GetRasterBand(1).GetStatistics(0, 0) assert stats == [0, 0, 0, -1], "did not get expected stats" ############################################################################### # Test statistics when stored nodata value doesn't accurately match the nodata # value used in the imagery (#3573) def test_stats_approx_nodata(): shutil.copyfile("data/minfloat.tif", "tmp/minfloat.tif") try: os.remove("tmp/minfloat.tif.aux.xml") except OSError: pass ds = gdal.Open("tmp/minfloat.tif") stats = ds.GetRasterBand(1).GetStatistics(0, 1) md = ds.GetRasterBand(1).GetMetadata() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None os.remove("tmp/minfloat.tif.aux.xml") ds = gdal.Open("tmp/minfloat.tif") minmax = ds.GetRasterBand(1).ComputeRasterMinMax() ds = None os.remove("tmp/minfloat.tif") if nodata != -3.4028234663852886e38: print("%.18g" % nodata) pytest.fail("did not get expected nodata") assert stats == [-3.0, 5.0, 1.0, 4.0], "did not get expected stats" assert md == { "STATISTICS_MEAN": "1", "STATISTICS_MAXIMUM": "5", "STATISTICS_MINIMUM": "-3", "STATISTICS_STDDEV": "4", "STATISTICS_VALID_PERCENT": "50", }, "did not get expected metadata" assert minmax == (-3.0, 5.0), "did not get expected minmax" ############################################################################### # Test read and copy of dataset with nan as nodata value (#3576) def test_stats_nan_3(): src_ds = gdal.Open("data/nan32_nodata.tif") nodata = src_ds.GetRasterBand(1).GetNoDataValue() assert gdaltest.isnan(nodata), "expected nan, got %f" % nodata out_ds = gdaltest.gtiff_drv.CreateCopy("tmp/nan32_nodata.tif", src_ds) del out_ds src_ds = None try: os.remove("tmp/nan32_nodata.tif.aux.xml") except OSError: pass ds = gdal.Open("tmp/nan32_nodata.tif") nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None gdaltest.gtiff_drv.Delete("tmp/nan32_nodata.tif") assert gdaltest.isnan(nodata), "expected nan, got %f" % nodata ############################################################################### # Test reading a VRT with a complex source that define nan as band nodata # and complex source nodata (#3576) def test_stats_nan_4(): ds = gdal.Open("data/nan32_nodata.vrt") cs = ds.GetRasterBand(1).Checksum() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert cs == 874, "did not get expected checksum" assert gdaltest.isnan(nodata), "expected nan, got %f" % nodata ############################################################################### # Test reading a VRT with a complex source that define 0 as band nodata # and complex source nodata (nan must be translated to 0 then) (#3576) def test_stats_nan_5(): ds = gdal.Open("data/nan32_nodata_nan_to_zero.vrt") cs = ds.GetRasterBand(1).Checksum() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert cs == 978, "did not get expected checksum" assert nodata == 0, "expected nan, got %f" % nodata ############################################################################### # Test reading a warped VRT with nan as src nodata and dest nodata (#3576) def test_stats_nan_6(): ds = gdal.Open("data/nan32_nodata_warp.vrt") cs = ds.GetRasterBand(1).Checksum() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert cs == 874, "did not get expected checksum" assert gdaltest.isnan(nodata), "expected nan, got %f" % nodata ############################################################################### # Test reading a warped VRT with nan as src nodata and 0 as dest nodata (#3576) def test_stats_nan_7(): ds = gdal.Open("data/nan32_nodata_warp_nan_to_zero.vrt") cs = ds.GetRasterBand(1).Checksum() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert cs == 978, "did not get expected checksum" assert nodata == 0, "expected nan, got %f" % nodata ############################################################################### # Test reading a warped VRT with zero as src nodata and nan as dest nodata (#3576) def test_stats_nan_8(): ds = gdal.Open("data/nan32_nodata_warp_zero_to_nan.vrt") cs = ds.GetRasterBand(1).Checksum() nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert cs == 874, "did not get expected checksum" assert gdaltest.isnan(nodata), "expected nan, got %f" % nodata ############################################################################### # Test statistics computation when nodata = +/- inf def stats_nodata_inf_progress_cbk(value, string, extra): # pylint: disable=unused-argument extra[0] = value def test_stats_nodata_inf(): ds = gdal.GetDriverByName("HFA").Create( "/vsimem/stats_nodata_inf.img", 3, 1, 1, gdal.GDT_Float32 ) ds.GetRasterBand(1).SetNoDataValue(gdaltest.neginf()) ds.GetRasterBand(1).WriteRaster( 0, 0, 1, 1, struct.pack("f", gdaltest.neginf()), buf_type=gdal.GDT_Float32 ) ds.GetRasterBand(1).WriteRaster( 1, 0, 1, 1, struct.pack("f", 1), buf_type=gdal.GDT_Float32 ) ds.GetRasterBand(1).WriteRaster( 2, 0, 1, 1, struct.pack("f", -2), buf_type=gdal.GDT_Float32 ) ds.GetRasterBand(1).Checksum() user_data = [0] stats = ds.GetRasterBand(1).ComputeStatistics( False, stats_nodata_inf_progress_cbk, user_data ) assert user_data[0] == 1.0, "did not get expected pct" ds = None gdal.GetDriverByName("HFA").Delete("/vsimem/stats_nodata_inf.img") assert stats == [-2.0, 1.0, -0.5, 1.5], "did not get expected stats" ############################################################################### # Test deserialization of +inf/-inf values written by Linux and Windows def stats_nodata_check(filename, expected_nodata): ds = gdal.Open(filename) nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None assert nodata == expected_nodata, "did not get expected nodata value" def test_stats_nodata_neginf_linux(): return stats_nodata_check("data/stats_nodata_neginf.tif", gdaltest.neginf()) def test_stats_nodata_neginf_msvc(): return stats_nodata_check("data/stats_nodata_neginf_msvc.tif", gdaltest.neginf()) def test_stats_nodata_posinf_linux(): return stats_nodata_check("data/stats_nodata_posinf.tif", gdaltest.posinf()) def test_stats_nodata_posinf_msvc(): return stats_nodata_check("data/stats_nodata_posinf_msvc.tif", gdaltest.posinf()) ############################################################################### # Test standard deviation computation on huge values @pytest.mark.require_driver("AAIGRID") def test_stats_stddev_huge_values(): gdal.FileFromMemBuffer( "/vsimem/stats_stddev_huge_values.asc", """ncols 4 nrows 4 xllcorner 0 yllcorner 0 cellsize 1 100000000 100000002 100000000 100000002 100000000 100000002 100000000 100000002 100000000 100000002 100000000 100000002 100000000 100000002 100000000 100000002""", ) ds = gdal.Open("/vsimem/stats_stddev_huge_values.asc") stats = ds.GetRasterBand(1).ComputeStatistics(0) assert stats == [ 100000000.0, 100000002.0, 100000001.0, 1.0, ], "did not get expected stats" ds = None gdal.GetDriverByName("AAIGRID").Delete("/vsimem/stats_stddev_huge_values.asc") ############################################################################### # Test approximate statistics computation on a square shaped raster whose first column # of blocks is nodata only def test_stats_square_shape(): ds = gdal.GetDriverByName("GTiff").Create( "/vsimem/stats_square_shape.tif", 32, 32, options=["TILED=YES", "BLOCKXSIZE=16", "BLOCKYSIZE=16"], ) ds.GetRasterBand(1).SetNoDataValue(0) ds.GetRasterBand(1).WriteRaster( 16, 0, 16, 32, struct.pack("B" * 1, 255), buf_xsize=1, buf_ysize=1 ) stats = ds.GetRasterBand(1).ComputeStatistics(True) hist = ds.GetRasterBand(1).GetHistogram(approx_ok=1) minmax = ds.GetRasterBand(1).ComputeRasterMinMax(1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_square_shape.tif") assert stats == [255, 255, 255, 0], "did not get expected stats" assert hist[255] == 16 * 16, "did not get expected histogram" if minmax != (255, 255): print(hist) pytest.fail("did not get expected minmax") ############################################################################### # Test when nodata = FLT_MIN (#6578) def test_stats_flt_min(): shutil.copyfile("data/flt_min.tif", "tmp/flt_min.tif") try: os.remove("tmp/flt_min.tif.aux.xml") except OSError: pass ds = gdal.Open("tmp/flt_min.tif") stats = ds.GetRasterBand(1).GetStatistics(0, 1) nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None os.remove("tmp/flt_min.tif.aux.xml") ds = gdal.Open("tmp/flt_min.tif") minmax = ds.GetRasterBand(1).ComputeRasterMinMax() ds = None os.remove("tmp/flt_min.tif") if nodata != 1.17549435082228751e-38: print("%.18g" % nodata) pytest.fail("did not get expected nodata") assert stats == [0.0, 1.0, 0.33333333333333337, 0.47140452079103168] or stats == [ 0.0, 1.0, 0.33333333333333331, 0.47140452079103168, ], "did not get expected stats" assert minmax == (0.0, 1.0), "did not get expected minmax" ############################################################################### # Test when nodata = DBL_MIN (#6578) def test_stats_dbl_min(): shutil.copyfile("data/dbl_min.tif", "tmp/dbl_min.tif") try: os.remove("tmp/dbl_min.tif.aux.xml") except OSError: pass ds = gdal.Open("tmp/dbl_min.tif") stats = ds.GetRasterBand(1).GetStatistics(0, 1) nodata = ds.GetRasterBand(1).GetNoDataValue() ds = None os.remove("tmp/dbl_min.tif.aux.xml") ds = gdal.Open("tmp/dbl_min.tif") minmax = ds.GetRasterBand(1).ComputeRasterMinMax() ds = None os.remove("tmp/dbl_min.tif") if nodata != 2.22507385850720138e-308: print("%.18g" % nodata) pytest.fail("did not get expected nodata") assert stats == [0.0, 1.0, 0.33333333333333337, 0.47140452079103168] or stats == [ 0.0, 1.0, 0.33333333333333331, 0.47140452079103168, ], "did not get expected stats" assert minmax == (0.0, 1.0), "did not get expected minmax" ############################################################################### # Test stats on a tiled Byte with partial tiles def test_stats_byte_partial_tiles(): ds = gdal.Translate( "/vsimem/stats_byte_tiled.tif", "../gdrivers/data/small_world.tif", creationOptions=["TILED=YES", "BLOCKXSIZE=64", "BLOCKYSIZE=64"], ) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_byte_tiled.tif") expected_stats = [0.0, 255.0, 50.22115, 67.119029288849973] assert stats == expected_stats, "did not get expected stats" # Same but with nodata set ds = gdal.Translate( "/vsimem/stats_byte_tiled.tif", "../gdrivers/data/small_world.tif", creationOptions=["TILED=YES", "BLOCKXSIZE=64", "BLOCKYSIZE=64"], ) ds.GetRasterBand(1).SetNoDataValue(0) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_byte_tiled.tif") expected_stats = [1.0, 255.0, 50.311081057390084, 67.14541389488096] assert stats == pytest.approx( expected_stats, rel=1e-10 ), "did not get expected stats" # Same but with nodata set but untiled and with non power of 16 block size ds = gdal.Translate( "/vsimem/stats_byte_untiled.tif", "../gdrivers/data/small_world.tif", options="-srcwin 0 0 399 200", ) ds.GetRasterBand(1).SetNoDataValue(0) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_byte_untiled.tif") expected_stats = [1.0, 255.0, 50.378183963744554, 67.184793517649453] assert stats == pytest.approx( expected_stats, rel=1e-10 ), "did not get expected stats" ds = gdal.GetDriverByName("GTiff").Create( "/vsimem/stats_byte_tiled.tif", 1000, 512, options=["TILED=YES", "BLOCKXSIZE=512", "BLOCKYSIZE=512"], ) ds.GetRasterBand(1).Fill(255) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.Unlink("/vsimem/stats_byte_tiled.tif") expected_stats = [255.0, 255.0, 255.0, 0.0] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" # Non optimized code path ds = gdal.GetDriverByName("MEM").Create("", 1, 1) ds.GetRasterBand(1).WriteRaster(0, 0, 1, 1, struct.pack("B" * 1, 1)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [1.0, 1.0, 1.0, 0.0] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ds = gdal.GetDriverByName("MEM").Create("", 3, 5) ds.GetRasterBand(1).WriteRaster(0, 0, 3, 1, struct.pack("B" * 3, 20, 30, 50)) ds.GetRasterBand(1).WriteRaster(0, 1, 3, 1, struct.pack("B" * 3, 60, 10, 5)) ds.GetRasterBand(1).WriteRaster(0, 2, 3, 1, struct.pack("B" * 3, 10, 20, 0)) ds.GetRasterBand(1).WriteRaster(0, 3, 3, 1, struct.pack("B" * 3, 10, 20, 255)) ds.GetRasterBand(1).WriteRaster(0, 4, 3, 1, struct.pack("B" * 3, 10, 20, 10)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 255.0, 35.333333333333336, 60.785597709398971] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ds = gdal.GetDriverByName("MEM").Create("", 32 + 2, 2) ds.GetRasterBand(1).Fill(1) ds.GetRasterBand(1).WriteRaster(32, 1, 2, 1, struct.pack("B" * 2, 0, 255)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 255.0, 4.7205882352941178, 30.576733555893391] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ds = gdal.GetDriverByName("MEM").Create("", 32 + 2, 2) ds.GetRasterBand(1).Fill(1) ds.GetRasterBand(1).SetNoDataValue(2) ds.GetRasterBand(1).WriteRaster(32, 1, 2, 1, struct.pack("B" * 2, 0, 255)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 255.0, 4.7205882352941178, 30.576733555893391] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ############################################################################### # Test stats on uint16 def test_stats_uint16(): ds = gdal.Translate( "/vsimem/stats_uint16_tiled.tif", "../gdrivers/data/small_world.tif", outputType=gdal.GDT_UInt16, scaleParams=[[0, 255, 0, 65535]], creationOptions=["TILED=YES", "BLOCKXSIZE=64", "BLOCKYSIZE=64"], ) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_uint16_tiled.tif") expected_stats = [ 0.0, 65535.0, 50.22115 * 65535 / 255, 67.119029288849973 * 65535 / 255, ] assert stats == expected_stats, "did not get expected stats" ds = gdal.Translate( "/vsimem/stats_uint16_untiled.tif", "../gdrivers/data/small_world.tif", options="-srcwin 0 0 399 200 -scale 0 255 0 65535 -ot UInt16", ) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_uint16_untiled.tif") expected_stats = [0.0, 65535.0, 12923.9921679198, 17259.703026841547] assert stats == expected_stats, "did not get expected stats" # Same but with nodata set but untiled and with non power of 16 block size ds = gdal.Translate( "/vsimem/stats_uint16_untiled.tif", "../gdrivers/data/small_world.tif", options="-srcwin 0 0 399 200 -scale 0 255 0 65535 -ot UInt16", ) ds.GetRasterBand(1).SetNoDataValue(0) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.GetDriverByName("GTiff").Delete("/vsimem/stats_uint16_untiled.tif") expected_stats = [ 257.0, 65535.0, 50.378183963744554 * 65535 / 255, 67.184793517649453 * 65535 / 255, ] assert stats == pytest.approx( expected_stats, rel=1e-10 ), "did not get expected stats" for fill_val in [0, 1, 32767, 32768, 65535]: ds = gdal.GetDriverByName("GTiff").Create( "/vsimem/stats_uint16_tiled.tif", 1000, 512, 1, gdal.GDT_UInt16, options=["TILED=YES", "BLOCKXSIZE=512", "BLOCKYSIZE=512"], ) ds.GetRasterBand(1).Fill(fill_val) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None gdal.Unlink("/vsimem/stats_uint16_tiled.tif") expected_stats = [fill_val, fill_val, fill_val, 0.0] if max([abs(stats[i] - expected_stats[i]) for i in range(4)]) > 1e-15: print(fill_val) pytest.fail("did not get expected stats") # Test remaining pixels after multiple of 32 ds = gdal.GetDriverByName("MEM").Create("", 32 + 2, 1, 1, gdal.GDT_UInt16) ds.GetRasterBand(1).Fill(1) ds.GetRasterBand(1).WriteRaster(32, 0, 2, 1, struct.pack("H" * 2, 0, 65535)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 65535.0, 1928.4411764705883, 11072.48066469611] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" # Non optimized code path for fill_val in [0, 1, 32767, 32768, 65535]: ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 1, gdal.GDT_UInt16) ds.GetRasterBand(1).WriteRaster(0, 0, 1, 1, struct.pack("H" * 1, fill_val)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [fill_val, fill_val, fill_val, 0.0] if max([abs(stats[i] - expected_stats[i]) for i in range(4)]) > 1e-15: print(fill_val) pytest.fail("did not get expected stats") ds = gdal.GetDriverByName("MEM").Create("", 3, 5, 1, gdal.GDT_UInt16) ds.GetRasterBand(1).WriteRaster(0, 0, 3, 1, struct.pack("H" * 3, 20, 30, 50)) ds.GetRasterBand(1).WriteRaster(0, 1, 3, 1, struct.pack("H" * 3, 60, 10, 5)) ds.GetRasterBand(1).WriteRaster(0, 2, 3, 1, struct.pack("H" * 3, 10, 20, 0)) ds.GetRasterBand(1).WriteRaster(0, 3, 3, 1, struct.pack("H" * 3, 10, 20, 65535)) ds.GetRasterBand(1).WriteRaster(0, 4, 3, 1, struct.pack("H" * 3, 10, 20, 10)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 65535.0, 4387.333333333333, 16342.408927558861] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ds = gdal.GetDriverByName("MEM").Create("", 2, 2, 1, gdal.GDT_UInt16) ds.GetRasterBand(1).WriteRaster(0, 0, 2, 1, struct.pack("H" * 2, 0, 65535)) ds.GetRasterBand(1).WriteRaster(0, 1, 2, 1, struct.pack("H" * 2, 1, 65534)) stats = ds.GetRasterBand(1).GetStatistics(0, 1) ds = None expected_stats = [0.0, 65535.0, 32767.5, 32767.000003814814] assert ( max([abs(stats[i] - expected_stats[i]) for i in range(4)]) <= 1e-15 ), "did not get expected stats" ############################################################################### # Test a case where the nodata value is almost the maximum value of float32 def test_stats_nodata_almost_max_float32(): gdal.FileFromMemBuffer( "/vsimem/float32_almost_nodata_max_float32.tif", open("data/float32_almost_nodata_max_float32.tif", "rb").read(), ) ds = gdal.Open("/vsimem/float32_almost_nodata_max_float32.tif") minmax = ds.GetRasterBand(1).ComputeRasterMinMax() assert minmax == (0, 0), "did not get expected minmax" stats = ds.GetRasterBand(1).ComputeStatistics(False) assert stats == [0, 0, 0, 0], "did not get expected stats" hist = ds.GetRasterBand(1).GetHistogram(approx_ok=0) assert hist[0] == 3, "did not get expected hist" ds = None gdal.GetDriverByName("GTiff").Delete( "/vsimem/float32_almost_nodata_max_float32.tif" ) ############################################################################### # Test STATISTICS_APPROXIMATE def test_stats_approx_stats_flag(dt=gdal.GDT_Byte, struct_frmt="B"): ds = gdal.GetDriverByName("MEM").Create("", 2000, 2000, 1, dt) ds.GetRasterBand(1).WriteRaster(1000, 1000, 1, 1, struct.pack(struct_frmt * 1, 20)) approx_ok = 1 force = 1 stats = ds.GetRasterBand(1).GetStatistics(approx_ok, force) assert stats == [0.0, 0.0, 0.0, 0.0], "did not get expected stats" md = ds.GetRasterBand(1).GetMetadata() assert md == { "STATISTICS_MEAN": "0", "STATISTICS_MAXIMUM": "0", "STATISTICS_MINIMUM": "0", "STATISTICS_APPROXIMATE": "YES", "STATISTICS_STDDEV": "0", "STATISTICS_VALID_PERCENT": "100", }, "did not get expected metadata" approx_ok = 0 force = 0 stats = ds.GetRasterBand(1).GetStatistics(approx_ok, force) assert stats == [0.0, 0.0, 0.0, -1.0], "did not get expected stats" approx_ok = 0 force = 1 stats = ds.GetRasterBand(1).GetStatistics(approx_ok, force) assert stats[1] == 20.0, "did not get expected stats" md = ds.GetRasterBand(1).GetMetadata() assert "STATISTICS_APPROXIMATE" not in md, "did not get expected metadata" def test_stats_approx_stats_flag_float(): return test_stats_approx_stats_flag(dt=gdal.GDT_Float32, struct_frmt="f") def test_stats_all_nodata(): ds = gdal.GetDriverByName("MEM").Create("", 2000, 2000) ds.GetRasterBand(1).SetNoDataValue(0) with gdaltest.disable_exceptions(), gdaltest.error_handler(): minmax = ds.GetRasterBand(1).ComputeRasterMinMax() assert math.isnan(minmax[0]) assert math.isnan(minmax[1]) with pytest.raises(Exception): ds.GetRasterBand(1).ComputeRasterMinMax() with pytest.raises(Exception): ds.GetRasterBand(1).ComputeRasterMinMax(can_return_none=True) with pytest.raises(Exception): # can_return_null also accepted for similarity with other methods ds.GetRasterBand(1).ComputeRasterMinMax(can_return_null=True) approx_ok = 1 force = 1 with pytest.raises(Exception): ds.GetRasterBand(1).GetStatistics(approx_ok, force) ds = gdal.GetDriverByName("MEM").Create("", 2000, 2000, 1, gdal.GDT_Float32) ds.GetRasterBand(1).SetNoDataValue(0) approx_ok = 1 force = 1 with pytest.raises(Exception): ds.GetRasterBand(1).GetStatistics(approx_ok, force) def test_stats_float32_with_nodata_slightly_above_float_max(): ds = gdal.Open("data/float32_with_nodata_slightly_above_float_max.tif") my_min, my_max = ds.GetRasterBand(1).ComputeRasterMinMax() assert (my_min, my_max) == ( -1.0989999771118164, 0.703338623046875, ), "did not get expected stats" def test_stats_clear(): filename = "/vsimem/out.tif" gdal.Translate(filename, "data/byte.tif") ds = gdal.Open(filename) assert ds.GetRasterBand(1).GetStatistics(False, False) == [0, 0, 0, -1] assert ds.GetRasterBand(1).ComputeStatistics(False) != [0, 0, 0, -1] ds = gdal.Open(filename) assert ds.GetRasterBand(1).GetStatistics(False, False) != [0, 0, 0, -1] ds.ClearStatistics() ds = gdal.Open(filename) assert ds.GetRasterBand(1).GetStatistics(False, False) == [0, 0, 0, -1] gdal.GetDriverByName("GTiff").Delete(filename) @pytest.mark.parametrize( "datatype,minval,maxval", [ (gdal.GDT_Byte, 1, 254), (gdal.GDT_Byte, -127, 127), (gdal.GDT_UInt16, 1, 65535), (gdal.GDT_Int16, -32767, 32766), (gdal.GDT_UInt32, 1, (1 << 32) - 2), (gdal.GDT_Int32, -(1 << 31) + 1, (1 << 31) - 2), (gdal.GDT_UInt64, 1, (1 << 53) - 2), (gdal.GDT_Int64, -(1 << 53) + 2, (1 << 53) - 2), ( gdal.GDT_Float32, -struct.unpack("f", struct.pack("f", 1e20))[0], struct.unpack("f", struct.pack("f", 1e20))[0], ), (gdal.GDT_Float64, -1e100, 1e100), (gdal.GDT_CInt16, -32767, 32766), (gdal.GDT_CInt32, -(1 << 31) + 1, (1 << 31) - 2), ( gdal.GDT_CFloat32, -struct.unpack("f", struct.pack("f", 1e20))[0], struct.unpack("f", struct.pack("f", 1e20))[0], ), (gdal.GDT_CFloat64, -1e100, 1e100), ], ) @pytest.mark.parametrize("nodata", [None, 0, 1]) def test_stats_computeminmax(datatype, minval, maxval, nodata): ds = gdal.GetDriverByName("MEM").Create("", 64, 1, 1, datatype) minval_mod = minval expected_minval = minval if datatype == gdal.GDT_Byte and minval < 0: ds.GetRasterBand(1).SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" ) minval_mod = 256 + minval if nodata: ds.GetRasterBand(1).SetNoDataValue(nodata) if nodata == 1 and minval == 1: expected_minval = maxval ds.GetRasterBand(1).WriteRaster( 0, 0, 64, 1, struct.pack("d" * 2, minval_mod, maxval), buf_type=gdal.GDT_Float64, buf_xsize=2, buf_ysize=1, ) assert ds.GetRasterBand(1).ComputeRasterMinMax(0) == (expected_minval, maxval) ############################################################################### # Test statistics on band with mask band def test_stats_mask_band(): src_ds = gdal.GetDriverByName("MEM").Create("", 3, 1, 1, gdal.GDT_Int16) src_ds.WriteRaster(0, 0, 3, 1, struct.pack("h" * 3, 1, 2, 3)) src_ds.CreateMaskBand(gdal.GMF_PER_DATASET) mask_band = src_ds.GetRasterBand(1).GetMaskBand() mask_band.WriteRaster(0, 0, 3, 1, struct.pack("B" * 3, 0, 255, 255)) assert src_ds.GetRasterBand(1).ComputeRasterMinMax(False) == (2, 3) assert src_ds.GetRasterBand(1).ComputeStatistics(False) == [2, 3, 2.5, 0.5] assert src_ds.GetRasterBand(1).GetHistogram(False) == [0, 0, 1, 1] + ([0] * 252)