LTP GCOV extension - code coverage report
Current view: directory - alg - rasterfill.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 265
Code covered: 41.1 % Executed lines: 109

       1                 : /******************************************************************************
       2                 :  * $Id: rasterfill.cpp 19220 2010-03-27 23:03:21Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL
       5                 :  * Purpose:  Interpolate in nodata areas.
       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.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : 
      34                 : CPL_CVSID("$Id: rasterfill.cpp 19220 2010-03-27 23:03:21Z rouault $");
      35                 : 
      36                 : /************************************************************************/
      37                 : /*                           GDALFilterLine()                           */
      38                 : /*                                                                      */
      39                 : /*      Apply 3x3 filtering one one scanline with masking for which     */
      40                 : /*      pixels are to be interpolated (ThisFMask) and which window      */
      41                 : /*      pixels are valid to include in the interpolation (TMask).       */
      42                 : /************************************************************************/
      43                 : 
      44                 : static void
      45                 : GDALFilterLine( float *pafLastLine, float *pafThisLine, float *pafNextLine,
      46                 :                 float *pafOutLine,
      47                 :                 GByte *pabyLastTMask, GByte *pabyThisTMask, GByte*pabyNextTMask,
      48               0 :                 GByte *pabyThisFMask, int nXSize )
      49                 : 
      50                 : {
      51                 :     int iX;
      52                 : 
      53               0 :     for( iX = 0; iX < nXSize; iX++ )
      54                 :     {
      55               0 :         if( !pabyThisFMask[iX] )
      56                 :         {
      57               0 :             pafOutLine[iX] = pafThisLine[iX];
      58               0 :             continue;
      59                 :         }
      60                 : 
      61               0 :         CPLAssert( pabyThisTMask[iX] );
      62                 : 
      63               0 :         double dfValSum = 0.0;
      64               0 :         double dfWeightSum = 0.0;
      65                 : 
      66                 :         // Previous line
      67               0 :         if( pafLastLine != NULL )
      68                 :         {
      69               0 :             if( iX > 0 && pabyLastTMask[iX-1] )
      70                 :             {
      71               0 :                 dfValSum += pafLastLine[iX-1];
      72               0 :                 dfWeightSum += 1.0;
      73                 :             }
      74               0 :             if( pabyLastTMask[iX] )
      75                 :             {
      76               0 :                 dfValSum += pafLastLine[iX];
      77               0 :                 dfWeightSum += 1.0;
      78                 :             }
      79               0 :             if( iX < nXSize-1 && pabyLastTMask[iX+1] )
      80                 :             {
      81               0 :                 dfValSum += pafLastLine[iX+1];
      82               0 :                 dfWeightSum += 1.0;
      83                 :             }
      84                 :         }
      85                 : 
      86                 :         // Current Line
      87               0 :         if( iX > 0 && pabyThisTMask[iX-1] )
      88                 :         {
      89               0 :             dfValSum += pafThisLine[iX-1];
      90               0 :             dfWeightSum += 1.0;
      91                 :         }
      92               0 :         if( pabyThisTMask[iX] )
      93                 :         {
      94               0 :             dfValSum += pafThisLine[iX];
      95               0 :             dfWeightSum += 1.0;
      96                 :         }
      97               0 :         if( iX < nXSize-1 && pabyThisTMask[iX+1] )
      98                 :         {
      99               0 :             dfValSum += pafThisLine[iX+1];
     100               0 :             dfWeightSum += 1.0;
     101                 :         }
     102                 : 
     103                 :         // Next line
     104               0 :         if( pafNextLine != NULL )
     105                 :         {
     106               0 :             if( iX > 0 && pabyNextTMask[iX-1] )
     107                 :             {
     108               0 :                 dfValSum += pafNextLine[iX-1];
     109               0 :                 dfWeightSum += 1.0;
     110                 :             }
     111               0 :             if( pabyNextTMask[iX] )
     112                 :             {
     113               0 :                 dfValSum += pafNextLine[iX];
     114               0 :                 dfWeightSum += 1.0;
     115                 :             }
     116               0 :             if( iX < nXSize-1 && pabyNextTMask[iX+1] )
     117                 :             {
     118               0 :                 dfValSum += pafNextLine[iX+1];
     119               0 :                 dfWeightSum += 1.0;
     120                 :             }
     121                 :         }
     122                 : 
     123               0 :         pafOutLine[iX] = dfValSum / dfWeightSum;
     124                 :     }
     125               0 : }
     126                 : 
     127                 : /************************************************************************/
     128                 : /*                          GDALMultiFilter()                           */
     129                 : /*                                                                      */
     130                 : /*      Apply multiple iterations of a 3x3 smoothing filter over a      */
     131                 : /*      band with masking controlling what pixels should be             */
     132                 : /*      filtered (FiltMaskBand non zero) and which pixels can be        */
     133                 : /*      considered valid contributors to the filter                     */
     134                 : /*      (TargetMaskBand non zero).                                      */
     135                 : /*                                                                      */
     136                 : /*      This implementation attempts to apply many iterations in        */
     137                 : /*      one IO pass by managing the filtering over a rolling buffer     */
     138                 : /*      of nIternations+2 scanlines.  While possibly clever this        */
     139                 : /*      makes the algorithm implementation largely                      */
     140                 : /*      incomprehensible.                                               */
     141                 : /************************************************************************/
     142                 : 
     143                 : static CPLErr
     144                 : GDALMultiFilter( GDALRasterBandH hTargetBand, 
     145                 :                  GDALRasterBandH hTargetMaskBand, 
     146                 :                  GDALRasterBandH hFiltMaskBand,
     147                 :                  int nIterations,
     148                 :                  GDALProgressFunc pfnProgress, 
     149               0 :                  void * pProgressArg )
     150                 : 
     151                 : {
     152                 :     float *paf3PassLineBuf;
     153                 :     GByte *pabyTMaskBuf;
     154                 :     GByte *pabyFMaskBuf;
     155                 :     float *pafThisPass, *pafLastPass, *pafSLastPass;
     156                 : 
     157               0 :     int   nBufLines = nIterations + 2;
     158               0 :     int   iPassCounter = 0;
     159                 :     int   nNewLine; // the line being loaded this time (zero based scanline)
     160               0 :     int   nXSize = GDALGetRasterBandXSize( hTargetBand );
     161               0 :     int   nYSize = GDALGetRasterBandYSize( hTargetBand );
     162               0 :     CPLErr eErr = CE_None;
     163                 : 
     164                 : /* -------------------------------------------------------------------- */
     165                 : /*      Report starting progress value.                                 */
     166                 : /* -------------------------------------------------------------------- */
     167               0 :     if( !pfnProgress( 0.0, "Smoothing Filter...", pProgressArg ) )
     168                 :     {
     169               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     170               0 :         return CE_Failure;
     171                 :     }
     172                 : 
     173                 : /* -------------------------------------------------------------------- */
     174                 : /*      Allocate rotating buffers.                                      */
     175                 : /* -------------------------------------------------------------------- */
     176               0 :     pabyTMaskBuf = (GByte *) VSIMalloc2(nXSize, nBufLines);
     177               0 :     pabyFMaskBuf = (GByte *) VSIMalloc2(nXSize, nBufLines);
     178                 : 
     179               0 :     paf3PassLineBuf = (float *) VSIMalloc3(nXSize, nBufLines, 3 * sizeof(float));
     180               0 :     if (pabyTMaskBuf == NULL || pabyFMaskBuf == NULL || paf3PassLineBuf == NULL)
     181                 :     {
     182                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     183               0 :                  "Could not allocate enough memory for temporary buffers");
     184               0 :         eErr = CE_Failure;
     185               0 :         goto end;
     186                 :     }
     187                 : 
     188                 : /* -------------------------------------------------------------------- */
     189                 : /*      Process rotating buffers.                                       */
     190                 : /* -------------------------------------------------------------------- */
     191               0 :     for( nNewLine = 0; 
     192                 :          eErr == CE_None && nNewLine < nYSize+nIterations; 
     193                 :          nNewLine++ )
     194                 :     {
     195                 : /* -------------------------------------------------------------------- */
     196                 : /*      Rotate pass buffers.                                            */
     197                 : /* -------------------------------------------------------------------- */
     198               0 :         iPassCounter = (iPassCounter + 1) % 3;
     199                 : 
     200                 :         pafSLastPass = paf3PassLineBuf 
     201               0 :             + ((iPassCounter+0)%3) * nXSize*nBufLines;
     202                 :         pafLastPass = paf3PassLineBuf 
     203               0 :             + ((iPassCounter+1)%3) * nXSize*nBufLines;
     204                 :         pafThisPass = paf3PassLineBuf 
     205               0 :             + ((iPassCounter+2)%3) * nXSize*nBufLines;
     206                 : 
     207                 : /* -------------------------------------------------------------------- */
     208                 : /*      Where does the new line go in the rotating buffer?              */
     209                 : /* -------------------------------------------------------------------- */
     210               0 :         int iBufOffset = nNewLine % nBufLines;
     211                 : 
     212                 : /* -------------------------------------------------------------------- */
     213                 : /*      Read the new data line if it is't off the bottom of the         */
     214                 : /*      image.                                                          */
     215                 : /* -------------------------------------------------------------------- */
     216               0 :         if( nNewLine < nYSize )
     217                 :         {
     218                 :             eErr = 
     219                 :                 GDALRasterIO( hTargetMaskBand, GF_Read, 
     220                 :                               0, nNewLine, nXSize, 1, 
     221                 :                               pabyTMaskBuf + nXSize * iBufOffset, nXSize, 1, 
     222               0 :                               GDT_Byte, 0, 0 );
     223                 :             
     224               0 :             if( eErr != CE_None )
     225               0 :                 break;
     226                 : 
     227                 :             eErr = 
     228                 :                 GDALRasterIO( hFiltMaskBand, GF_Read, 
     229                 :                               0, nNewLine, nXSize, 1, 
     230                 :                               pabyFMaskBuf + nXSize * iBufOffset, nXSize, 1, 
     231               0 :                               GDT_Byte, 0, 0 );
     232                 :             
     233               0 :             if( eErr != CE_None )
     234               0 :                 break;
     235                 : 
     236                 :             eErr = 
     237                 :                 GDALRasterIO( hTargetBand, GF_Read, 
     238                 :                               0, nNewLine, nXSize, 1, 
     239                 :                               pafThisPass + nXSize * iBufOffset, nXSize, 1, 
     240               0 :                               GDT_Float32, 0, 0 );
     241                 :             
     242               0 :             if( eErr != CE_None )
     243               0 :                 break;
     244                 :         }
     245                 : 
     246                 : /* -------------------------------------------------------------------- */
     247                 : /*      Loop over the loaded data, applying the filter to all loaded    */
     248                 : /*      lines with neighbours.                                          */
     249                 : /* -------------------------------------------------------------------- */
     250                 :         int iFLine;
     251                 : 
     252               0 :         for( iFLine = nNewLine-1;
     253                 :              eErr == CE_None && iFLine >= nNewLine-nIterations;
     254                 :              iFLine-- )
     255                 :         {
     256                 :             int iLastOffset, iThisOffset, iNextOffset;
     257                 : 
     258               0 :             iLastOffset = (iFLine-1) % nBufLines; 
     259               0 :             iThisOffset = (iFLine  ) % nBufLines;
     260               0 :             iNextOffset = (iFLine+1) % nBufLines;
     261                 : 
     262                 :             // default to preserving the old value.
     263               0 :             if( iFLine >= 0 )
     264                 :                 memcpy( pafThisPass + iThisOffset * nXSize, 
     265                 :                         pafLastPass + iThisOffset * nXSize, 
     266               0 :                         sizeof(float) * nXSize );
     267                 : 
     268                 :             // currently this skips the first and last line.  Eventually 
     269                 :             // we will enable these too.  TODO
     270               0 :             if( iFLine < 1 || iFLine >= nYSize-1 )
     271                 :             {
     272               0 :                 continue;
     273                 :             }
     274                 : 
     275                 :             GDALFilterLine( 
     276                 :                 pafSLastPass + iLastOffset * nXSize,
     277                 :                 pafLastPass  + iThisOffset * nXSize, 
     278                 :                 pafThisPass  + iNextOffset * nXSize, 
     279                 :                 pafThisPass  + iThisOffset * nXSize,
     280                 :                 pabyTMaskBuf + iLastOffset * nXSize,
     281                 :                 pabyTMaskBuf + iThisOffset * nXSize,
     282                 :                 pabyTMaskBuf + iNextOffset * nXSize,
     283                 :                 pabyFMaskBuf + iThisOffset * nXSize, 
     284               0 :                 nXSize );
     285                 :         }
     286                 : 
     287                 : /* -------------------------------------------------------------------- */
     288                 : /*      Write out the top data line that will be rolling out of our     */
     289                 : /*      buffer.                                                         */
     290                 : /* -------------------------------------------------------------------- */
     291               0 :         int iLineToSave = nNewLine - nIterations;
     292                 : 
     293               0 :         if( iLineToSave >= 0 && eErr == CE_None )
     294                 :         {
     295               0 :             iBufOffset = iLineToSave % nBufLines;
     296                 : 
     297                 :             eErr = 
     298                 :                 GDALRasterIO( hTargetBand, GF_Write, 
     299                 :                               0, iLineToSave, nXSize, 1, 
     300                 :                               pafThisPass + nXSize * iBufOffset, nXSize, 1, 
     301               0 :                               GDT_Float32, 0, 0 );
     302                 :         }
     303                 : 
     304                 : /* -------------------------------------------------------------------- */
     305                 : /*      Report progress.                                                */
     306                 : /* -------------------------------------------------------------------- */
     307               0 :         if( eErr == CE_None
     308                 :             && !pfnProgress( (nNewLine+1) / (double) (nYSize+nIterations), 
     309                 :                              "Smoothing Filter...", pProgressArg ) )
     310                 :         {
     311               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     312               0 :             eErr = CE_Failure;
     313                 :         }
     314                 :     }
     315                 : 
     316                 : /* -------------------------------------------------------------------- */
     317                 : /*      Cleanup                                                         */
     318                 : /* -------------------------------------------------------------------- */
     319               0 : end:
     320               0 :     CPLFree( pabyTMaskBuf );
     321               0 :     CPLFree( pabyFMaskBuf );
     322               0 :     CPLFree( paf3PassLineBuf );
     323                 : 
     324               0 :     return eErr;
     325                 : }
     326                 :  
     327                 : /************************************************************************/
     328                 : /*                             QUAD_CHECK()                             */
     329                 : /*                                                                      */
     330                 : /*      macro for checking whether a point is nearer than the           */
     331                 : /*      existing closest point.                                         */
     332                 : /************************************************************************/
     333                 : #define QUAD_CHECK(quad_dist, quad_value,         \
     334                 : target_x, target_y, origin_x, origin_y, target_value )      \
     335                 :                   \
     336                 : if( quad_value != nNoDataVal )            \
     337                 : {                 \
     338                 :     double dfDistSq = ((target_x-origin_x) * (target_x-origin_x))       \
     339                 :                     + ((target_y-origin_y) * (target_y-origin_y));      \
     340                 :                       \
     341                 :     if( dfDistSq < quad_dist*quad_dist )       \
     342                 :     {                 \
     343                 :   CPLAssert( dfDistSq > 0.0 );                                    \
     344                 :         quad_dist = sqrt(dfDistSq);           \
     345                 :         quad_value = target_value;          \
     346                 :     }                 \
     347                 : }
     348                 : 
     349                 : /************************************************************************/
     350                 : /*                           GDALFillNodata()                           */
     351                 : /************************************************************************/
     352                 : 
     353                 : /**
     354                 :  * Fill selected raster regions by interpolation from the edges.
     355                 :  *
     356                 :  * This algorithm will interpolate values for all designated 
     357                 :  * nodata pixels (marked by zeros in hMaskBand).  For each pixel
     358                 :  * a four direction conic search is done to find values to interpolate
     359                 :  * from (using inverse distance weighting).  Once all values are
     360                 :  * interpolated, zero or more smoothing iterations (3x3 average
     361                 :  * filters on interpolated pixels) are applied to smooth out 
     362                 :  * artifacts. 
     363                 :  *
     364                 :  * This algorithm is generally suitable for interpolating missing
     365                 :  * regions of fairly continuously varying rasters (such as elevation
     366                 :  * models for instance).  It is also suitable for filling small holes
     367                 :  * and cracks in more irregularly varying images (like airphotos).  It
     368                 :  * is generally not so great for interpolating a raster from sparse 
     369                 :  * point data - see the algorithms defined in gdal_grid.h for that case.
     370                 :  *
     371                 :  * @param hTargetBand the raster band to be modified in place. 
     372                 :  * @param hMaskBand a mask band indicating pixels to be interpolated (zero valued
     373                 :  * @param dfMaxSearchDist the maximum number of pixels to search in all 
     374                 :  * directions to find values to interpolate from.
     375                 :  * @param bDeprecatedOption unused argument, should be zero.
     376                 :  * @param nSmoothingIterations the number of 3x3 smoothing filter passes to 
     377                 :  * run (0 or more).
     378                 :  * @param papszOptions additional name=value options in a string list (none 
     379                 :  * supported at this time - just pass NULL).
     380                 :  * @param pfnProgress the progress function to report completion.
     381                 :  * @param pProgressArg callback data for progress function.
     382                 :  * 
     383                 :  * @return CE_None on success or CE_Failure if something goes wrong. 
     384                 :  */
     385                 : 
     386                 : CPLErr CPL_STDCALL
     387                 : GDALFillNodata( GDALRasterBandH hTargetBand, 
     388                 :                 GDALRasterBandH hMaskBand,
     389                 :                 double dfMaxSearchDist, 
     390                 :                 int bDeprecatedOption,
     391                 :                 int nSmoothingIterations,
     392                 :                 char **papszOptions,
     393                 :                 GDALProgressFunc pfnProgress, 
     394               1 :                 void * pProgressArg )
     395                 : 
     396                 : {
     397               1 :     VALIDATE_POINTER1( hTargetBand, "GDALFillNodata", CE_Failure );
     398                 : 
     399               1 :     int nXSize = GDALGetRasterBandXSize( hTargetBand );
     400               1 :     int nYSize = GDALGetRasterBandYSize( hTargetBand );
     401               1 :     CPLErr eErr = CE_None;
     402                 : 
     403                 :     // Special "x" pixel values identifying pixels as special.
     404                 :     GUInt32 nNoDataVal;
     405                 :     GDALDataType eType;
     406                 : 
     407               1 :     if( dfMaxSearchDist == 0.0 )
     408               0 :         dfMaxSearchDist = MAX(nXSize,nYSize) + 1;
     409                 : 
     410               1 :     int nMaxSearchDist = (int) floor(dfMaxSearchDist);
     411                 : 
     412               1 :     if( nXSize > 65533 || nYSize > 65533 )
     413                 :     {
     414               0 :         eType = GDT_UInt32;
     415               0 :         nNoDataVal = 4000002;
     416                 :     }
     417                 :     else
     418                 :     {
     419               1 :         eType = GDT_UInt16;
     420               1 :         nNoDataVal = 65535;
     421                 :     }
     422                 : 
     423               1 :     if( hMaskBand == NULL )
     424               0 :         hMaskBand = GDALGetMaskBand( hTargetBand );
     425                 : 
     426                 :     /* If there are smoothing iterations, reserve 10% of the progress for them */
     427               1 :     double dfProgressRatio = (nSmoothingIterations > 0) ? 0.9 : 1.0;
     428                 : 
     429                 : /* -------------------------------------------------------------------- */
     430                 : /*      Initialize progress counter.                                    */
     431                 : /* -------------------------------------------------------------------- */
     432               1 :     if( pfnProgress == NULL )
     433               0 :         pfnProgress = GDALDummyProgress;
     434                 : 
     435               1 :     if( !pfnProgress( 0.0, "Filling...", pProgressArg ) )
     436                 :     {
     437               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     438               0 :         return CE_Failure;
     439                 :     }
     440                 : 
     441                 : /* -------------------------------------------------------------------- */
     442                 : /*      Create a work file to hold the Y "last value" indices.          */
     443                 : /* -------------------------------------------------------------------- */
     444               1 :     GDALDriverH  hDriver = GDALGetDriverByName( "GTiff" );
     445               1 :     if (hDriver == NULL)
     446                 :     {
     447                 :         CPLError(CE_Failure, CPLE_AppDefined,
     448               0 :                  "GDALFillNodata needs GTiff driver");
     449               0 :         return CE_Failure;
     450                 :     }
     451                 :     
     452                 :     GDALDatasetH hYDS;
     453                 :     GDALRasterBandH hYBand;
     454                 :     static const char *apszOptions[] = { "COMPRESS=LZW", NULL };
     455               1 :     CPLString osTmpFile = CPLGenerateTempFilename("");
     456               1 :     CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";
     457                 :     
     458                 :     hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1, 
     459               1 :                        eType, (char **) apszOptions );
     460                 :     
     461               1 :     if( hYDS == NULL )
     462               1 :         return CE_Failure;
     463                 : 
     464               1 :     hYBand = GDALGetRasterBand( hYDS, 1 );
     465                 : 
     466                 : /* -------------------------------------------------------------------- */
     467                 : /*      Create a work file to hold the pixel value associated with      */
     468                 : /*      the "last xy value" pixel.                                      */
     469                 : /* -------------------------------------------------------------------- */
     470                 :     GDALDatasetH hValDS;
     471                 :     GDALRasterBandH hValBand;
     472               1 :     CPLString osValTmpFile = osTmpFile + "fill_val_work.tif";
     473                 : 
     474                 :     hValDS = GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
     475                 :                          GDALGetRasterDataType( hTargetBand ), 
     476               1 :                          (char **) apszOptions );
     477                 :     
     478               1 :     if( hValDS == NULL )
     479               0 :         return CE_Failure;
     480                 : 
     481               1 :     hValBand = GDALGetRasterBand( hValDS, 1 );
     482                 : 
     483                 : /* -------------------------------------------------------------------- */
     484                 : /*      Create a mask file to make it clear what pixels can be filtered */
     485                 : /*      on the filtering pass.                                          */
     486                 : /* -------------------------------------------------------------------- */
     487                 :     GDALDatasetH hFiltMaskDS;
     488                 :     GDALRasterBandH hFiltMaskBand;
     489               1 :     CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";
     490                 :     
     491                 :     hFiltMaskDS = 
     492                 :         GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
     493               1 :                     GDT_Byte, (char **) apszOptions );
     494                 :     
     495               1 :     if( hFiltMaskDS == NULL )
     496               0 :         return CE_Failure;
     497                 : 
     498               1 :     hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );
     499                 : 
     500                 : /* -------------------------------------------------------------------- */
     501                 : /*      Allocate buffers for last scanline and this scanline.           */
     502                 : /* -------------------------------------------------------------------- */
     503                 :     GUInt32 *panLastY, *panThisY, *panTopDownY;
     504                 :     float   *pafLastValue, *pafThisValue, *pafScanline, *pafTopDownValue;
     505                 :     GByte   *pabyMask, *pabyFiltMask;
     506                 :     int     iX;
     507                 :     int     iY;
     508                 : 
     509               1 :     panLastY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     510               1 :     panThisY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     511               1 :     panTopDownY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     512               1 :     pafLastValue = (float *) VSICalloc(nXSize,sizeof(float));
     513               1 :     pafThisValue = (float *) VSICalloc(nXSize,sizeof(float));
     514               1 :     pafTopDownValue = (float *) VSICalloc(nXSize,sizeof(float));
     515               1 :     pafScanline = (float *) VSICalloc(nXSize,sizeof(float));
     516               1 :     pabyMask = (GByte *) VSICalloc(nXSize,1);
     517               1 :     pabyFiltMask = (GByte *) VSICalloc(nXSize,1);
     518               1 :     if (panLastY == NULL || panThisY == NULL || panTopDownY == NULL ||
     519                 :         pafLastValue == NULL || pafThisValue == NULL || pafTopDownValue == NULL ||
     520                 :         pafScanline == NULL || pabyMask == NULL || pabyFiltMask == NULL)
     521                 :     {
     522                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     523               0 :                  "Could not allocate enough memory for temporary buffers");
     524                 : 
     525               0 :         eErr = CE_Failure;
     526               0 :         goto end;
     527                 :     }
     528                 : 
     529              21 :     for( iX = 0; iX < nXSize; iX++ )
     530                 :     {
     531              20 :         panLastY[iX] = nNoDataVal;
     532                 :     }
     533                 : 
     534                 : /* ==================================================================== */
     535                 : /*      Make first pass from top to bottom collecting the "last         */
     536                 : /*      known value" for each column and writing it out to the work     */
     537                 : /*      files.                                                          */
     538                 : /* ==================================================================== */
     539                 :     
     540              21 :     for( iY = 0; iY < nYSize && eErr == CE_None; iY++ )
     541                 :     {
     542                 : /* -------------------------------------------------------------------- */
     543                 : /*      Read data and mask for this line.                               */
     544                 : /* -------------------------------------------------------------------- */
     545                 :         eErr = 
     546                 :             GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
     547              20 :                           pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
     548                 : 
     549              20 :         if( eErr != CE_None )
     550               0 :             break;
     551                 : 
     552                 :         eErr = 
     553                 :             GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
     554              20 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     555                 :         
     556              20 :         if( eErr != CE_None )
     557               0 :             break;
     558                 :         
     559                 : /* -------------------------------------------------------------------- */
     560                 : /*      Figure out the most recent pixel for each column.               */
     561                 : /* -------------------------------------------------------------------- */
     562                 :         
     563             420 :         for( iX = 0; iX < nXSize; iX++ )
     564                 :         {
     565             400 :             if( pabyMask[iX] )
     566                 :             {
     567             400 :                 pafThisValue[iX] = pafScanline[iX];
     568             400 :                 panThisY[iX] = iY;
     569                 :             }
     570               0 :             else if( iY - panLastY[iX] <= dfMaxSearchDist )
     571                 :             {
     572               0 :                 pafThisValue[iX] = pafLastValue[iX];
     573               0 :                 panThisY[iX] = panLastY[iX];
     574                 :             }
     575                 :             else
     576                 :             {
     577               0 :                 panThisY[iX] = nNoDataVal;
     578                 :             }
     579                 :         }
     580                 :         
     581                 : /* -------------------------------------------------------------------- */
     582                 : /*      Write out best index/value to working files.                    */
     583                 : /* -------------------------------------------------------------------- */
     584                 :         eErr = GDALRasterIO( hYBand, GF_Write, 0, iY, nXSize, 1, 
     585              20 :                              panThisY, nXSize, 1, GDT_UInt32, 0, 0 );
     586              20 :         if( eErr != CE_None )
     587               0 :             break;
     588                 : 
     589                 :         eErr = GDALRasterIO( hValBand, GF_Write, 0, iY, nXSize, 1, 
     590              20 :                              pafThisValue, nXSize, 1, GDT_Float32, 0, 0 );
     591              20 :         if( eErr != CE_None )
     592               0 :             break;
     593                 : 
     594                 : /* -------------------------------------------------------------------- */
     595                 : /*      Flip this/last buffers.                                         */
     596                 : /* -------------------------------------------------------------------- */
     597                 :         {
     598              20 :             float *pafTmp = pafThisValue;
     599              20 :             pafThisValue = pafLastValue;
     600              20 :             pafLastValue = pafTmp;
     601                 : 
     602              20 :             GUInt32 *panTmp = panThisY;
     603              20 :             panThisY = panLastY;
     604              20 :             panLastY = panTmp;
     605                 :         }
     606                 : 
     607                 : /* -------------------------------------------------------------------- */
     608                 : /*      report progress.                                                */
     609                 : /* -------------------------------------------------------------------- */
     610              20 :         if( eErr == CE_None
     611                 :             && !pfnProgress( dfProgressRatio * (0.5*(iY+1) / (double)nYSize), 
     612                 :                              "Filling...", pProgressArg ) )
     613                 :         {
     614               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     615               0 :             eErr = CE_Failure;
     616                 :         }
     617                 :     }
     618                 : 
     619                 : /* ==================================================================== */
     620                 : /*      Now we will do collect similar this/last information from       */
     621                 : /*      bottom to top and use it in combination with the top to         */
     622                 : /*      bottom search info to interpolate.                              */
     623                 : /* ==================================================================== */
     624              21 :     for( iY = nYSize-1; iY >= 0 && eErr == CE_None; iY-- )
     625                 :     {
     626                 :         eErr = 
     627                 :             GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
     628              20 :                           pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
     629                 : 
     630              20 :         if( eErr != CE_None )
     631               0 :             break;
     632                 : 
     633                 :         eErr = 
     634                 :             GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
     635              20 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     636                 :         
     637              20 :         if( eErr != CE_None )
     638               0 :             break;
     639                 :         
     640                 : /* -------------------------------------------------------------------- */
     641                 : /*      Figure out the most recent pixel for each column.               */
     642                 : /* -------------------------------------------------------------------- */
     643                 :         
     644             420 :         for( iX = 0; iX < nXSize; iX++ )
     645                 :         {
     646             400 :             if( pabyMask[iX] )
     647                 :             {
     648             400 :                 pafThisValue[iX] = pafScanline[iX];
     649             400 :                 panThisY[iX] = iY;
     650                 :             }
     651               0 :             else if( panLastY[iX] - iY <= dfMaxSearchDist )
     652                 :             {
     653               0 :                 pafThisValue[iX] = pafLastValue[iX];
     654               0 :                 panThisY[iX] = panLastY[iX];
     655                 :             }
     656                 :             else
     657                 :             {
     658               0 :                 panThisY[iX] = nNoDataVal;
     659                 :             }
     660                 :         }
     661                 :         
     662                 : /* -------------------------------------------------------------------- */
     663                 : /*      Load the last y and corresponding value from the top down pass. */
     664                 : /* -------------------------------------------------------------------- */
     665                 :         eErr = 
     666                 :             GDALRasterIO( hYBand, GF_Read, 0, iY, nXSize, 1, 
     667              20 :                           panTopDownY, nXSize, 1, GDT_UInt32, 0, 0 );
     668                 : 
     669              20 :         if( eErr != CE_None )
     670               0 :             break;
     671                 : 
     672                 :         eErr = 
     673                 :             GDALRasterIO( hValBand, GF_Read, 0, iY, nXSize, 1, 
     674              20 :                           pafTopDownValue, nXSize, 1, GDT_Float32, 0, 0 );
     675                 : 
     676              20 :         if( eErr != CE_None )
     677               0 :             break;
     678                 : 
     679                 : /* -------------------------------------------------------------------- */
     680                 : /*      Attempt to interpolate any pixels that are nodata.              */
     681                 : /* -------------------------------------------------------------------- */
     682              20 :         memset( pabyFiltMask, 0, nXSize );
     683             420 :         for( iX = 0; iX < nXSize; iX++ )
     684                 :         {
     685                 :             int iStep, iQuad;
     686             400 :             int nThisMaxSearchDist = nMaxSearchDist;
     687                 : 
     688                 :             // If this was a valid target - no change.
     689             400 :             if( pabyMask[iX] )
     690             400 :                 continue;
     691                 : 
     692                 :             // Quadrants 0:topleft, 1:bottomleft, 2:topright, 3:bottomright
     693                 :             double adfQuadDist[4];
     694                 :             double adfQuadValue[4];
     695                 : 
     696               0 :             for( iQuad = 0; iQuad < 4; iQuad++ )
     697               0 :                 adfQuadDist[iQuad] = dfMaxSearchDist + 1.0;
     698                 :             
     699                 :             // Step left and right by one pixel searching for the closest 
     700                 :             // target value for each quadrant. 
     701               0 :             for( iStep = 0; iStep < nThisMaxSearchDist; iStep++ )
     702                 :             {
     703               0 :                 int iLeftX = MAX(0,iX - iStep);
     704               0 :                 int iRightX = MIN(nXSize-1,iX + iStep);
     705                 :                 
     706                 :                 // top left includes current line 
     707               0 :                 QUAD_CHECK(adfQuadDist[0],adfQuadValue[0], 
     708                 :                            iLeftX, panTopDownY[iLeftX], iX, iY,
     709                 :                            pafTopDownValue[iLeftX] );
     710                 : 
     711                 :                 // bottom left 
     712               0 :                 QUAD_CHECK(adfQuadDist[1],adfQuadValue[1], 
     713                 :                            iLeftX, panLastY[iLeftX], iX, iY, 
     714                 :                            pafLastValue[iLeftX] );
     715                 : 
     716                 :                 // top right and bottom right do no include center pixel.
     717               0 :                 if( iStep == 0 )
     718               0 :                      continue;
     719                 :                     
     720                 :                 // top right includes current line 
     721               0 :                 QUAD_CHECK(adfQuadDist[2],adfQuadValue[2], 
     722                 :                            iRightX, panTopDownY[iRightX], iX, iY,
     723                 :                            pafTopDownValue[iRightX] );
     724                 : 
     725                 :                 // bottom right
     726               0 :                 QUAD_CHECK(adfQuadDist[3],adfQuadValue[3], 
     727                 :                            iRightX, panLastY[iRightX], iX, iY,
     728                 :                            pafLastValue[iRightX] );
     729                 : 
     730                 :                 // every four steps, recompute maximum distance.
     731               0 :                 if( (iStep & 0x3) == 0 )
     732                 :                     nThisMaxSearchDist = (int) floor(
     733               0 :                         MAX(MAX(adfQuadDist[0],adfQuadDist[1]),
     734                 :                             MAX(adfQuadDist[2],adfQuadDist[3])) );
     735                 :             }
     736                 : 
     737               0 :             double dfWeightSum = 0.0;
     738               0 :             double dfValueSum = 0.0;
     739                 :             
     740               0 :             for( iQuad = 0; iQuad < 4; iQuad++ )
     741                 :             {
     742               0 :                 if( adfQuadDist[iQuad] <= dfMaxSearchDist )
     743                 :                 {
     744               0 :                     double dfWeight = 1.0 / adfQuadDist[iQuad];
     745                 : 
     746               0 :                     dfWeightSum += dfWeight;
     747               0 :                     dfValueSum += adfQuadValue[iQuad] * dfWeight;
     748                 :                 }
     749                 :             }
     750                 : 
     751               0 :             if( dfWeightSum > 0.0 )
     752                 :             {
     753               0 :                 pabyMask[iX] = 255;
     754               0 :                 pabyFiltMask[iX] = 255;
     755               0 :                 pafScanline[iX] = dfValueSum / dfWeightSum;
     756                 :             }
     757                 : 
     758                 :         }
     759                 : 
     760                 : /* -------------------------------------------------------------------- */
     761                 : /*      Write out the updated data and mask information.                */
     762                 : /* -------------------------------------------------------------------- */
     763                 :         eErr = 
     764                 :             GDALRasterIO( hTargetBand, GF_Write, 0, iY, nXSize, 1, 
     765              20 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     766                 :         
     767              20 :         if( eErr != CE_None )
     768               0 :             break;
     769                 : 
     770                 :         eErr = 
     771                 :             GDALRasterIO( hFiltMaskBand, GF_Write, 0, iY, nXSize, 1, 
     772              20 :                           pabyFiltMask, nXSize, 1, GDT_Byte, 0, 0 );
     773                 :         
     774              20 :         if( eErr != CE_None )
     775               0 :             break;
     776                 : 
     777                 : /* -------------------------------------------------------------------- */
     778                 : /*      Flip this/last buffers.                                         */
     779                 : /* -------------------------------------------------------------------- */
     780                 :         {
     781              20 :             float *pafTmp = pafThisValue;
     782              20 :             pafThisValue = pafLastValue;
     783              20 :             pafLastValue = pafTmp;
     784                 :             
     785              20 :             GUInt32 *panTmp = panThisY;
     786              20 :             panThisY = panLastY;
     787              20 :             panLastY = panTmp;
     788                 :         }
     789                 : 
     790                 : /* -------------------------------------------------------------------- */
     791                 : /*      report progress.                                                */
     792                 : /* -------------------------------------------------------------------- */
     793              20 :         if( eErr == CE_None
     794                 :             && !pfnProgress( dfProgressRatio*(0.5+0.5*(nYSize-iY) / (double)nYSize), 
     795                 :                              "Filling...", pProgressArg ) )
     796                 :         {
     797               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     798               0 :             eErr = CE_Failure;
     799                 :         }
     800                 :     }        
     801                 : 
     802                 : /* ==================================================================== */
     803                 : /*      Now we will do iterative average filters over the               */
     804                 : /*      interpolated values to smooth things out and make linear        */
     805                 : /*      artifacts less obvious.                                         */
     806                 : /* ==================================================================== */
     807               1 :     if( eErr == CE_None && nSmoothingIterations > 0 )
     808                 :     {
     809                 :         // force masks to be to flushed and recomputed.
     810               0 :         GDALFlushRasterCache( hMaskBand );
     811                 : 
     812                 :         void *pScaledProgress;
     813                 :         pScaledProgress =
     814               0 :             GDALCreateScaledProgress( dfProgressRatio, 1.0, pfnProgress, NULL );
     815                 : 
     816                 :         eErr = GDALMultiFilter( hTargetBand, hMaskBand, hFiltMaskBand, 
     817                 :                                 nSmoothingIterations,
     818               0 :                                 GDALScaledProgress, pScaledProgress );
     819                 : 
     820               0 :         GDALDestroyScaledProgress( pScaledProgress );
     821                 :     }
     822                 : 
     823                 : /* -------------------------------------------------------------------- */
     824                 : /*      Close and clean up temporary files. Free working buffers        */
     825                 : /* -------------------------------------------------------------------- */
     826               1 : end:
     827               1 :     CPLFree(panLastY);
     828               1 :     CPLFree(panThisY);
     829               1 :     CPLFree(panTopDownY);
     830               1 :     CPLFree(pafLastValue);
     831               1 :     CPLFree(pafThisValue);
     832               1 :     CPLFree(pafTopDownValue);
     833               1 :     CPLFree(pafScanline);
     834               1 :     CPLFree(pabyMask);
     835               1 :     CPLFree(pabyFiltMask);
     836                 : 
     837               1 :     GDALClose( hYDS );
     838               1 :     GDALClose( hValDS );
     839               1 :     GDALClose( hFiltMaskDS );
     840                 : 
     841               1 :     GDALDeleteDataset( hDriver, osYTmpFile );
     842               1 :     GDALDeleteDataset( hDriver, osValTmpFile );
     843               1 :     GDALDeleteDataset( hDriver, osFiltMaskTmpFile );
     844                 : 
     845               1 :     return eErr;
     846                 : }

Generated by: LTP GCOV extension version 1.5