LTP GCOV extension - code coverage report
Current view: directory - alg - gdalsievefilter.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 154
Code covered: 86.4 % Executed lines: 133

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

Generated by: LTP GCOV extension version 1.5