Skip to content

Commit

Permalink
Add GDALRasterComputeMinMaxLocation / GDALRasterBand::ComputeMinMaxLo…
Browse files Browse the repository at this point in the history
…cation, and map it to SWIG

and add a gdal_minmax_location.py script:

```
$ python ../swig/python/gdal-utils/osgeo_utils/samples/gdal_minmax_location.py byte.tif
Minimum=74.0 at (col,line)=(9,17), (X,Y)_georef=(441290.0,3750270.0), (long,lat)_WGS84=(-117.6358076,33.8929309)
Maximum=255.0 at (col,line)=(2,18), (X,Y)_georef=(440870.0,3750210.0), (long,lat)_WGS84=(-117.6403456,33.8923662)
```
  • Loading branch information
rouault committed Nov 3, 2024
1 parent 14c25cd commit 58d4d3e
Show file tree
Hide file tree
Showing 9 changed files with 638 additions and 0 deletions.
139 changes: 139 additions & 0 deletions autotest/cpp/test_gdal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4777,4 +4777,143 @@ TEST_F(test_gdal, ReadRaster)
}
}

// Test GDALComputeRasterMinMaxLocation
TEST_F(test_gdal, GDALComputeRasterMinMaxLocation)
{
GDALDatasetH hDS = GDALOpen(GCORE_DATA_DIR "byte.tif", GA_ReadOnly);
ASSERT_NE(hDS, nullptr);
GDALRasterBandH hBand = GDALGetRasterBand(hDS, 1);
{
double dfMin = 0;
double dfMax = 0;
int nMinX = -1;
int nMinY = -1;
int nMaxX = -1;
int nMaxY = -1;
EXPECT_EQ(GDALComputeRasterMinMaxLocation(hBand, &dfMin, &dfMax, &nMinX,
&nMinY, &nMaxX, &nMaxY),
CE_None);
EXPECT_EQ(dfMin, 74.0);
EXPECT_EQ(dfMax, 255.0);
EXPECT_EQ(nMinX, 9);
EXPECT_EQ(nMinY, 17);
EXPECT_EQ(nMaxX, 2);
EXPECT_EQ(nMaxY, 18);
GByte val = 0;
EXPECT_EQ(GDALRasterIO(hBand, GF_Read, nMinX, nMinY, 1, 1, &val, 1, 1,
GDT_Byte, 0, 0),
CE_None);
EXPECT_EQ(val, 74);
EXPECT_EQ(GDALRasterIO(hBand, GF_Read, nMaxX, nMaxY, 1, 1, &val, 1, 1,
GDT_Byte, 0, 0),
CE_None);
EXPECT_EQ(val, 255);
}
{
int nMinX = -1;
int nMinY = -1;
EXPECT_EQ(GDALComputeRasterMinMaxLocation(hBand, nullptr, nullptr,
&nMinX, &nMinY, nullptr,
nullptr),
CE_None);
EXPECT_EQ(nMinX, 9);
EXPECT_EQ(nMinY, 17);
}
{
int nMaxX = -1;
int nMaxY = -1;
EXPECT_EQ(GDALComputeRasterMinMaxLocation(hBand, nullptr, nullptr,
nullptr, nullptr, &nMaxX,
&nMaxY),
CE_None);
EXPECT_EQ(nMaxX, 2);
EXPECT_EQ(nMaxY, 18);
}
{
EXPECT_EQ(GDALComputeRasterMinMaxLocation(hBand, nullptr, nullptr,
nullptr, nullptr, nullptr,
nullptr),
CE_None);
}
GDALClose(hDS);
}

// Test GDALComputeRasterMinMaxLocation
TEST_F(test_gdal, GDALComputeRasterMinMaxLocation_byte_min_max_optim)
{
GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
->Create("", 1, 4, 1, GDT_Byte, nullptr));
std::array<uint8_t, 4> buffer = {
1, //////////////////////////////////////////////////////////
0, //////////////////////////////////////////////////////////
255, //////////////////////////////////////////////////////////
1, //////////////////////////////////////////////////////////
};
GDALRasterIOExtraArg sExtraArg;
INIT_RASTERIO_EXTRA_ARG(sExtraArg);
EXPECT_EQ(poDS->GetRasterBand(1)->RasterIO(
GF_Write, 0, 0, 1, 4, buffer.data(), 1, 4, GDT_Byte,
sizeof(uint8_t), 1 * sizeof(uint8_t), &sExtraArg),
CE_None);

double dfMin = 0;
double dfMax = 0;
int nMinX = -1;
int nMinY = -1;
int nMaxX = -1;
int nMaxY = -1;
EXPECT_EQ(poDS->GetRasterBand(1)->ComputeRasterMinMaxLocation(
&dfMin, &dfMax, &nMinX, &nMinY, &nMaxX, &nMaxY),
CE_None);
EXPECT_EQ(dfMin, 0);
EXPECT_EQ(dfMax, 255);
EXPECT_EQ(nMinX, 0);
EXPECT_EQ(nMinY, 1);
EXPECT_EQ(nMaxX, 0);
EXPECT_EQ(nMaxY, 2);
}

// Test GDALComputeRasterMinMaxLocation
TEST_F(test_gdal, GDALComputeRasterMinMaxLocation_with_mask)
{
GDALDatasetUniquePtr poDS(GDALDriver::FromHandle(GDALGetDriverByName("MEM"))
->Create("", 2, 2, 1, GDT_Byte, nullptr));
std::array<uint8_t, 6> buffer = {
2, 10, //////////////////////////////////////////////////////////
4, 20, //////////////////////////////////////////////////////////
};
GDALRasterIOExtraArg sExtraArg;
INIT_RASTERIO_EXTRA_ARG(sExtraArg);
EXPECT_EQ(poDS->GetRasterBand(1)->RasterIO(
GF_Write, 0, 0, 2, 2, buffer.data(), 2, 2, GDT_Byte,
sizeof(uint8_t), 2 * sizeof(uint8_t), &sExtraArg),
CE_None);

poDS->GetRasterBand(1)->CreateMaskBand(0);
std::array<uint8_t, 6> buffer_mask = {
0, 255, //////////////////////////////////////////////////////////
255, 0, //////////////////////////////////////////////////////////
};
EXPECT_EQ(poDS->GetRasterBand(1)->GetMaskBand()->RasterIO(
GF_Write, 0, 0, 2, 2, buffer_mask.data(), 2, 2, GDT_Byte,
sizeof(uint8_t), 2 * sizeof(uint8_t), &sExtraArg),
CE_None);

double dfMin = 0;
double dfMax = 0;
int nMinX = -1;
int nMinY = -1;
int nMaxX = -1;
int nMaxY = -1;
EXPECT_EQ(poDS->GetRasterBand(1)->ComputeRasterMinMaxLocation(
&dfMin, &dfMax, &nMinX, &nMinY, &nMaxX, &nMaxY),
CE_None);
EXPECT_EQ(dfMin, 4);
EXPECT_EQ(dfMax, 10);
EXPECT_EQ(nMinX, 0);
EXPECT_EQ(nMinY, 1);
EXPECT_EQ(nMaxX, 1);
EXPECT_EQ(nMaxY, 0);
}

} // namespace
19 changes: 19 additions & 0 deletions autotest/gcore/basic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,3 +987,22 @@ def test_colorinterp():
assert name not in d
d[name] = c
assert gdal.GetColorInterpretationByName(name) == c


def test_ComputeMinMaxLocation():

ds = gdal.Open("data/byte.tif")
ret = ds.GetRasterBand(1).ComputeMinMaxLocation()
assert (
ret.min == 74
and ret.max == 255
and ret.minX == 9
and ret.minY == 17
and ret.maxX == 2
and ret.maxY == 18
)

ds = gdal.GetDriverByName("MEM").Create("", 1, 1, 1, gdal.GDT_Float64)
ds.GetRasterBand(1).Fill(float("nan"))
ret = ds.GetRasterBand(1).ComputeMinMaxLocation()
assert ret is None
1 change: 1 addition & 0 deletions doc/source/api/python_samples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Python Raster Sample scripts
- hsv_merge: Merge greyscale image into RGB image as intensity in HSV space.
- gdal_ls: Display the list of files in a virtual directory, like /vsicurl or /vsizip
- gdal_cp: Copy a virtual file
- gdal_minmax_location: returns the location where min/max values of a raster are hit.

Python Vector Sample scripts
------------------------------
Expand Down
4 changes: 4 additions & 0 deletions gcore/gdal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,10 @@ CPLErr CPL_DLL CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand,
CPLErr CPL_DLL CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand,
int bApproxOK,
double adfMinMax[2]);
CPLErr CPL_DLL GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand,
double *pdfMin, double *pdfMax,
int *pnMinX, int *pnMinY,
int *pnMaxX, int *pnMaxY);
CPLErr CPL_DLL CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand);
CPLErr CPL_DLL CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand);
CPLErr CPL_DLL CPL_STDCALL GDALGetRasterHistogram(
Expand Down
3 changes: 3 additions & 0 deletions gcore/gdal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,9 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
virtual CPLErr SetStatistics(double dfMin, double dfMax, double dfMean,
double dfStdDev);
virtual CPLErr ComputeRasterMinMax(int bApproxOK, double *adfMinMax);
virtual CPLErr ComputeRasterMinMaxLocation(double *pdfMin, double *pdfMax,
int *pnMinX, int *pnMinY,
int *pnMaxX, int *pnMaxY);

// Only defined when Doxygen enabled
#ifdef DOXYGEN_SKIP
Expand Down
Loading

0 comments on commit 58d4d3e

Please sign in to comment.