Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "gdal raster fillnodata" standalone command
5 : * Author: Alessandro Pasotti <elpaso at itopen dot it>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2025, Alessandro Pasotti <elpaso at itopen dot it>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_raster_fill_nodata.h"
14 :
15 : #include "cpl_progress.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_alg.h"
18 : #include "commonutils.h"
19 :
20 : #include <algorithm>
21 :
22 : //! @cond Doxygen_Suppress
23 :
24 : #ifndef _
25 : #define _(x) (x)
26 : #endif
27 :
28 : /************************************************************************/
29 : /* GDALRasterFillNodataAlgorithm::GDALRasterFillNodataAlgorithm() */
30 : /************************************************************************/
31 :
32 39 : GDALRasterFillNodataAlgorithm::GDALRasterFillNodataAlgorithm(
33 39 : bool standalone) noexcept
34 : : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION,
35 39 : HELP_URL, standalone)
36 : {
37 39 : AddBandArg(&m_band).SetDefault(m_band);
38 :
39 : AddArg("max-distance", 'd',
40 : _("The maximum distance (in pixels) that the algorithm will search "
41 : "out for values to interpolate."),
42 78 : &m_maxDistance)
43 39 : .SetDefault(m_maxDistance)
44 39 : .SetMetaVar("MAX_DISTANCE");
45 :
46 : AddArg("smoothing-iterations", 's',
47 : _("The number of 3x3 average filter smoothing iterations to run "
48 : "after the interpolation to dampen artifacts. The default is zero "
49 : "smoothing iterations."),
50 78 : &m_smoothingIterations)
51 39 : .SetDefault(m_smoothingIterations)
52 39 : .SetMetaVar("SMOOTHING_ITERATIONS");
53 :
54 : auto &mask{AddArg("mask", 0,
55 : _("Use the first band of the specified file as a "
56 : "validity mask (zero is invalid, non-zero is valid)."),
57 39 : &m_maskDataset)};
58 :
59 39 : SetAutoCompleteFunctionForFilename(mask, GDAL_OF_RASTER);
60 :
61 : AddArg("strategy", 0,
62 : _("By default, pixels are interpolated using an inverse distance "
63 : "weighting (invdist). It is also possible to choose a nearest "
64 : "neighbour (nearest) strategy."),
65 78 : &m_strategy)
66 39 : .SetDefault(m_strategy)
67 39 : .SetChoices("invdist", "nearest");
68 39 : }
69 :
70 : /************************************************************************/
71 : /* GDALRasterFillNodataAlgorithm::RunStep() */
72 : /************************************************************************/
73 :
74 15 : bool GDALRasterFillNodataAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
75 : {
76 15 : auto pfnProgress = ctxt.m_pfnProgress;
77 15 : auto pProgressData = ctxt.m_pProgressData;
78 :
79 15 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
80 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)> pScaledData(
81 : GDALCreateScaledProgress(0.0, 0.5, pfnProgress, pProgressData),
82 30 : GDALDestroyScaledProgress);
83 : auto poTmpDS = CreateTemporaryCopy(
84 15 : this, poSrcDS, m_band, true, pScaledData ? GDALScaledProgress : nullptr,
85 45 : pScaledData.get());
86 15 : if (!poTmpDS)
87 1 : return false;
88 :
89 14 : GDALRasterBand *maskBand{nullptr};
90 14 : if (m_maskDataset.GetDatasetRef())
91 : {
92 2 : maskBand = m_maskDataset.GetDatasetRef()->GetRasterBand(1);
93 2 : if (!maskBand)
94 : {
95 0 : ReportError(CE_Failure, CPLE_AppDefined, "Cannot get mask band.");
96 0 : return false;
97 : }
98 : }
99 :
100 : // Get the output band
101 14 : GDALRasterBand *dstBand{poTmpDS->GetRasterBand(1)};
102 14 : CPLAssert(dstBand);
103 :
104 : // Prepare options to pass to GDALFillNodata
105 14 : CPLStringList aosFillOptions;
106 :
107 14 : if (EQUAL(m_strategy.c_str(), "nearest"))
108 1 : aosFillOptions.AddNameValue("INTERPOLATION", "NEAREST");
109 : else
110 : aosFillOptions.AddNameValue("INTERPOLATION",
111 13 : "INV_DIST"); // default strategy
112 :
113 14 : pScaledData.reset(
114 : GDALCreateScaledProgress(0.5, 1.0, pfnProgress, pProgressData));
115 28 : const auto retVal = GDALFillNodata(
116 14 : dstBand, maskBand, m_maxDistance, 0, m_smoothingIterations,
117 14 : aosFillOptions.List(), pScaledData ? GDALScaledProgress : nullptr,
118 : pScaledData.get());
119 :
120 14 : if (retVal == CE_None)
121 : {
122 13 : if (pfnProgress)
123 11 : pfnProgress(1.0, "", pProgressData);
124 13 : m_outputDataset.Set(std::move(poTmpDS));
125 : }
126 :
127 14 : return retVal == CE_None;
128 : }
129 :
130 : GDALRasterFillNodataAlgorithmStandalone::
131 : ~GDALRasterFillNodataAlgorithmStandalone() = default;
132 :
133 : //! @endcond
|