Skip to content

Commit

Permalink
gdal reproject: add a --size argument, add --bbox-crs as well
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Mar 6, 2025
1 parent fd803f4 commit 9077905
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 2 deletions.
40 changes: 38 additions & 2 deletions apps/gdalalg_raster_reproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ GDALRasterReprojectAlgorithm::GDALRasterReprojectAlgorithm(bool standaloneStep)
.SetMaxCount(2)
.SetRepeatedArgAllowed(false)
.SetDisplayHintAboutRepetition(false)
.SetMetaVar("<xres>,<yres>");
.SetMetaVar("<xres>,<yres>")
.SetMutualExclusionGroup("resolution-size");
resArg.AddValidationAction(
[&resArg]()
{
const auto &val = resArg.Get<std::vector<double>>();
CPLAssert(val.size() == 2);
if (!(val[0] >= 0 && val[1] >= 0))
if (!(val[0] > 0 && val[1] > 0))
{
CPLError(CE_Failure, CPLE_AppDefined,
"Target resolution should be strictly positive.");
Expand All @@ -63,7 +64,31 @@ GDALRasterReprojectAlgorithm::GDALRasterReprojectAlgorithm(bool standaloneStep)
return true;
});

auto &sizeArg = AddArg("size", 0, _("Target size in pixels"), &m_size)
.SetMinCount(2)
.SetMaxCount(2)
.SetRepeatedArgAllowed(false)
.SetDisplayHintAboutRepetition(false)
.SetMetaVar("<width>,<height>")
.SetMutualExclusionGroup("resolution-size");
sizeArg.AddValidationAction(
[&sizeArg]()
{
const auto &val = sizeArg.Get<std::vector<int>>();
CPLAssert(val.size() == 2);
if (!(val[0] >= 0 && val[1] >= 0))
{
CPLError(CE_Failure, CPLE_AppDefined,
"Target size should be positive or 0.");
return false;
}
return true;
});

AddBBOXArg(&m_bbox, _("Target bounding box (in destination CRS units)"));
AddArg("bbox-crs", 0, _("CRS of target bounding box"), &m_bboxCrs)
.SetIsCRSArg()
.AddHiddenAlias("bbox_srs");

AddArg("target-aligned-pixels", 0,
_("Round target extent to target resolution"),
Expand Down Expand Up @@ -105,6 +130,12 @@ bool GDALRasterReprojectAlgorithm::RunStep(GDALProgressFunc, void *)
aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[0]));
aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[1]));
}
if (!m_size.empty())
{
aosOptions.AddString("-ts");
aosOptions.AddString(CPLSPrintf("%d", m_size[0]));
aosOptions.AddString(CPLSPrintf("%d", m_size[1]));
}
if (!m_bbox.empty())
{
aosOptions.AddString("-te");
Expand All @@ -113,6 +144,11 @@ bool GDALRasterReprojectAlgorithm::RunStep(GDALProgressFunc, void *)
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[2]));
aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[3]));
}
if (!m_bboxCrs.empty())
{
aosOptions.AddString("-te_srs");
aosOptions.AddString(m_bboxCrs.c_str());
}
if (m_targetAlignedPixels)
{
aosOptions.AddString("-tap");
Expand Down
2 changes: 2 additions & 0 deletions apps/gdalalg_raster_reproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class GDALRasterReprojectAlgorithm /* non final */
std::string m_resampling{};
std::vector<double> m_resolution{};
std::vector<double> m_bbox{};
std::string m_bboxCrs{};
std::vector<int> m_size{};
bool m_targetAlignedPixels = false;
};

Expand Down
37 changes: 37 additions & 0 deletions autotest/utilities/test_gdalalg_raster_reproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,40 @@ def test_gdalalg_raster_reproject_failure(tmp_vsimem):
out_filename,
],
)


def test_gdalalg_raster_reproject_size(tmp_vsimem):

out_filename = str(tmp_vsimem / "out.tif")

pipeline = get_reproject_alg()
pipeline.ParseRunAndFinalize(
[
"--size=10,0",
"../gcore/data/byte.tif",
out_filename,
],
)

with gdal.OpenEx(out_filename) as ds:
assert ds.RasterXSize == 10
assert ds.RasterYSize == 10


def test_gdalalg_raster_reproject_bbox_crs(tmp_vsimem):

out_filename = str(tmp_vsimem / "out.tif")

pipeline = get_reproject_alg()
pipeline.ParseRunAndFinalize(
[
"--bbox=-117.638051657173,33.8904636339659,-117.627303823822,33.8995379597727",
"--bbox-crs=EPSG:4267",
"../gcore/data/byte.tif",
out_filename,
],
)

with gdal.OpenEx(out_filename) as ds:
assert ds.RasterXSize == 17
assert ds.RasterYSize == 17
111 changes: 111 additions & 0 deletions doc/source/programs/gdal_raster_reproject.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ Synopsis
-d, --dst-crs <DST-CRS> Destination CRS
-r, --resampling <RESAMPLING> Resampling method. RESAMPLING=nearest|bilinear|cubic|cubicspline|lanczos|average|rms|mode|min|max|med|q1|q3|sum
--resolution <xres>,<yres> Target resolution (in destination CRS units)
Mutually exclusive with --size
--size <width>,<height> Target size in pixels
Mutually exclusive with --resolution
--bbox <xmin>,<ymin>,<xmax>,<ymax> Target bounding box (in destination CRS units)
--bbox-crs <BBOX-CRS> CRS of target bounding box
--target-aligned-pixels Round target extent to target resolution
Advanced Options:
Expand All @@ -52,6 +56,113 @@ Description
-----------

:program:`gdal raster reproject` can be used to reproject a raster dataset.
The program can reproject to any supported projection.

Standard options
++++++++++++++++

.. include:: gdal_options/of_raster_create_copy.rst

.. include:: gdal_options/co.rst

.. include:: gdal_options/overwrite.rst

.. option:: -s, --src-crs <SRC-CRS>

Set source spatial reference. If not specified the SRS found in the input
dataset will be used.

.. include:: options/srs_def_gdalwarp.rst

.. option:: -d, --dst-crs <SRC-CRS>

Set source spatial reference. If not specified the SRS found in the input
dataset will be used.

.. include:: options/srs_def_gdalwarp.rst

.. option:: -r, --resampling <RESAMPLING>

Resampling method to use. Available methods are:

``near``: nearest neighbour resampling (default, fastest algorithm, worst interpolation quality).

``bilinear``: bilinear resampling.

``cubic``: cubic resampling.

``cubicspline``: cubic spline resampling.

``lanczos``: Lanczos windowed sinc resampling.

``average``: average resampling, computes the weighted average of all non-NODATA contributing pixels.

``rms`` root mean square / quadratic mean of all non-NODATA contributing pixels (GDAL >= 3.3)

``mode``: mode resampling, selects the value which appears most often of all the sampled points. In the case of ties, the first value identified as the mode will be selected.

``max``: maximum resampling, selects the maximum value from all non-NODATA contributing pixels.

``min``: minimum resampling, selects the minimum value from all non-NODATA contributing pixels.

``med``: median resampling, selects the median value of all non-NODATA contributing pixels.

``q1``: first quartile resampling, selects the first quartile value of all non-NODATA contributing pixels.

``q3``: third quartile resampling, selects the third quartile value of all non-NODATA contributing pixels.

``sum``: compute the weighted sum of all non-NODATA contributing pixels (since GDAL 3.1)

.. note::

When downsampling is performed (use of :option:`--resolution` or :option:`--size`), existing
overviews (either internal/implicit or external ones) on the source image
will be used by default by selecting the closest overview to the desired output
resolution.
The resampling method used to create those overviews is generally not the one you
specify through the :option:`-r` option.

.. option:: --resolution <xres>,<yres>

Set output file resolution (in target georeferenced units).

If not specified (or not deduced from -te and -ts), gdalwarp will, in the
general case, generate an output raster with xres=yres.

If neither :option:`--resolution` nor :option:`--size` are specified,
that no reprojection is involved (including taking into account geolocation arrays
or RPC), the resolution of the source file(s) will be preserved (in previous
version, an output raster with xres=yres was always generated).

.. option:: --size <width>,<height>

Set output file size in pixels and lines. If width or height is set to 0,
the other dimension will be guessed from the computed resolution. Note that
:option:`--size` cannot be used with :option:`--resolution`

.. option:: --bbox <xmin>,<ymin>,<xmax>,<ymax>

Set georeferenced extents of output file to be created (in target SRS by
default, or in the SRS specified with :option:`--bbox-crs`)

.. option:: --bbox-crs <BBOX-CRS>

Specifies the SRS in which to interpret the coordinates given with :option:`--bbox`.

.. include:: options/srs_def_gdalwarp.rst

This must not be confused with :option:`-dst-crs` which is the target SRS of the output
dataset. :option:`--bbox-crs` is a convenience e.g. when knowing the output coordinates in a
geodetic long/lat SRS, but still wanting a result in a projected coordinate system.

.. option:: --target-aligned-pixels

Aign the coordinates of the extent of the output
file to the values of the :option:`--resolution`, such that the aligned extent
includes the minimum extent (edges lines/columns that are detected as
blank, before actual warping, will be removed).
Alignment means that xmin / resx, ymin / resy,
xmax / resx and ymax / resy are integer values.

Examples
--------
Expand Down

0 comments on commit 9077905

Please sign in to comment.