LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_pansharpen.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 109 109 100.0 %
Date: 2025-06-19 12:30:01 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "pansharpen" step of "raster pipeline"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_pansharpen.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "cpl_minixml.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : /************************************************************************/
      25             : /*       GDALRasterPansharpenAlgorithm::GetConstructorOptions()         */
      26             : /************************************************************************/
      27             : 
      28             : /* static */ GDALRasterPansharpenAlgorithm::ConstructorOptions
      29          33 : GDALRasterPansharpenAlgorithm::GetConstructorOptions(bool standaloneStep)
      30             : {
      31          33 :     ConstructorOptions opts;
      32          33 :     opts.SetStandaloneStep(standaloneStep);
      33          33 :     opts.SetAddDefaultArguments(false);
      34          33 :     opts.SetInputDatasetAlias("panchromatic");
      35          33 :     opts.SetInputDatasetHelpMsg(_("Input panchromatic raster dataset"));
      36          33 :     return opts;
      37             : }
      38             : 
      39             : /************************************************************************/
      40             : /*     GDALRasterPansharpenAlgorithm::GDALRasterPansharpenAlgorithm()   */
      41             : /************************************************************************/
      42             : 
      43          33 : GDALRasterPansharpenAlgorithm::GDALRasterPansharpenAlgorithm(
      44          33 :     bool standaloneStep)
      45             :     : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      46          33 :                                       GetConstructorOptions(standaloneStep))
      47             : {
      48          33 :     const auto AddSpectralDatasetArg = [this]()
      49             :     {
      50             :         auto &arg = AddArg("spectral", 0, _("Input spectral band dataset"),
      51          66 :                            &m_spectralDatasets)
      52          33 :                         .SetPositional()
      53          33 :                         .SetRequired()
      54          33 :                         .SetMinCount(1)
      55             :                         // due to ",band=" comma syntax
      56          33 :                         .SetAutoOpenDataset(false)
      57             :                         // due to ",band=" comma syntax
      58          33 :                         .SetPackedValuesAllowed(false)
      59          33 :                         .SetMetaVar("SPECTRAL");
      60             : 
      61          33 :         SetAutoCompleteFunctionForFilename(arg, GDAL_OF_RASTER);
      62          33 :     };
      63             : 
      64          33 :     if (standaloneStep)
      65             :     {
      66          13 :         AddRasterInputArgs(false, false);
      67          13 :         AddSpectralDatasetArg();
      68          13 :         AddProgressArg();
      69          13 :         AddRasterOutputArgs(false);
      70             :     }
      71             :     else
      72             :     {
      73          20 :         AddRasterHiddenInputDatasetArg();
      74          20 :         AddSpectralDatasetArg();
      75             :     }
      76             : 
      77          66 :     AddArg("resampling", 'r', _("Resampling algorithm"), &m_resampling)
      78          33 :         .SetDefault(m_resampling)
      79             :         .SetChoices("nearest", "bilinear", "cubic", "cubicspline", "lanczos",
      80          33 :                     "average");
      81          33 :     AddArg("weights", 0, _("Weight for each input spectral band"), &m_weights);
      82          33 :     AddArg("nodata", 0, _("Override nodata value of input bands"), &m_nodata);
      83          66 :     AddArg("bit-depth", 0, _("Override bit depth of input bands"), &m_bitDepth)
      84          33 :         .SetMinValueIncluded(8);
      85             :     AddArg("spatial-extent-adjustment", 0,
      86             :            _("Select behavior when bands have not the same extent"),
      87          66 :            &m_spatialExtentAdjustment)
      88          33 :         .SetDefault(m_spatialExtentAdjustment)
      89          33 :         .SetChoices("union", "intersection", "none", "none-without-warning");
      90          33 :     AddNumThreadsArg(&m_numThreads, &m_numThreadsStr);
      91          33 : }
      92             : 
      93             : /************************************************************************/
      94             : /*            GDALRasterPansharpenAlgorithm::RunStep()                  */
      95             : /************************************************************************/
      96             : 
      97          11 : bool GDALRasterPansharpenAlgorithm::RunStep(GDALPipelineStepRunContext &)
      98             : {
      99          11 :     auto poPanDS = m_inputDataset[0].GetDatasetRef();
     100          11 :     CPLAssert(poPanDS);
     101          11 :     CPLAssert(m_outputDataset.GetName().empty());
     102          11 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     103             : 
     104          11 :     if (poPanDS->GetRasterCount() != 1)
     105             :     {
     106           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     107             :                     "Input panchromatic dataset must have a single band");
     108           1 :         return false;
     109             :     }
     110             : 
     111             :     // to keep in this scope to keep datasets of spectral bands open until
     112             :     // GDALCreatePansharpenedVRT() runs
     113             :     std::vector<std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>>
     114          20 :         apoDatasetsToReleaseRef;
     115          20 :     std::vector<GDALRasterBandH> ahSpectralBands;
     116             : 
     117          20 :     for (auto &spectralDataset : m_spectralDatasets)
     118             :     {
     119          12 :         if (auto poSpectralDS = spectralDataset.GetDatasetRef())
     120             :         {
     121          12 :             for (int i = 1; i <= poSpectralDS->GetRasterCount(); ++i)
     122             :             {
     123           9 :                 ahSpectralBands.push_back(
     124           9 :                     GDALRasterBand::ToHandle(poSpectralDS->GetRasterBand(i)));
     125             :             }
     126             :         }
     127             :         else
     128             :         {
     129           9 :             const auto &name = spectralDataset.GetName();
     130           9 :             std::string dsName(name);
     131           9 :             const auto pos = name.find(",band=");
     132           9 :             int iBand = 0;
     133           9 :             if (pos != std::string::npos)
     134             :             {
     135           4 :                 dsName.resize(pos);
     136           4 :                 iBand = atoi(name.c_str() + pos + strlen(",band="));
     137             :             }
     138             :             std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser> poDS(
     139             :                 GDALDataset::Open(dsName.c_str(),
     140           9 :                                   GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
     141           9 :             if (!poDS)
     142           1 :                 return false;
     143             : 
     144           8 :             if (iBand <= 0)
     145             :             {
     146          16 :                 for (int i = 1; i <= poDS->GetRasterCount(); ++i)
     147             :                 {
     148          12 :                     ahSpectralBands.push_back(
     149          12 :                         GDALRasterBand::ToHandle(poDS->GetRasterBand(i)));
     150             :                 }
     151             :             }
     152           4 :             else if (iBand > poDS->GetRasterCount())
     153             :             {
     154           1 :                 ReportError(CE_Failure, CPLE_IllegalArg, "Illegal band in '%s'",
     155             :                             name.c_str());
     156           1 :                 return false;
     157             :             }
     158             :             else
     159             :             {
     160           3 :                 ahSpectralBands.push_back(
     161           3 :                     GDALRasterBand::ToHandle(poDS->GetRasterBand(iBand)));
     162             :             }
     163             : 
     164           7 :             apoDatasetsToReleaseRef.push_back(std::move(poDS));
     165             :         }
     166             :     }
     167             : 
     168          16 :     CPLXMLTreeCloser root(CPLCreateXMLNode(nullptr, CXT_Element, "VRTDataset"));
     169          32 :     for (int i = 0; i < static_cast<int>(ahSpectralBands.size()); ++i)
     170             :     {
     171             :         auto psBandNode =
     172          24 :             CPLCreateXMLNode(root.get(), CXT_Element, "VRTRasterBand");
     173          24 :         CPLAddXMLAttributeAndValue(
     174             :             psBandNode, "dataType",
     175          24 :             GDALGetDataTypeName(GDALGetRasterDataType(ahSpectralBands[i])));
     176          24 :         CPLAddXMLAttributeAndValue(psBandNode, "band", CPLSPrintf("%d", i + 1));
     177          24 :         CPLAddXMLAttributeAndValue(psBandNode, "subClass",
     178             :                                    "VRTPansharpenedRasterBand");
     179             :     }
     180           8 :     CPLAddXMLAttributeAndValue(root.get(), "subClass",
     181             :                                "VRTPansharpenedDataset");
     182             :     auto psPansharpeningOptionsNode =
     183           8 :         CPLCreateXMLNode(root.get(), CXT_Element, "PansharpeningOptions");
     184           8 :     if (!m_weights.empty())
     185             :     {
     186           2 :         auto psAlgorithmOptionsNode = CPLCreateXMLNode(
     187             :             psPansharpeningOptionsNode, CXT_Element, "AlgorithmOptions");
     188           4 :         std::string osWeights;
     189           8 :         for (double w : m_weights)
     190             :         {
     191           6 :             if (!osWeights.empty())
     192           4 :                 osWeights += ',';
     193           6 :             osWeights += CPLSPrintf("%.17g", w);
     194             :         }
     195           2 :         CPLCreateXMLElementAndValue(psAlgorithmOptionsNode, "Weights",
     196             :                                     osWeights.c_str());
     197             :     }
     198           8 :     CPLCreateXMLElementAndValue(psPansharpeningOptionsNode, "Resampling",
     199             :                                 m_resampling.c_str());
     200           8 :     CPLCreateXMLElementAndValue(psPansharpeningOptionsNode, "NumThreads",
     201             :                                 m_numThreadsStr.c_str());
     202           8 :     if (m_bitDepth > 0)
     203             :     {
     204           1 :         CPLCreateXMLElementAndValue(psPansharpeningOptionsNode, "BitDepth",
     205             :                                     CPLSPrintf("%d", m_bitDepth));
     206             :     }
     207           8 :     if (GetArg("nodata")->IsExplicitlySet())
     208             :     {
     209           1 :         CPLCreateXMLElementAndValue(psPansharpeningOptionsNode, "NoData",
     210             :                                     CPLSPrintf("%.17g", m_nodata));
     211             :     }
     212           8 :     CPLCreateXMLElementAndValue(
     213             :         psPansharpeningOptionsNode, "SpatialExtentAdjustment",
     214          16 :         CPLString(m_spatialExtentAdjustment).replaceAll('-', 0).c_str());
     215          32 :     for (int i = 0; i < static_cast<int>(ahSpectralBands.size()); ++i)
     216             :     {
     217          24 :         auto psSpectraBandNode = CPLCreateXMLNode(psPansharpeningOptionsNode,
     218             :                                                   CXT_Element, "SpectralBand");
     219          24 :         CPLAddXMLAttributeAndValue(psSpectraBandNode, "dstBand",
     220             :                                    CPLSPrintf("%d", i + 1));
     221             :     }
     222          16 :     CPLCharUniquePtr pszXML(CPLSerializeXMLTree(root.get()));
     223             :     auto poVRTDS = std::unique_ptr<GDALDataset>(
     224             :         GDALDataset::FromHandle(GDALCreatePansharpenedVRT(
     225           8 :             pszXML.get(), GDALRasterBand::ToHandle(poPanDS->GetRasterBand(1)),
     226          16 :             static_cast<int>(ahSpectralBands.size()), ahSpectralBands.data())));
     227           8 :     const bool bRet = poVRTDS != nullptr;
     228           8 :     if (poVRTDS)
     229             :     {
     230           7 :         m_outputDataset.Set(std::move(poVRTDS));
     231             :     }
     232           8 :     return bRet;
     233             : }
     234             : 
     235             : GDALRasterPansharpenAlgorithmStandalone::
     236             :     ~GDALRasterPansharpenAlgorithmStandalone() = default;
     237             : 
     238             : //! @endcond

Generated by: LCOV version 1.14