LCOV - code coverage report
Current view: directory - alg - rasterfill.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 264 107 40.5 %
Date: 2012-04-28 Functions: 3 1 33.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: rasterfill.cpp 22395 2011-05-17 21:27:03Z warmerdam $
       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 22395 2011-05-17 21:27:03Z warmerdam $");
      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               0 : GDALFilterLine( float *pafLastLine, float *pafThisLine, float *pafNextLine,
      46                 :                 float *pafOutLine,
      47                 :                 GByte *pabyLastTMask, GByte *pabyThisTMask, GByte*pabyNextTMask,
      48                 :                 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] = (float) (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               0 : GDALMultiFilter( GDALRasterBandH hTargetBand, 
     145                 :                  GDALRasterBandH hTargetMaskBand, 
     146                 :                  GDALRasterBandH hFiltMaskBand,
     147                 :                  int nIterations,
     148                 :                  GDALProgressFunc pfnProgress, 
     149                 :                  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                 : 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               2 : GDALFillNodata( GDALRasterBandH hTargetBand, 
     388                 :                 GDALRasterBandH hMaskBand,
     389                 :                 double dfMaxSearchDist, 
     390                 :                 int bDeprecatedOption,
     391                 :                 int nSmoothingIterations,
     392                 :                 char **papszOptions,
     393                 :                 GDALProgressFunc pfnProgress, 
     394                 :                 void * pProgressArg )
     395                 : 
     396                 : {
     397               2 :     VALIDATE_POINTER1( hTargetBand, "GDALFillNodata", CE_Failure );
     398                 : 
     399               2 :     int nXSize = GDALGetRasterBandXSize( hTargetBand );
     400               2 :     int nYSize = GDALGetRasterBandYSize( hTargetBand );
     401               2 :     CPLErr eErr = CE_None;
     402                 : 
     403                 :     // Special "x" pixel values identifying pixels as special.
     404                 :     GUInt32 nNoDataVal;
     405                 :     GDALDataType eType;
     406                 : 
     407               2 :     if( dfMaxSearchDist == 0.0 )
     408               0 :         dfMaxSearchDist = MAX(nXSize,nYSize) + 1;
     409                 : 
     410               2 :     int nMaxSearchDist = (int) floor(dfMaxSearchDist);
     411                 : 
     412               2 :     if( nXSize > 65533 || nYSize > 65533 )
     413                 :     {
     414               0 :         eType = GDT_UInt32;
     415               0 :         nNoDataVal = 4000002;
     416                 :     }
     417                 :     else
     418                 :     {
     419               2 :         eType = GDT_UInt16;
     420               2 :         nNoDataVal = 65535;
     421                 :     }
     422                 : 
     423               2 :     if( hMaskBand == NULL )
     424               0 :         hMaskBand = GDALGetMaskBand( hTargetBand );
     425                 : 
     426                 :     /* If there are smoothing iterations, reserve 10% of the progress for them */
     427               2 :     double dfProgressRatio = (nSmoothingIterations > 0) ? 0.9 : 1.0;
     428                 : 
     429                 : /* -------------------------------------------------------------------- */
     430                 : /*      Initialize progress counter.                                    */
     431                 : /* -------------------------------------------------------------------- */
     432               2 :     if( pfnProgress == NULL )
     433               0 :         pfnProgress = GDALDummyProgress;
     434                 : 
     435               2 :     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               2 :     GDALDriverH  hDriver = GDALGetDriverByName( "GTiff" );
     445               2 :     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", "BIGTIFF=IF_SAFER", 
     455                 :                                          NULL };
     456               2 :     CPLString osTmpFile = CPLGenerateTempFilename("");
     457               2 :     CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";
     458                 :     
     459                 :     hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1, 
     460               2 :                        eType, (char **) apszOptions );
     461                 :     
     462               2 :     if( hYDS == NULL )
     463               0 :         return CE_Failure;
     464                 : 
     465               2 :     hYBand = GDALGetRasterBand( hYDS, 1 );
     466                 : 
     467                 : /* -------------------------------------------------------------------- */
     468                 : /*      Create a work file to hold the pixel value associated with      */
     469                 : /*      the "last xy value" pixel.                                      */
     470                 : /* -------------------------------------------------------------------- */
     471                 :     GDALDatasetH hValDS;
     472                 :     GDALRasterBandH hValBand;
     473               2 :     CPLString osValTmpFile = osTmpFile + "fill_val_work.tif";
     474                 : 
     475                 :     hValDS = GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
     476                 :                          GDALGetRasterDataType( hTargetBand ), 
     477               2 :                          (char **) apszOptions );
     478                 :     
     479               2 :     if( hValDS == NULL )
     480               0 :         return CE_Failure;
     481                 : 
     482               2 :     hValBand = GDALGetRasterBand( hValDS, 1 );
     483                 : 
     484                 : /* -------------------------------------------------------------------- */
     485                 : /*      Create a mask file to make it clear what pixels can be filtered */
     486                 : /*      on the filtering pass.                                          */
     487                 : /* -------------------------------------------------------------------- */
     488                 :     GDALDatasetH hFiltMaskDS;
     489                 :     GDALRasterBandH hFiltMaskBand;
     490               2 :     CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";
     491                 :     
     492                 :     hFiltMaskDS = 
     493                 :         GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
     494               2 :                     GDT_Byte, (char **) apszOptions );
     495                 :     
     496               2 :     if( hFiltMaskDS == NULL )
     497               0 :         return CE_Failure;
     498                 : 
     499               2 :     hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );
     500                 : 
     501                 : /* -------------------------------------------------------------------- */
     502                 : /*      Allocate buffers for last scanline and this scanline.           */
     503                 : /* -------------------------------------------------------------------- */
     504                 :     GUInt32 *panLastY, *panThisY, *panTopDownY;
     505                 :     float   *pafLastValue, *pafThisValue, *pafScanline, *pafTopDownValue;
     506                 :     GByte   *pabyMask, *pabyFiltMask;
     507                 :     int     iX;
     508                 :     int     iY;
     509                 : 
     510               2 :     panLastY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     511               2 :     panThisY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     512               2 :     panTopDownY = (GUInt32 *) VSICalloc(nXSize,sizeof(GUInt32));
     513               2 :     pafLastValue = (float *) VSICalloc(nXSize,sizeof(float));
     514               2 :     pafThisValue = (float *) VSICalloc(nXSize,sizeof(float));
     515               2 :     pafTopDownValue = (float *) VSICalloc(nXSize,sizeof(float));
     516               2 :     pafScanline = (float *) VSICalloc(nXSize,sizeof(float));
     517               2 :     pabyMask = (GByte *) VSICalloc(nXSize,1);
     518               2 :     pabyFiltMask = (GByte *) VSICalloc(nXSize,1);
     519               2 :     if (panLastY == NULL || panThisY == NULL || panTopDownY == NULL ||
     520                 :         pafLastValue == NULL || pafThisValue == NULL || pafTopDownValue == NULL ||
     521                 :         pafScanline == NULL || pabyMask == NULL || pabyFiltMask == NULL)
     522                 :     {
     523                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     524               0 :                  "Could not allocate enough memory for temporary buffers");
     525                 : 
     526               0 :         eErr = CE_Failure;
     527               0 :         goto end;
     528                 :     }
     529                 : 
     530              42 :     for( iX = 0; iX < nXSize; iX++ )
     531                 :     {
     532              40 :         panLastY[iX] = nNoDataVal;
     533                 :     }
     534                 : 
     535                 : /* ==================================================================== */
     536                 : /*      Make first pass from top to bottom collecting the "last         */
     537                 : /*      known value" for each column and writing it out to the work     */
     538                 : /*      files.                                                          */
     539                 : /* ==================================================================== */
     540                 :     
     541              42 :     for( iY = 0; iY < nYSize && eErr == CE_None; iY++ )
     542                 :     {
     543                 : /* -------------------------------------------------------------------- */
     544                 : /*      Read data and mask for this line.                               */
     545                 : /* -------------------------------------------------------------------- */
     546                 :         eErr = 
     547                 :             GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
     548              40 :                           pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
     549                 : 
     550              40 :         if( eErr != CE_None )
     551               0 :             break;
     552                 : 
     553                 :         eErr = 
     554                 :             GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
     555              40 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     556                 :         
     557              40 :         if( eErr != CE_None )
     558               0 :             break;
     559                 :         
     560                 : /* -------------------------------------------------------------------- */
     561                 : /*      Figure out the most recent pixel for each column.               */
     562                 : /* -------------------------------------------------------------------- */
     563                 :         
     564             840 :         for( iX = 0; iX < nXSize; iX++ )
     565                 :         {
     566             800 :             if( pabyMask[iX] )
     567                 :             {
     568             800 :                 pafThisValue[iX] = pafScanline[iX];
     569             800 :                 panThisY[iX] = iY;
     570                 :             }
     571               0 :             else if( iY - panLastY[iX] <= dfMaxSearchDist )
     572                 :             {
     573               0 :                 pafThisValue[iX] = pafLastValue[iX];
     574               0 :                 panThisY[iX] = panLastY[iX];
     575                 :             }
     576                 :             else
     577                 :             {
     578               0 :                 panThisY[iX] = nNoDataVal;
     579                 :             }
     580                 :         }
     581                 :         
     582                 : /* -------------------------------------------------------------------- */
     583                 : /*      Write out best index/value to working files.                    */
     584                 : /* -------------------------------------------------------------------- */
     585                 :         eErr = GDALRasterIO( hYBand, GF_Write, 0, iY, nXSize, 1, 
     586              40 :                              panThisY, nXSize, 1, GDT_UInt32, 0, 0 );
     587              40 :         if( eErr != CE_None )
     588               0 :             break;
     589                 : 
     590                 :         eErr = GDALRasterIO( hValBand, GF_Write, 0, iY, nXSize, 1, 
     591              40 :                              pafThisValue, nXSize, 1, GDT_Float32, 0, 0 );
     592              40 :         if( eErr != CE_None )
     593               0 :             break;
     594                 : 
     595                 : /* -------------------------------------------------------------------- */
     596                 : /*      Flip this/last buffers.                                         */
     597                 : /* -------------------------------------------------------------------- */
     598                 :         {
     599              40 :             float *pafTmp = pafThisValue;
     600              40 :             pafThisValue = pafLastValue;
     601              40 :             pafLastValue = pafTmp;
     602                 : 
     603              40 :             GUInt32 *panTmp = panThisY;
     604              40 :             panThisY = panLastY;
     605              40 :             panLastY = panTmp;
     606                 :         }
     607                 : 
     608                 : /* -------------------------------------------------------------------- */
     609                 : /*      report progress.                                                */
     610                 : /* -------------------------------------------------------------------- */
     611              40 :         if( eErr == CE_None
     612                 :             && !pfnProgress( dfProgressRatio * (0.5*(iY+1) / (double)nYSize), 
     613                 :                              "Filling...", pProgressArg ) )
     614                 :         {
     615               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     616               0 :             eErr = CE_Failure;
     617                 :         }
     618                 :     }
     619                 : 
     620                 : /* ==================================================================== */
     621                 : /*      Now we will do collect similar this/last information from       */
     622                 : /*      bottom to top and use it in combination with the top to         */
     623                 : /*      bottom search info to interpolate.                              */
     624                 : /* ==================================================================== */
     625              42 :     for( iY = nYSize-1; iY >= 0 && eErr == CE_None; iY-- )
     626                 :     {
     627                 :         eErr = 
     628                 :             GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
     629              40 :                           pabyMask, nXSize, 1, GDT_Byte, 0, 0 );
     630                 : 
     631              40 :         if( eErr != CE_None )
     632               0 :             break;
     633                 : 
     634                 :         eErr = 
     635                 :             GDALRasterIO( hTargetBand, GF_Read, 0, iY, nXSize, 1, 
     636              40 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     637                 :         
     638              40 :         if( eErr != CE_None )
     639               0 :             break;
     640                 :         
     641                 : /* -------------------------------------------------------------------- */
     642                 : /*      Figure out the most recent pixel for each column.               */
     643                 : /* -------------------------------------------------------------------- */
     644                 :         
     645             840 :         for( iX = 0; iX < nXSize; iX++ )
     646                 :         {
     647             800 :             if( pabyMask[iX] )
     648                 :             {
     649             800 :                 pafThisValue[iX] = pafScanline[iX];
     650             800 :                 panThisY[iX] = iY;
     651                 :             }
     652               0 :             else if( panLastY[iX] - iY <= dfMaxSearchDist )
     653                 :             {
     654               0 :                 pafThisValue[iX] = pafLastValue[iX];
     655               0 :                 panThisY[iX] = panLastY[iX];
     656                 :             }
     657                 :             else
     658                 :             {
     659               0 :                 panThisY[iX] = nNoDataVal;
     660                 :             }
     661                 :         }
     662                 :         
     663                 : /* -------------------------------------------------------------------- */
     664                 : /*      Load the last y and corresponding value from the top down pass. */
     665                 : /* -------------------------------------------------------------------- */
     666                 :         eErr = 
     667                 :             GDALRasterIO( hYBand, GF_Read, 0, iY, nXSize, 1, 
     668              40 :                           panTopDownY, nXSize, 1, GDT_UInt32, 0, 0 );
     669                 : 
     670              40 :         if( eErr != CE_None )
     671               0 :             break;
     672                 : 
     673                 :         eErr = 
     674                 :             GDALRasterIO( hValBand, GF_Read, 0, iY, nXSize, 1, 
     675              40 :                           pafTopDownValue, nXSize, 1, GDT_Float32, 0, 0 );
     676                 : 
     677              40 :         if( eErr != CE_None )
     678               0 :             break;
     679                 : 
     680                 : /* -------------------------------------------------------------------- */
     681                 : /*      Attempt to interpolate any pixels that are nodata.              */
     682                 : /* -------------------------------------------------------------------- */
     683              40 :         memset( pabyFiltMask, 0, nXSize );
     684             840 :         for( iX = 0; iX < nXSize; iX++ )
     685                 :         {
     686                 :             int iStep, iQuad;
     687             800 :             int nThisMaxSearchDist = nMaxSearchDist;
     688                 : 
     689                 :             // If this was a valid target - no change.
     690             800 :             if( pabyMask[iX] )
     691             800 :                 continue;
     692                 : 
     693                 :             // Quadrants 0:topleft, 1:bottomleft, 2:topright, 3:bottomright
     694                 :             double adfQuadDist[4];
     695                 :             double adfQuadValue[4];
     696                 : 
     697               0 :             for( iQuad = 0; iQuad < 4; iQuad++ )
     698               0 :                 adfQuadDist[iQuad] = dfMaxSearchDist + 1.0;
     699                 :             
     700                 :             // Step left and right by one pixel searching for the closest 
     701                 :             // target value for each quadrant. 
     702               0 :             for( iStep = 0; iStep < nThisMaxSearchDist; iStep++ )
     703                 :             {
     704               0 :                 int iLeftX = MAX(0,iX - iStep);
     705               0 :                 int iRightX = MIN(nXSize-1,iX + iStep);
     706                 :                 
     707                 :                 // top left includes current line 
     708               0 :                 QUAD_CHECK(adfQuadDist[0],adfQuadValue[0], 
     709                 :                            iLeftX, panTopDownY[iLeftX], iX, iY,
     710                 :                            pafTopDownValue[iLeftX] );
     711                 : 
     712                 :                 // bottom left 
     713               0 :                 QUAD_CHECK(adfQuadDist[1],adfQuadValue[1], 
     714                 :                            iLeftX, panLastY[iLeftX], iX, iY, 
     715                 :                            pafLastValue[iLeftX] );
     716                 : 
     717                 :                 // top right and bottom right do no include center pixel.
     718               0 :                 if( iStep == 0 )
     719               0 :                      continue;
     720                 :                     
     721                 :                 // top right includes current line 
     722               0 :                 QUAD_CHECK(adfQuadDist[2],adfQuadValue[2], 
     723                 :                            iRightX, panTopDownY[iRightX], iX, iY,
     724                 :                            pafTopDownValue[iRightX] );
     725                 : 
     726                 :                 // bottom right
     727               0 :                 QUAD_CHECK(adfQuadDist[3],adfQuadValue[3], 
     728                 :                            iRightX, panLastY[iRightX], iX, iY,
     729                 :                            pafLastValue[iRightX] );
     730                 : 
     731                 :                 // every four steps, recompute maximum distance.
     732               0 :                 if( (iStep & 0x3) == 0 )
     733                 :                     nThisMaxSearchDist = (int) floor(
     734               0 :                         MAX(MAX(adfQuadDist[0],adfQuadDist[1]),
     735               0 :                             MAX(adfQuadDist[2],adfQuadDist[3])) );
     736                 :             }
     737                 : 
     738               0 :             double dfWeightSum = 0.0;
     739               0 :             double dfValueSum = 0.0;
     740                 :             
     741               0 :             for( iQuad = 0; iQuad < 4; iQuad++ )
     742                 :             {
     743               0 :                 if( adfQuadDist[iQuad] <= dfMaxSearchDist )
     744                 :                 {
     745               0 :                     double dfWeight = 1.0 / adfQuadDist[iQuad];
     746                 : 
     747               0 :                     dfWeightSum += dfWeight;
     748               0 :                     dfValueSum += adfQuadValue[iQuad] * dfWeight;
     749                 :                 }
     750                 :             }
     751                 : 
     752               0 :             if( dfWeightSum > 0.0 )
     753                 :             {
     754               0 :                 pabyMask[iX] = 255;
     755               0 :                 pabyFiltMask[iX] = 255;
     756               0 :                 pafScanline[iX] = (float) (dfValueSum / dfWeightSum);
     757                 :             }
     758                 : 
     759                 :         }
     760                 : 
     761                 : /* -------------------------------------------------------------------- */
     762                 : /*      Write out the updated data and mask information.                */
     763                 : /* -------------------------------------------------------------------- */
     764                 :         eErr = 
     765                 :             GDALRasterIO( hTargetBand, GF_Write, 0, iY, nXSize, 1, 
     766              40 :                           pafScanline, nXSize, 1, GDT_Float32, 0, 0 );
     767                 :         
     768              40 :         if( eErr != CE_None )
     769               0 :             break;
     770                 : 
     771                 :         eErr = 
     772                 :             GDALRasterIO( hFiltMaskBand, GF_Write, 0, iY, nXSize, 1, 
     773              40 :                           pabyFiltMask, nXSize, 1, GDT_Byte, 0, 0 );
     774                 :         
     775              40 :         if( eErr != CE_None )
     776               0 :             break;
     777                 : 
     778                 : /* -------------------------------------------------------------------- */
     779                 : /*      Flip this/last buffers.                                         */
     780                 : /* -------------------------------------------------------------------- */
     781                 :         {
     782              40 :             float *pafTmp = pafThisValue;
     783              40 :             pafThisValue = pafLastValue;
     784              40 :             pafLastValue = pafTmp;
     785                 :             
     786              40 :             GUInt32 *panTmp = panThisY;
     787              40 :             panThisY = panLastY;
     788              40 :             panLastY = panTmp;
     789                 :         }
     790                 : 
     791                 : /* -------------------------------------------------------------------- */
     792                 : /*      report progress.                                                */
     793                 : /* -------------------------------------------------------------------- */
     794              40 :         if( eErr == CE_None
     795                 :             && !pfnProgress( dfProgressRatio*(0.5+0.5*(nYSize-iY) / (double)nYSize), 
     796                 :                              "Filling...", pProgressArg ) )
     797                 :         {
     798               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     799               0 :             eErr = CE_Failure;
     800                 :         }
     801                 :     }        
     802                 : 
     803                 : /* ==================================================================== */
     804                 : /*      Now we will do iterative average filters over the               */
     805                 : /*      interpolated values to smooth things out and make linear        */
     806                 : /*      artifacts less obvious.                                         */
     807                 : /* ==================================================================== */
     808               2 :     if( eErr == CE_None && nSmoothingIterations > 0 )
     809                 :     {
     810                 :         // force masks to be to flushed and recomputed.
     811               0 :         GDALFlushRasterCache( hMaskBand );
     812                 : 
     813                 :         void *pScaledProgress;
     814                 :         pScaledProgress =
     815               0 :             GDALCreateScaledProgress( dfProgressRatio, 1.0, pfnProgress, NULL );
     816                 : 
     817                 :         eErr = GDALMultiFilter( hTargetBand, hMaskBand, hFiltMaskBand, 
     818                 :                                 nSmoothingIterations,
     819               0 :                                 GDALScaledProgress, pScaledProgress );
     820                 : 
     821               0 :         GDALDestroyScaledProgress( pScaledProgress );
     822                 :     }
     823                 : 
     824                 : /* -------------------------------------------------------------------- */
     825                 : /*      Close and clean up temporary files. Free working buffers        */
     826                 : /* -------------------------------------------------------------------- */
     827                 : end:
     828               2 :     CPLFree(panLastY);
     829               2 :     CPLFree(panThisY);
     830               2 :     CPLFree(panTopDownY);
     831               2 :     CPLFree(pafLastValue);
     832               2 :     CPLFree(pafThisValue);
     833               2 :     CPLFree(pafTopDownValue);
     834               2 :     CPLFree(pafScanline);
     835               2 :     CPLFree(pabyMask);
     836               2 :     CPLFree(pabyFiltMask);
     837                 : 
     838               2 :     GDALClose( hYDS );
     839               2 :     GDALClose( hValDS );
     840               2 :     GDALClose( hFiltMaskDS );
     841                 : 
     842               2 :     GDALDeleteDataset( hDriver, osYTmpFile );
     843               2 :     GDALDeleteDataset( hDriver, osValTmpFile );
     844               2 :     GDALDeleteDataset( hDriver, osFiltMaskTmpFile );
     845                 : 
     846               2 :     return eErr;
     847                 : }

Generated by: LCOV version 1.7