LCOV - code coverage report
Current view: directory - alg - rasterfill.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 260 0 0.0 %
Date: 2010-01-09 Functions: 3 0 0.0 %

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

Generated by: LCOV version 1.7