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 18 : GDALRasterSieveAlgorithm::GDALRasterSieveAlgorithm(bool standaloneStep) 34 : : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION, 35 18 : 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 18 : &m_maskDataset, GDAL_OF_RASTER)}; 43 : 44 18 : SetAutoCompleteFunctionForFilename(mask, GDAL_OF_RASTER); 45 : 46 18 : AddBandArg(&m_band); 47 : AddArg("size-threshold", 's', _("Minimum size of polygons to keep"), 48 36 : &m_sizeThreshold) 49 18 : .SetDefault(m_sizeThreshold); 50 : 51 : AddArg("connect-diagonal-pixels", 'c', 52 36 : _("Consider diagonal pixels as connected"), &m_connectDiagonalPixels) 53 18 : .SetDefault(m_connectDiagonalPixels); 54 18 : } 55 : 56 : /************************************************************************/ 57 : /* GDALRasterSieveAlgorithm::RunStep() */ 58 : /************************************************************************/ 59 : 60 10 : bool GDALRasterSieveAlgorithm::RunStep(GDALProgressFunc pfnProgress, 61 : void *pProgressData) 62 : { 63 10 : auto poSrcDS = m_inputDataset.GetDatasetRef(); 64 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)> pScaledData( 65 : GDALCreateScaledProgress(0.0, 0.5, pfnProgress, pProgressData), 66 20 : GDALDestroyScaledProgress); 67 : auto poTmpDS = CreateTemporaryCopy( 68 10 : poSrcDS, m_band, true, pScaledData ? GDALScaledProgress : nullptr, 69 30 : pScaledData.get()); 70 10 : if (!poTmpDS) 71 1 : return false; 72 : 73 9 : GDALRasterBand *maskBand{nullptr}; 74 9 : if (m_maskDataset.GetDatasetRef()) 75 : { 76 1 : maskBand = m_maskDataset.GetDatasetRef()->GetRasterBand(1); 77 1 : if (!maskBand) 78 : { 79 0 : ReportError(CE_Failure, CPLE_AppDefined, "Cannot get mask band."); 80 0 : return false; 81 : } 82 : } 83 : 84 : // Get the output band 85 9 : GDALRasterBand *dstBand = poTmpDS->GetRasterBand(1); 86 9 : CPLAssert(dstBand); 87 : 88 9 : pScaledData.reset( 89 : GDALCreateScaledProgress(0.5, 1.0, pfnProgress, pProgressData)); 90 27 : const CPLErr err = GDALSieveFilter( 91 : dstBand, maskBand, dstBand, m_sizeThreshold, 92 9 : m_connectDiagonalPixels ? 8 : 4, nullptr, 93 9 : pScaledData ? GDALScaledProgress : nullptr, pScaledData.get()); 94 9 : if (err == CE_None) 95 : { 96 9 : if (pfnProgress) 97 1 : pfnProgress(1.0, "", pProgressData); 98 9 : m_outputDataset.Set(std::move(poTmpDS)); 99 : } 100 : 101 9 : return err == CE_None; 102 : } 103 : 104 : //! @endcond