LCOV - code coverage report
Current view: directory - alg - gdalsievefilter.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 155 134 86.5 %
Date: 2010-01-09 Functions: 3 3 100.0 %

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Project:  GDAL
       4                 :  * Purpose:  Raster to Polygon Converter
       5                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6                 :  *
       7                 :  ******************************************************************************
       8                 :  * Copyright (c) 2008, Frank Warmerdam
       9                 :  *
      10                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      11                 :  * copy of this software and associated documentation files (the "Software"),
      12                 :  * to deal in the Software without restriction, including without limitation
      13                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14                 :  * and/or sell copies of the Software, and to permit persons to whom the
      15                 :  * Software is furnished to do so, subject to the following conditions:
      16                 :  *
      17                 :  * The above copyright notice and this permission notice shall be included
      18                 :  * in all copies or substantial portions of the Software.
      19                 :  *
      20                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26                 :  * DEALINGS IN THE SOFTWARE.
      27                 :  ****************************************************************************/
      28                 : 
      29                 : #include "gdal_alg_priv.h"
      30                 : #include "cpl_conv.h"
      31                 : #include <vector>
      32                 : 
      33                 : CPL_CVSID("$Id: gdalsievefilter.cpp 16327 2009-02-14 11:18:38Z rouault $");
      34                 : 
      35                 : #define GP_NODATA_MARKER -51502112
      36                 : 
      37                 : /*
      38                 :  * General Plan
      39                 :  *
      40                 :  * 1) make a pass with the polygon enumerator to build up the 
      41                 :  *    polygon map array.  Also accumulate polygon size information.
      42                 :  *
      43                 :  * 2) Identify the polygons that need to be merged.
      44                 :  * 
      45                 :  * 3) Make a pass with the polygon enumerator.  For each "to be merged" 
      46                 :  *    polygon keep track of it's largest neighbour. 
      47                 :  * 
      48                 :  * 4) Fix up remappings that would go to polygons smaller than the seive
      49                 :  *    size.  Ensure these in term map to the largest neighbour of the 
      50                 :  *    "to be seieved" polygons. 
      51                 :  * 
      52                 :  * 5) Make another pass with the polygon enumerator. This time we remap
      53                 :  *    the actual pixel values of all polygons to be merged.
      54                 :  * 
      55                 :  */
      56                 : 
      57                 : /************************************************************************/
      58                 : /*                          GPMaskImageData()                           */
      59                 : /*                                                                      */
      60                 : /*      Mask out image pixels to a special nodata value if the mask     */
      61                 : /*      band is zero.                                                   */
      62                 : /************************************************************************/
      63                 : 
      64                 : static CPLErr 
      65              21 : GPMaskImageData( GDALRasterBandH hMaskBand, GByte *pabyMaskLine, int iY, int nXSize, 
      66                 :                  GInt32 *panImageLine )
      67                 : 
      68                 : {
      69                 :     CPLErr eErr;
      70                 : 
      71                 :     eErr = GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
      72              21 :                          pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
      73              21 :     if( eErr == CE_None )
      74                 :     {
      75                 :         int i;
      76             126 :         for( i = 0; i < nXSize; i++ )
      77                 :         {
      78             105 :             if( pabyMaskLine[i] == 0 )
      79               0 :                 panImageLine[i] = GP_NODATA_MARKER;
      80                 :         }
      81                 :     }
      82                 : 
      83              21 :     return eErr;
      84                 : }
      85                 : 
      86                 : /************************************************************************/
      87                 : /*                          CompareNeighbour()                          */
      88                 : /*                                                                      */
      89                 : /*      Compare two neighbouring polygons, and update eaches            */
      90                 : /*      "biggest neighbour" if the other is larger than it's current    */
      91                 : /*      largest neighbour.                                              */
      92                 : /*                                                                      */
      93                 : /*      Note that this should end up with each polygon knowing the      */
      94                 : /*      id of it's largest neighbour.  No attempt is made to            */
      95                 : /*      restrict things to small polygons that we will be merging,      */
      96                 : /*      nor to exclude assigning "biggest neighbours" that are still    */
      97                 : /*      smaller than our sieve threshold.                               */
      98                 : /************************************************************************/
      99                 : 
     100             470 : static inline void CompareNeighbour( int nPolyId1, int nPolyId2, 
     101                 :                                      int *panPolyIdMap, 
     102                 :                                      int *panPolyValue,
     103                 :                                      std::vector<int> &anPolySizes,
     104                 :                                      std::vector<int> &anBigNeighbour )
     105                 : 
     106                 : {
     107                 :     // make sure we are working with the final merged polygon ids. 
     108             470 :     nPolyId1 = panPolyIdMap[nPolyId1];
     109             470 :     nPolyId2 = panPolyIdMap[nPolyId2];
     110                 : 
     111             470 :     if( nPolyId1 == nPolyId2 )
     112             185 :         return;
     113                 : 
     114                 :     // nodata polygon do not need neighbours, and cannot be neighbours
     115                 :     // to valid polygons. 
     116             570 :     if( panPolyValue[nPolyId1] == GP_NODATA_MARKER
     117             285 :         || panPolyValue[nPolyId2] == GP_NODATA_MARKER )
     118               0 :         return;
     119                 : 
     120             285 :     if( anBigNeighbour[nPolyId1] == -1
     121                 :         || anPolySizes[anBigNeighbour[nPolyId1]] < anPolySizes[nPolyId2] )
     122             104 :         anBigNeighbour[nPolyId1] = nPolyId2;
     123                 : 
     124             285 :     if( anBigNeighbour[nPolyId2] == -1
     125                 :         || anPolySizes[anBigNeighbour[nPolyId2]] < anPolySizes[nPolyId1] )
     126              42 :         anBigNeighbour[nPolyId2] = nPolyId1;
     127                 : }
     128                 : 
     129                 : /************************************************************************/
     130                 : /*                          GDALSieveFilter()                           */
     131                 : /************************************************************************/
     132                 : 
     133                 : /** 
     134                 :  * Removes small raster polygons. 
     135                 :  *
     136                 :  * The function removes raster polygons smaller than a provided
     137                 :  * threshold size (in pixels) and replaces replaces them with the pixel value 
     138                 :  * of the largest neighbour polygon.  
     139                 :  *
     140                 :  * Polygon are determined (per GDALRasterPolygonEnumerator) as regions of
     141                 :  * the raster where the pixels all have the same value, and that are contiguous
     142                 :  * (connected).  
     143                 :  *
     144                 :  * Pixels determined to be "nodata" per hMaskBand will not be treated as part
     145                 :  * of a polygon regardless of their pixel values.  Nodata areas will never be
     146                 :  * changed nor affect polygon sizes. 
     147                 :  *
     148                 :  * Polygons smaller than the threshold with no neighbours that are as large
     149                 :  * as the threshold will not be altered.  Polygons surrounded by nodata areas
     150                 :  * will therefore not be altered.  
     151                 :  *
     152                 :  * The algorithm makes three passes over the input file to enumerate the
     153                 :  * polygons and collect limited information about them.  Memory use is 
     154                 :  * proportional to the number of polygons (roughly 24 bytes per polygon), but
     155                 :  * is not directly related to the size of the raster.  So very large raster
     156                 :  * files can be processed effectively if there aren't too many polygons.  But
     157                 :  * extremely noisy rasters with many one pixel polygons will end up being 
     158                 :  * expensive (in memory) to process.
     159                 :  * 
     160                 :  * @param hSrcBand the source raster band to be processed.
     161                 :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a 
     162                 :  * value other than zero will be considered suitable for inclusion in polygons.
     163                 :  * @param hDstBand the output raster band.  It may be the same as hSrcBand
     164                 :  * to update the source in place. 
     165                 :  * @param nSizeThreshold raster polygons with sizes smaller than this will
     166                 :  * be merged into their largest neighbour.
     167                 :  * @param nConnectedness either 4 indicating that diagonal pixels are not
     168                 :  * considered directly adjacent for polygon membership purposes or 8
     169                 :  * indicating they are. 
     170                 :  * @param papszOption algorithm options in name=value list form.  None currently
     171                 :  * supported.
     172                 :  * @param pfnProgress callback for reporting algorithm progress matching the
     173                 :  * GDALProgressFunc() semantics.  May be NULL.
     174                 :  * @param pProgressArg callback argument passed to pfnProgress.
     175                 :  *
     176                 :  * @return CE_None on success or CE_Failure if an error occurs.
     177                 :  */
     178                 : 
     179                 : CPLErr CPL_STDCALL
     180               5 : GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
     181                 :                  GDALRasterBandH hDstBand,
     182                 :                  int nSizeThreshold, int nConnectedness,
     183                 :                  char **papszOptions,
     184                 :                  GDALProgressFunc pfnProgress, 
     185                 :                  void * pProgressArg )
     186                 : 
     187                 : {
     188               5 :     VALIDATE_POINTER1( hSrcBand, "GDALSieveFilter", CE_Failure );
     189               5 :     VALIDATE_POINTER1( hDstBand, "GDALSieveFilter", CE_Failure );
     190                 : 
     191               5 :     if( pfnProgress == NULL )
     192               5 :         pfnProgress = GDALDummyProgress;
     193                 : 
     194                 : /* -------------------------------------------------------------------- */
     195                 : /*      Allocate working buffers.                                       */
     196                 : /* -------------------------------------------------------------------- */
     197               5 :     CPLErr eErr = CE_None;
     198               5 :     int nXSize = GDALGetRasterBandXSize( hSrcBand );
     199               5 :     int nYSize = GDALGetRasterBandYSize( hSrcBand );
     200               5 :     GInt32 *panLastLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     201               5 :     GInt32 *panThisLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     202               5 :     GInt32 *panLastLineId =  (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     203               5 :     GInt32 *panThisLineId =  (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     204               5 :     GInt32 *panThisLineWriteVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     205               5 :     GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL;
     206               5 :     if (panLastLineVal == NULL || panThisLineVal == NULL ||
     207                 :         panLastLineId == NULL || panThisLineId == NULL ||
     208                 :         panThisLineWriteVal == NULL ||
     209                 :         (hMaskBand != NULL && pabyMaskLine == NULL))
     210                 :     {
     211                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     212               0 :                  "Could not allocate enough memory for temporary buffers");
     213               0 :         CPLFree( panThisLineId );
     214               0 :         CPLFree( panLastLineId );
     215               0 :         CPLFree( panThisLineVal );
     216               0 :         CPLFree( panLastLineVal );
     217               0 :         CPLFree( panThisLineWriteVal );
     218               0 :         CPLFree( pabyMaskLine );
     219               0 :         return CE_Failure;
     220                 :     }
     221                 : 
     222                 : /* -------------------------------------------------------------------- */
     223                 : /*      The first pass over the raster is only used to build up the     */
     224                 : /*      polygon id map so we will know in advance what polygons are     */
     225                 : /*      what on the second pass.                                        */
     226                 : /* -------------------------------------------------------------------- */
     227                 :     int iY, iX, iPoly;
     228               5 :     GDALRasterPolygonEnumerator oFirstEnum( nConnectedness );
     229               5 :     std::vector<int> anPolySizes;
     230                 : 
     231              41 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     232                 :     {
     233                 :         eErr = GDALRasterIO( 
     234                 :             hSrcBand,
     235                 :             GF_Read, 0, iY, nXSize, 1, 
     236              36 :             panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     237                 :         
     238              36 :         if( eErr == CE_None && hMaskBand != NULL )
     239               7 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     240                 : 
     241              36 :         if( iY == 0 )
     242                 :             oFirstEnum.ProcessLine( 
     243               5 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     244                 :         else
     245                 :             oFirstEnum.ProcessLine(
     246                 :                 panLastLineVal, panThisLineVal, 
     247                 :                 panLastLineId,  panThisLineId, 
     248              31 :                 nXSize );
     249                 : 
     250                 : /* -------------------------------------------------------------------- */
     251                 : /*      Accumulate polygon sizes.                                       */
     252                 : /* -------------------------------------------------------------------- */
     253              36 :         if( oFirstEnum.nNextPolygonId > (int) anPolySizes.size() )
     254              32 :             anPolySizes.resize( oFirstEnum.nNextPolygonId );
     255                 : 
     256             256 :         for( iX = 0; iX < nXSize; iX++ )
     257                 :         {
     258             220 :             iPoly = panThisLineId[iX]; 
     259                 : 
     260                 :             CPLAssert( iPoly >= 0 );
     261             220 :             anPolySizes[iPoly] += 1;
     262                 :         }
     263                 : 
     264                 : /* -------------------------------------------------------------------- */
     265                 : /*      swap this/last lines.                                           */
     266                 : /* -------------------------------------------------------------------- */
     267              36 :         GInt32 *panTmp = panLastLineVal;
     268              36 :         panLastLineVal = panThisLineVal;
     269              36 :         panThisLineVal = panTmp;
     270                 : 
     271              36 :         panTmp = panThisLineId;
     272              36 :         panThisLineId = panLastLineId;
     273              36 :         panLastLineId = panTmp;
     274                 : 
     275                 : /* -------------------------------------------------------------------- */
     276                 : /*      Report progress, and support interrupts.                        */
     277                 : /* -------------------------------------------------------------------- */
     278              36 :         if( eErr == CE_None 
     279                 :             && !pfnProgress( 0.25 * ((iY+1) / (double) nYSize), 
     280                 :                              "", pProgressArg ) )
     281                 :         {
     282               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     283               0 :             eErr = CE_Failure;
     284                 :         }
     285                 :     }
     286                 : 
     287                 : /* -------------------------------------------------------------------- */
     288                 : /*      Make a pass through the maps, ensuring every polygon id         */
     289                 : /*      points to the final id it should use, not an intermediate       */
     290                 : /*      value.                                                          */
     291                 : /* -------------------------------------------------------------------- */
     292               5 :     oFirstEnum.CompleteMerges();
     293                 : 
     294                 : /* -------------------------------------------------------------------- */
     295                 : /*      Push the sizes of merged polygon fragments into the the         */
     296                 : /*      merged polygon id's count.                                      */
     297                 : /* -------------------------------------------------------------------- */
     298             100 :     for( iPoly = 0; iPoly < oFirstEnum.nNextPolygonId; iPoly++ )
     299                 :     {
     300              95 :         if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
     301                 :         {
     302               9 :             anPolySizes[oFirstEnum.panPolyIdMap[iPoly]] += anPolySizes[iPoly];
     303               9 :             anPolySizes[iPoly] = 0;
     304                 :         }
     305                 :     }
     306                 : 
     307                 : /* -------------------------------------------------------------------- */
     308                 : /*      We will use a new enumerator for the second pass primariliy     */
     309                 : /*      so we can preserve the first pass map.                          */
     310                 : /* -------------------------------------------------------------------- */
     311               5 :     GDALRasterPolygonEnumerator oSecondEnum( nConnectedness );
     312                 : 
     313               5 :     std::vector<int> anBigNeighbour;
     314               5 :     anBigNeighbour.resize( anPolySizes.size() );
     315                 : 
     316             100 :     for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
     317              95 :         anBigNeighbour[iPoly] = -1;
     318                 : 
     319                 : /* ==================================================================== */
     320                 : /*      Second pass ... identify the largest neighbour for each         */
     321                 : /*      polygon.                                                        */
     322                 : /* ==================================================================== */
     323              41 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     324                 :     {
     325                 : /* -------------------------------------------------------------------- */
     326                 : /*      Read the image data.                                            */
     327                 : /* -------------------------------------------------------------------- */
     328                 :         eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, 
     329              36 :                              panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     330                 : 
     331              36 :         if( eErr == CE_None && hMaskBand != NULL )
     332               7 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     333                 : 
     334              36 :         if( eErr != CE_None )
     335               0 :             continue;
     336                 : 
     337                 : /* -------------------------------------------------------------------- */
     338                 : /*      Determine what polygon the various pixels belong to (redoing    */
     339                 : /*      the same thing done in the first pass above).                   */
     340                 : /* -------------------------------------------------------------------- */
     341              36 :         if( iY == 0 )
     342                 :             oSecondEnum.ProcessLine( 
     343               5 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     344                 :         else
     345                 :             oSecondEnum.ProcessLine(
     346                 :                 panLastLineVal, panThisLineVal, 
     347                 :                 panLastLineId,  panThisLineId, 
     348              31 :                 nXSize );
     349                 : 
     350                 : /* -------------------------------------------------------------------- */
     351                 : /*      Check our neighbours, and update our biggest neighbour map      */
     352                 : /*      as appropriate.                                                 */
     353                 : /* -------------------------------------------------------------------- */
     354             256 :         for( iX = 0; iX < nXSize; iX++ )
     355                 :         {
     356             220 :             if( iY > 0 )
     357                 :             {
     358                 :                 CompareNeighbour( panThisLineId[iX], 
     359                 :                                   panLastLineId[iX],
     360                 :                                   oFirstEnum.panPolyIdMap,
     361                 :                                   oFirstEnum.panPolyValue,
     362             190 :                                   anPolySizes, anBigNeighbour );
     363                 : 
     364             190 :                 if( iX > 0 && nConnectedness == 8 )
     365                 :                     CompareNeighbour( panThisLineId[iX], 
     366                 :                                       panLastLineId[iX-1],
     367                 :                                       oFirstEnum.panPolyIdMap,
     368                 :                                       oFirstEnum.panPolyValue,
     369              48 :                                       anPolySizes, anBigNeighbour );
     370                 :                     
     371             190 :                 if( iX < nXSize-1 && nConnectedness == 8 )
     372                 :                     CompareNeighbour( panThisLineId[iX], 
     373                 :                                       panLastLineId[iX+1],
     374                 :                                       oFirstEnum.panPolyIdMap,
     375                 :                                       oFirstEnum.panPolyValue,
     376              48 :                                       anPolySizes, anBigNeighbour );
     377                 :                     
     378                 :             }
     379                 :             
     380             220 :             if( iX > 0 )
     381                 :                 CompareNeighbour( panThisLineId[iX], 
     382                 :                                   panThisLineId[iX-1],
     383                 :                                   oFirstEnum.panPolyIdMap,
     384                 :                                   oFirstEnum.panPolyValue,
     385             184 :                                   anPolySizes, anBigNeighbour );
     386                 : 
     387                 :             // We don't need to compare to next pixel or next line
     388                 :             // since they will be compared to us.
     389                 :         }                     
     390                 : 
     391                 : /* -------------------------------------------------------------------- */
     392                 : /*      Swap pixel value, and polygon id lines to be ready for the      */
     393                 : /*      next line.                                                      */
     394                 : /* -------------------------------------------------------------------- */
     395              36 :         GInt32 *panTmp = panLastLineVal;
     396              36 :         panLastLineVal = panThisLineVal;
     397              36 :         panThisLineVal = panTmp;
     398                 : 
     399              36 :         panTmp = panThisLineId;
     400              36 :         panThisLineId = panLastLineId;
     401              36 :         panLastLineId = panTmp;
     402                 : 
     403                 : /* -------------------------------------------------------------------- */
     404                 : /*      Report progress, and support interrupts.                        */
     405                 : /* -------------------------------------------------------------------- */
     406              36 :         if( eErr == CE_None 
     407                 :             && !pfnProgress( 0.25 + 0.25 * ((iY+1) / (double) nYSize), 
     408                 :                              "", pProgressArg ) )
     409                 :         {
     410               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     411               0 :             eErr = CE_Failure;
     412                 :         }
     413                 :     }
     414                 : 
     415                 : /* -------------------------------------------------------------------- */
     416                 : /*      If our biggest neighbour is still smaller than the              */
     417                 : /*      threshold, then try tracking to that polygons biggest           */
     418                 : /*      neighbour, and so forth.                                        */
     419                 : /* -------------------------------------------------------------------- */
     420               5 :     int nFailedMerges = 0;
     421               5 :     int nIsolatedSmall = 0;
     422               5 :     int nSieveTargets = 0;
     423                 : 
     424             100 :     for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
     425                 :     {
     426              95 :         if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
     427               9 :             continue;
     428                 : 
     429                 :         // Ignore nodata polygons. 
     430              86 :         if( oFirstEnum.panPolyValue[iPoly] == GP_NODATA_MARKER )
     431               0 :             continue;
     432                 : 
     433                 :         // Don't try to merge polygons larger than the threshold.
     434              86 :         if( anPolySizes[iPoly] >= nSizeThreshold )
     435                 :         {
     436              18 :             anBigNeighbour[iPoly] = -1;
     437              18 :             continue;
     438                 :         }
     439                 : 
     440              68 :         nSieveTargets++;
     441                 : 
     442                 :         // if we have no neighbours but we are small, what shall we do?
     443              68 :         if( anBigNeighbour[iPoly] == -1 )
     444                 :         {
     445               0 :             nIsolatedSmall++;
     446               0 :             continue;
     447                 :         }
     448                 : 
     449                 :         // If our biggest neighbour is larger than the threshold
     450                 :         // then we are golden. 
     451              68 :         if( anPolySizes[anBigNeighbour[iPoly]] >= nSizeThreshold )
     452              42 :             continue;
     453                 : 
     454                 : #ifdef notdef
     455                 :         // Will our neighbours biggest neighbour do?  
     456                 :         // Eventually we need something sort of recursive here with
     457                 :         // loop detection.
     458                 :         if( anPolySizes[anBigNeighbour[anBigNeighbour[iPoly]]] 
     459                 :             >= nSizeThreshold )
     460                 :         {
     461                 :             anBigNeighbour[iPoly] = anBigNeighbour[anBigNeighbour[iPoly]];
     462                 :             continue;
     463                 :         }
     464                 : #endif
     465                 : 
     466              26 :         nFailedMerges++;
     467              26 :         anBigNeighbour[iPoly] = -1;
     468                 :     }                 
     469                 : 
     470                 :     CPLDebug( "GDALSieveFilter", 
     471                 :               "Small Polygons: %d, Isolated: %d, Unmergable: %d",
     472               5 :               nSieveTargets, nIsolatedSmall, nFailedMerges );
     473                 : 
     474                 : /* ==================================================================== */
     475                 : /*      Make a third pass over the image, actually applying the         */
     476                 : /*      merges.  We reuse the second enumerator but preserve the        */
     477                 : /*      "final maps" from the first.                                    */
     478                 : /* ==================================================================== */
     479               5 :     oSecondEnum.Clear();
     480                 :     
     481                 : 
     482              41 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     483                 :     {
     484                 : /* -------------------------------------------------------------------- */
     485                 : /*      Read the image data.                                            */
     486                 : /* -------------------------------------------------------------------- */
     487                 :         eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, 
     488              36 :                              panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     489                 : 
     490              36 :         memcpy( panThisLineWriteVal, panThisLineVal, 4 * nXSize );
     491                 : 
     492              36 :         if( eErr == CE_None && hMaskBand != NULL )
     493               7 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     494                 : 
     495              36 :         if( eErr != CE_None )
     496               0 :             continue;
     497                 : 
     498                 : /* -------------------------------------------------------------------- */
     499                 : /*      Determine what polygon the various pixels belong to (redoing    */
     500                 : /*      the same thing done in the first pass above).                   */
     501                 : /* -------------------------------------------------------------------- */
     502              36 :         if( iY == 0 )
     503                 :             oSecondEnum.ProcessLine( 
     504               5 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     505                 :         else
     506                 :             oSecondEnum.ProcessLine(
     507                 :                 panLastLineVal, panThisLineVal, 
     508                 :                 panLastLineId,  panThisLineId, 
     509              31 :                 nXSize );
     510                 : 
     511                 : /* -------------------------------------------------------------------- */
     512                 : /*      Reprocess the actual pixel values according to the polygon      */
     513                 : /*      merging, and write out this line of image data.                 */
     514                 : /* -------------------------------------------------------------------- */
     515             256 :         for( iX = 0; iX < nXSize; iX++ )
     516                 :         {
     517             220 :             int iThisPoly = oFirstEnum.panPolyIdMap[panThisLineId[iX]];
     518                 : 
     519             220 :             if( anBigNeighbour[iThisPoly] != -1 )
     520                 :             {
     521              42 :                 panThisLineWriteVal[iX] = 
     522                 :                     oFirstEnum.panPolyValue[
     523              42 :                         anBigNeighbour[iThisPoly]];
     524                 :             }
     525                 :         }
     526                 : 
     527                 : /* -------------------------------------------------------------------- */
     528                 : /*      Write the update data out.                                      */
     529                 : /* -------------------------------------------------------------------- */
     530                 :         eErr = GDALRasterIO( hDstBand, GF_Write, 0, iY, nXSize, 1, 
     531              36 :                              panThisLineWriteVal, nXSize, 1, GDT_Int32, 0, 0 );
     532                 : 
     533                 : /* -------------------------------------------------------------------- */
     534                 : /*      Swap pixel value, and polygon id lines to be ready for the      */
     535                 : /*      next line.                                                      */
     536                 : /* -------------------------------------------------------------------- */
     537              36 :         GInt32 *panTmp = panLastLineVal;
     538              36 :         panLastLineVal = panThisLineVal;
     539              36 :         panThisLineVal = panTmp;
     540                 : 
     541              36 :         panTmp = panThisLineId;
     542              36 :         panThisLineId = panLastLineId;
     543              36 :         panLastLineId = panTmp;
     544                 : 
     545                 : /* -------------------------------------------------------------------- */
     546                 : /*      Report progress, and support interrupts.                        */
     547                 : /* -------------------------------------------------------------------- */
     548              36 :         if( eErr == CE_None 
     549                 :             && !pfnProgress( 0.5 + 0.5 * ((iY+1) / (double) nYSize), 
     550                 :                              "", pProgressArg ) )
     551                 :         {
     552               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     553               0 :             eErr = CE_Failure;
     554                 :         }
     555                 :     }
     556                 : 
     557                 : /* -------------------------------------------------------------------- */
     558                 : /*      Cleanup                                                         */
     559                 : /* -------------------------------------------------------------------- */
     560               5 :     CPLFree( panThisLineId );
     561               5 :     CPLFree( panLastLineId );
     562               5 :     CPLFree( panThisLineVal );
     563               5 :     CPLFree( panLastLineVal );
     564               5 :     CPLFree( panThisLineWriteVal );
     565               5 :     CPLFree( pabyMaskLine );
     566                 : 
     567               5 :     return eErr;
     568                 : }
     569                 : 

Generated by: LCOV version 1.7