Skip to content

Commit

Permalink
gdal raster mosaic/stack: add a --resolution=same mode, and default t…
Browse files Browse the repository at this point in the history
…o it
  • Loading branch information
rouault committed Jan 27, 2025
1 parent 46c3484 commit 9f45b20
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 62 deletions.
24 changes: 16 additions & 8 deletions apps/gdalalg_raster_mosaic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,18 @@ GDALRasterMosaicAlgorithm::GDALRasterMosaicAlgorithm()
AddArg("band", 'b', _("Specify input band(s) number."), &m_bands);
AddOverwriteArg(&m_overwrite);
{
auto &arg = AddArg("resolution", 0,
_("Target resolution (in destination CRS units)"),
&m_resolution)
.SetMetaVar("<xres>,<yres>|average|highest|lowest");
auto &arg =
AddArg("resolution", 0,
_("Target resolution (in destination CRS units)"),
&m_resolution)
.SetDefault("same")
.SetMetaVar("<xres>,<yres>|same|average|highest|lowest");
arg.AddValidationAction(
[this, &arg]()
{
const std::string val = arg.Get<std::string>();
if (val != "average" && val != "highest" && val != "lowest")
if (val != "average" && val != "highest" && val != "lowest" &&
val != "same")
{
const auto aosTokens =
CPLStringList(CSLTokenizeString2(val.c_str(), ",", 0));
Expand All @@ -66,8 +69,8 @@ GDALRasterMosaicAlgorithm::GDALRasterMosaicAlgorithm()
{
ReportError(CE_Failure, CPLE_AppDefined,
"resolution: two comma separated positive "
"values should be provided, or 'average', "
"'highest' or 'lowest'");
"values should be provided, or 'same', "
"'average', 'highest' or 'lowest'");
return false;
}
}
Expand Down Expand Up @@ -190,7 +193,12 @@ bool GDALRasterMosaicAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
aosOptions.push_back("-program_name");
aosOptions.push_back("gdal raster mosaic");

if (!m_resolution.empty())
if (m_resolution.empty())
{
aosOptions.push_back("-resolution");
aosOptions.push_back("same");
}
else
{
const auto aosTokens =
CPLStringList(CSLTokenizeString2(m_resolution.c_str(), ",", 0));
Expand Down
25 changes: 17 additions & 8 deletions apps/gdalalg_raster_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,18 @@ GDALRasterStackAlgorithm::GDALRasterStackAlgorithm()
AddArg("band", 'b', _("Specify input band(s) number."), &m_bands);
AddOverwriteArg(&m_overwrite);
{
auto &arg = AddArg("resolution", 0,
_("Target resolution (in destination CRS units)"),
&m_resolution)
.SetMetaVar("<xres>,<yres>|average|highest|lowest");
auto &arg =
AddArg("resolution", 0,
_("Target resolution (in destination CRS units)"),
&m_resolution)
.SetDefault("same")
.SetMetaVar("<xres>,<yres>|same|average|highest|lowest");
arg.AddValidationAction(
[this, &arg]()
{
const std::string val = arg.Get<std::string>();
if (val != "average" && val != "highest" && val != "lowest")
if (val != "average" && val != "highest" && val != "lowest" &&
val != "same")
{
const auto aosTokens =
CPLStringList(CSLTokenizeString2(val.c_str(), ",", 0));
Expand All @@ -66,8 +69,8 @@ GDALRasterStackAlgorithm::GDALRasterStackAlgorithm()
{
ReportError(CE_Failure, CPLE_AppDefined,
"resolution: two comma separated positive "
"values should be provided, or 'average', "
"'highest' or 'lowest'");
"values should be provided, or 'same', "
"'average', 'highest' or 'lowest'");
return false;
}
}
Expand Down Expand Up @@ -188,7 +191,12 @@ bool GDALRasterStackAlgorithm::RunImpl(GDALProgressFunc pfnProgress,

aosOptions.push_back("-separate");

if (!m_resolution.empty())
if (m_resolution.empty())
{
aosOptions.push_back("-resolution");
aosOptions.push_back("same");
}
else
{
const auto aosTokens =
CPLStringList(CSLTokenizeString2(m_resolution.c_str(), ",", 0));
Expand All @@ -204,6 +212,7 @@ bool GDALRasterStackAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
aosOptions.push_back(m_resolution);
}
}

if (!m_bbox.empty())
{
aosOptions.push_back("-te");
Expand Down
24 changes: 21 additions & 3 deletions autotest/utilities/test_gdalalg_raster_mosaic.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def test_gdalalg_raster_mosaic_resolution_average():

alg = get_mosaic_alg()
alg.GetArg("input").Set([src1_ds, src2_ds])
alg.GetArg("resolution").Set("average")
alg.GetArg("output").Set("")
assert alg.Run()
ds = alg.GetArg("output").Get().GetDataset()
Expand Down Expand Up @@ -196,24 +197,41 @@ def test_gdalalg_raster_mosaic_target_aligned_pixels():
assert ds.GetGeoTransform() == pytest.approx((1.8, 0.3, 0.0, 49.2, 0.0, -0.6))


def test_gdalalg_raster_mosaic_resolution_same_default():

src1_ds = gdal.GetDriverByName("MEM").Create("", 1, 1)
src1_ds.SetGeoTransform([2, 1, 0, 49, 0, -1])
src2_ds = gdal.GetDriverByName("MEM").Create("", 2, 2)
src2_ds.SetGeoTransform([3, 0.5, 0, 49, 0, -0.5])

alg = get_mosaic_alg()
alg.GetArg("input").Set([src1_ds, src2_ds])
alg.GetArg("output").Set("")
with pytest.raises(
Exception,
match="whereas previous sources have resolution",
):
assert alg.Run()


def test_gdalalg_raster_mosaic_resolution_invalid():

alg = get_mosaic_alg()
with pytest.raises(
Exception,
match="resolution: two comma separated positive values should be provided, or 'average', 'highest' or 'lowest'",
match="resolution: two comma separated positive values should be provided, or 'same', 'average', 'highest' or 'lowest'",
):
alg.GetArg("resolution").Set("invalid")

with pytest.raises(
Exception,
match="resolution: two comma separated positive values should be provided, or 'average', 'highest' or 'lowest'",
match="resolution: two comma separated positive values should be provided, or 'same', 'average', 'highest' or 'lowest'",
):
alg.GetArg("resolution").Set("0.5")

with pytest.raises(
Exception,
match="resolution: two comma separated positive values should be provided, or 'average', 'highest' or 'lowest'",
match="resolution: two comma separated positive values should be provided, or 'same', 'average', 'highest' or 'lowest'",
):
alg.GetArg("resolution").Set("-0.5,-0.5")

Expand Down
45 changes: 23 additions & 22 deletions doc/source/programs/gdal_raster_mosaic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,29 @@ Synopsis
Build a mosaic, either virtual (VRT) or materialized
Positional arguments:
-i, --input <INPUTS> Input raster datasets (or specify a @<filename> to point to a file containing filenames) [1.. values]
-o, --output <OUTPUT> Output raster dataset (created by algorithm) [required]
-i, --input <INPUTS> Input raster datasets (or specify a @<filename> to point to a file containing filenames) [1.. values]
-o, --output <OUTPUT> Output raster dataset (created by algorithm) [required]
Common Options:
-h, --help Display help message and exit
--version Display GDAL version and exit
--json-usage Display usage as JSON document and exit
--drivers Display driver list as JSON document and exit
--config <KEY>=<VALUE> Configuration option [may be repeated]
--progress Display progress bar
-h, --help Display help message and exit
--version Display GDAL version and exit
--json-usage Display usage as JSON document and exit
--drivers Display driver list as JSON document and exit
--config <KEY>=<VALUE> Configuration option [may be repeated]
--progress Display progress bar
Options:
-f, --of, --format, --output-format <OUTPUT-FORMAT> Output format
--co, --creation-option <KEY>=<VALUE> Creation option [may be repeated]
-b, --band <BAND> Specify input band(s) number. [may be repeated]
--overwrite Whether overwriting existing output is allowed
--resolution <xres>,<yres>|average|highest|lowest> Target resolution (in destination CRS units)
--bbox <BBOX> Target bounding box as xmin,ymin,xmax,ymax (in destination CRS units)
--target-aligned-pixels Round target extent to target resolution
--srcnodata <SRCNODATA> Set nodata values for input bands. [1.. values]
--dstnodata <VRTNODATA> Set nodata values at the destination band level. [1.. values]
--hidenodata Makes the destination band not report the NoData.
--addalpha Adds an alpha mask band to the destination when the source raster have none.
-f, --of, --format, --output-format <OUTPUT-FORMAT> Output format
--co, --creation-option <KEY>=<VALUE> Creation option [may be repeated]
-b, --band <BAND> Specify input band(s) number. [may be repeated]
--overwrite Whether overwriting existing output is allowed
--resolution <xres>,<yres>|same|average|highest|lowest> Target resolution (in destination CRS units) (default: same)
--bbox <BBOX> Target bounding box as xmin,ymin,xmax,ymax (in destination CRS units)
--target-aligned-pixels Round target extent to target resolution
--srcnodata <SRCNODATA> Set nodata values for input bands. [1.. values]
--dstnodata <DSTNODATA> Set nodata values at the destination band level. [1.. values]
--hidenodata Makes the destination band not report the NoData.
--addalpha Adds an alpha mask band to the destination when the source raster have none.
Description
Expand Down Expand Up @@ -86,16 +85,18 @@ The following options are available:
If input bands not set all bands will be added to the output.
Multiple :option:`-b` switches may be used to select a set of input bands.

.. option:: --resolution {<xres,yres>|highest|lowest|average}
.. option:: --resolution {<xres,yres>|same|highest|lowest|average}

In case the resolution of all input files is not the same, the :option:`--resolution` flag
enables the user to control the way the output resolution is computed.

`same`, the default, checks that all source rasters have the same resolution and errors out when this is not the case.

`highest` will pick the smallest values of pixel dimensions within the set of source rasters.

`lowest` will pick the largest values of pixel dimensions within the set of source rasters.

`average` is the default and will compute an average of pixel dimensions within the set of source rasters.
`average` will compute an average of pixel dimensions within the set of source rasters.

<xres>,<yres>. The values must be expressed in georeferenced units.
Both must be positive values.
Expand Down
43 changes: 22 additions & 21 deletions doc/source/programs/gdal_raster_stack.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,28 @@ Synopsis
Combine together input bands into a multi-band output, either virtual (VRT) or materialized.
Positional arguments:
-i, --input <INPUTS> Input raster datasets (or specify a @<filename> to point to a file containing filenames) [1.. values]
-o, --output <OUTPUT> Output raster dataset (created by algorithm) [required]
-i, --input <INPUTS> Input raster datasets (or specify a @<filename> to point to a file containing filenames) [1.. values]
-o, --output <OUTPUT> Output raster dataset (created by algorithm) [required]
Common Options:
-h, --help Display help message and exit
--version Display GDAL version and exit
--json-usage Display usage as JSON document and exit
--drivers Display driver list as JSON document and exit
--config <KEY>=<VALUE> Configuration option [may be repeated]
--progress Display progress bar
-h, --help Display help message and exit
--version Display GDAL version and exit
--json-usage Display usage as JSON document and exit
--drivers Display driver list as JSON document and exit
--config <KEY>=<VALUE> Configuration option [may be repeated]
--progress Display progress bar
Options:
-f, --of, --format, --output-format <OUTPUT-FORMAT> Output format
--co, --creation-option <KEY>=<VALUE> Creation option [may be repeated]
-b, --band <BAND> Specify input band(s) number. [may be repeated]
--overwrite Whether overwriting existing output is allowed
--resolution <xres>,<yres>|average|highest|lowest> Target resolution (in destination CRS units)
--bbox <BBOX> Target bounding box as xmin,ymin,xmax,ymax (in destination CRS units)
--target-aligned-pixels Round target extent to target resolution
--srcnodata <SRCNODATA> Set nodata values for input bands. [1.. values]
--dstnodata <VRTNODATA> Set nodata values at the destination band level. [1.. values]
--hidenodata Makes the destination band not report the NoData.
-f, --of, --format, --output-format <OUTPUT-FORMAT> Output format
--co, --creation-option <KEY>=<VALUE> Creation option [may be repeated]
-b, --band <BAND> Specify input band(s) number. [may be repeated]
--overwrite Whether overwriting existing output is allowed
--resolution <xres>,<yres>|same|average|highest|lowest> Target resolution (in destination CRS units) (default: same)
--bbox <BBOX> Target bounding box as xmin,ymin,xmax,ymax (in destination CRS units)
--target-aligned-pixels Round target extent to target resolution
--srcnodata <SRCNODATA> Set nodata values for input bands. [1.. values]
--dstnodata <DSTNODATA> Set nodata values at the destination band level. [1.. values]
--hidenodata Makes the destination band not report the NoData.
Description
Expand Down Expand Up @@ -77,16 +76,18 @@ The following options are available:
If input bands not set all bands will be added to the output.
Multiple :option:`-b` switches may be used to select a set of input bands.

.. option:: --resolution {<xres,yres>|highest|lowest|average}
.. option:: --resolution {<xres,yres>|same|highest|lowest|average}

In case the resolution of all input files is not the same, the :option:`--resolution` flag
enables the user to control the way the output resolution is computed.

`same`, the default, checks that all source rasters have the same resolution and errors out when this is not the case.

`highest` will pick the smallest values of pixel dimensions within the set of source rasters.

`lowest` will pick the largest values of pixel dimensions within the set of source rasters.

`average` is the default and will compute an average of pixel dimensions within the set of source rasters.
`average` will compute an average of pixel dimensions within the set of source rasters.

<xres>,<yres>. The values must be expressed in georeferenced units.
Both must be positive values.
Expand Down

0 comments on commit 9f45b20

Please sign in to comment.