Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: gdal "raster sieve" subcommand 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_sieve.h" 14 : 15 : #include "cpl_conv.h" 16 : #include "cpl_vsi_virtual.h" 17 : 18 : #include "gdal_alg.h" 19 : #include "gdal_priv.h" 20 : #include "gdal_utils.h" 21 : #include "commonutils.h" 22 : 23 : //! @cond Doxygen_Suppress 24 : 25 : #ifndef _ 26 : #define _(x) (x) 27 : #endif 28 : 29 : /************************************************************************/ 30 : /* GDALRasterSieveAlgorithm::GDALRasterSieveAlgorithm() */ 31 : /************************************************************************/ 32 : 33 32 : GDALRasterSieveAlgorithm::GDALRasterSieveAlgorithm(bool standaloneStep) 34 : : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION, 35 32 : HELP_URL, standaloneStep) 36 : { 37 : auto &mask{ 38 : AddArg("mask", 0, 39 : _("Use the first band of the specified file as a " 40 : "validity mask (all pixels with a value other than zero " 41 : "will be considered suitable for inclusion in polygons)"), 42 32 : &m_maskDataset, GDAL_OF_RASTER)}; 43 : 44 32 : SetAutoCompleteFunctionForFilename(mask, GDAL_OF_RASTER); 45 : 46 32 : AddBandArg(&m_band); 47 : AddArg("size-threshold", 's', _("Minimum size of polygons to keep"), 48 64 : &m_sizeThreshold) 49 32 : .SetDefault(m_sizeThreshold); 50 : 51 : AddArg("connect-diagonal-pixels", 'c', 52 64 : _("Consider diagonal pixels as connected"), &m_connectDiagonalPixels) 53 32 : .SetDefault(m_connectDiagonalPixels); 54 32 : } 55 : 56 : /************************************************************************/ 57 : /* GDALRasterSieveAlgorithm::RunStep() */ 58 : /************************************************************************/ 59 : 60 10 : bool GDALRasterSieveAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt) 61 : { 62 10 : auto pfnProgress = ctxt.m_pfnProgress; 63 10 : auto pProgressData = ctxt.m_pProgressData; 64 10 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 65 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)> pScaledData( 66 : GDALCreateScaledProgress(0.0, 0.5, pfnProgress, pProgressData), 67 20 : GDALDestroyScaledProgress); 68 : auto poTmpDS = CreateTemporaryCopy( 69 10 : this, poSrcDS, m_band, true, pScaledData ? GDALScaledProgress : nullptr, 70 30 : pScaledData.get()); 71 10 : if (!poTmpDS) 72 1 : return false; 73 : 74 9 : GDALRasterBand *maskBand{nullptr}; 75 9 : if (m_maskDataset.GetDatasetRef()) 76 : { 77 1 : maskBand = m_maskDataset.GetDatasetRef()->GetRasterBand(1); 78 1 : if (!maskBand) 79 : { 80 0 : ReportError(CE_Failure, CPLE_AppDefined, "Cannot get mask band."); 81 0 : return false; 82 : } 83 : } 84 : 85 : // Get the output band 86 9 : GDALRasterBand *dstBand = poTmpDS->GetRasterBand(1); 87 9 : CPLAssert(dstBand); 88 : 89 9 : pScaledData.reset( 90 : GDALCreateScaledProgress(0.5, 1.0, pfnProgress, pProgressData)); 91 27 : const CPLErr err = GDALSieveFilter( 92 : dstBand, maskBand, dstBand, m_sizeThreshold, 93 9 : m_connectDiagonalPixels ? 8 : 4, nullptr, 94 9 : pScaledData ? GDALScaledProgress : nullptr, pScaledData.get()); 95 9 : if (err == CE_None) 96 : { 97 9 : if (pfnProgress) 98 1 : pfnProgress(1.0, "", pProgressData); 99 9 : m_outputDataset.Set(std::move(poTmpDS)); 100 : } 101 : 102 9 : return err == CE_None; 103 : } 104 : 105 : GDALRasterSieveAlgorithmStandalone::~GDALRasterSieveAlgorithmStandalone() = 106 : default; 107 : 108 : //! @endcond