Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages  

overview.cpp

00001 /******************************************************************************
00002  * $Id: overview_cpp-source.html,v 1.5 2000/11/06 04:49:01 warmerda Exp $
00003  *
00004  * Project:  GDAL Core
00005  * Purpose:  Helper code to implement overview support in different drivers.
00006  * Author:   Frank Warmerdam, warmerda@home.com
00007  *
00008  ******************************************************************************
00009  * Copyright (c) 2000, Frank Warmerdam
00010  *
00011  * Permission is hereby granted, free of charge, to any person obtaining a
00012  * copy of this software and associated documentation files (the "Software"),
00013  * to deal in the Software without restriction, including without limitation
00014  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00015  * and/or sell copies of the Software, and to permit persons to whom the
00016  * Software is furnished to do so, subject to the following conditions:
00017  *
00018  * The above copyright notice and this permission notice shall be included
00019  * in all copies or substantial portions of the Software.
00020  *
00021  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00022  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00024  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00025  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00026  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00027  * DEALINGS IN THE SOFTWARE.
00028  ******************************************************************************
00029  *
00030  * $Log: overview_cpp-source.html,v $
00030  * Revision 1.5  2000/11/06 04:49:01  warmerda
00030  * *** empty log message ***
00030  *
00031  * Revision 1.4  2000/08/18 15:25:06  warmerda
00032  * added cascading overview regeneration to speed up averaged overviews
00033  *
00034  * Revision 1.3  2000/07/17 17:08:45  warmerda
00035  * added support for complex data
00036  *
00037  * Revision 1.2  2000/06/26 22:17:58  warmerda
00038  * added scaled progress support
00039  *
00040  * Revision 1.1  2000/04/21 21:54:05  warmerda
00041  * New
00042  *
00043  */
00044 
00045 #include "gdal_priv.h"
00046 
00047 /************************************************************************/
00048 /*                       GDALDownsampleChunk32R()                       */
00049 /************************************************************************/
00050 
00051 static CPLErr
00052 GDALDownsampleChunk32R( int nSrcWidth, int nSrcHeight, 
00053                         float * pafChunk, int nChunkYOff, int nChunkYSize,
00054                         GDALRasterBand * poOverview,
00055                         const char * pszResampling )
00056 
00057 {
00058     int      nDstYOff, nDstYOff2, nOXSize, nOYSize;
00059     float    *pafDstScanline;
00060 
00061     nOXSize = poOverview->GetXSize();
00062     nOYSize = poOverview->GetYSize();
00063 
00064     pafDstScanline = (float *) CPLMalloc(nOXSize * sizeof(float));
00065 
00066 /* -------------------------------------------------------------------- */
00067 /*      Figure out the line to start writing to, and the first line     */
00068 /*      to not write to.  In theory this approach should ensure that    */
00069 /*      every output line will be written if all input chunks are       */
00070 /*      processed.                                                      */
00071 /* -------------------------------------------------------------------- */
00072     nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
00073     nDstYOff2 = (int) 
00074         (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
00075 
00076     if( nChunkYOff + nChunkYSize == nSrcHeight )
00077         nDstYOff2 = nOYSize;
00078     
00079 /* ==================================================================== */
00080 /*      Loop over destination scanlines.                                */
00081 /* ==================================================================== */
00082     for( int iDstLine = nDstYOff; iDstLine < nDstYOff2; iDstLine++ )
00083     {
00084         float *pafSrcScanline;
00085         int   nSrcYOff, nSrcYOff2, iDstPixel;
00086 
00087         nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
00088         if( nSrcYOff < nChunkYOff )
00089             nSrcYOff = nChunkYOff;
00090         
00091         nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
00092         if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
00093             nSrcYOff2 = nSrcHeight;
00094         if( nSrcYOff2 > nChunkYOff + nChunkYSize )
00095             nSrcYOff2 = nChunkYOff + nChunkYSize;
00096 
00097         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nSrcWidth);
00098 
00099 /* -------------------------------------------------------------------- */
00100 /*      Loop over destination pixels                                    */
00101 /* -------------------------------------------------------------------- */
00102         for( iDstPixel = 0; iDstPixel < nOXSize; iDstPixel++ )
00103         {
00104             int   nSrcXOff, nSrcXOff2;
00105 
00106             nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
00107             nSrcXOff2 = (int) 
00108                 (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
00109             if( nSrcXOff2 > nSrcWidth )
00110                 nSrcXOff2 = nSrcWidth;
00111             
00112             if( EQUALN(pszResampling,"NEAR",4) )
00113             {
00114                 pafDstScanline[iDstPixel] = pafSrcScanline[nSrcXOff];
00115             }
00116             else if( EQUALN(pszResampling,"AVER",4) )
00117             {
00118                 double dfTotal = 0.0;
00119                 int    nCount = 0, iX, iY;
00120 
00121                 for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
00122                 {
00123                     for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
00124                     {
00125                         dfTotal += pafSrcScanline[iX+(iY-nSrcYOff)*nSrcWidth];
00126                         nCount++;
00127                     }
00128                 }
00129                 
00130                 CPLAssert( nCount > 0 );
00131                 if( nCount == 0 )
00132                 {
00133                     pafDstScanline[iDstPixel] = 0.0;
00134                 }
00135                 else
00136                     pafDstScanline[iDstPixel] = dfTotal / nCount;
00137             }
00138         }
00139 
00140         poOverview->RasterIO( GF_Write, 0, iDstLine, nOXSize, 1, 
00141                               pafDstScanline, nOXSize, 1, GDT_Float32, 
00142                               0, 0 );
00143     }
00144 
00145     CPLFree( pafDstScanline );
00146 
00147     return CE_None;
00148 }
00149 
00150 /************************************************************************/
00151 /*                       GDALDownsampleChunkC32R()                      */
00152 /************************************************************************/
00153 
00154 static CPLErr
00155 GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight, 
00156                          float * pafChunk, int nChunkYOff, int nChunkYSize,
00157                          GDALRasterBand * poOverview,
00158                          const char * pszResampling )
00159     
00160 {
00161     int      nDstYOff, nDstYOff2, nOXSize, nOYSize;
00162     float    *pafDstScanline;
00163 
00164     nOXSize = poOverview->GetXSize();
00165     nOYSize = poOverview->GetYSize();
00166 
00167     pafDstScanline = (float *) CPLMalloc(nOXSize * sizeof(float) * 2);
00168 
00169 /* -------------------------------------------------------------------- */
00170 /*      Figure out the line to start writing to, and the first line     */
00171 /*      to not write to.  In theory this approach should ensure that    */
00172 /*      every output line will be written if all input chunks are       */
00173 /*      processed.                                                      */
00174 /* -------------------------------------------------------------------- */
00175     nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
00176     nDstYOff2 = (int) 
00177         (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
00178 
00179     if( nChunkYOff + nChunkYSize == nSrcHeight )
00180         nDstYOff2 = nOYSize;
00181     
00182 /* ==================================================================== */
00183 /*      Loop over destination scanlines.                                */
00184 /* ==================================================================== */
00185     for( int iDstLine = nDstYOff; iDstLine < nDstYOff2; iDstLine++ )
00186     {
00187         float *pafSrcScanline;
00188         int   nSrcYOff, nSrcYOff2, iDstPixel;
00189 
00190         nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
00191         if( nSrcYOff < nChunkYOff )
00192             nSrcYOff = nChunkYOff;
00193         
00194         nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
00195         if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
00196             nSrcYOff2 = nSrcHeight;
00197         if( nSrcYOff2 > nChunkYOff + nChunkYSize )
00198             nSrcYOff2 = nChunkYOff + nChunkYSize;
00199 
00200         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nSrcWidth);
00201 
00202 /* -------------------------------------------------------------------- */
00203 /*      Loop over destination pixels                                    */
00204 /* -------------------------------------------------------------------- */
00205         for( iDstPixel = 0; iDstPixel < nOXSize; iDstPixel++ )
00206         {
00207             int   nSrcXOff, nSrcXOff2;
00208 
00209             nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
00210             nSrcXOff2 = (int) 
00211                 (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
00212             if( nSrcXOff2 > nSrcWidth )
00213                 nSrcXOff2 = nSrcWidth;
00214             
00215             if( EQUALN(pszResampling,"NEAR",4) )
00216             {
00217                 pafDstScanline[iDstPixel*2] = pafSrcScanline[nSrcXOff*2];
00218                 pafDstScanline[iDstPixel*2+1] = pafSrcScanline[nSrcXOff*2+1];
00219             }
00220             else if( EQUALN(pszResampling,"AVER",4) )
00221             {
00222                 double dfTotalR = 0.0, dfTotalI = 0.0;
00223                 int    nCount = 0, iX, iY;
00224 
00225                 for( iY = nSrcYOff; iY < nSrcYOff2; iY++ )
00226                 {
00227                     for( iX = nSrcXOff; iX < nSrcXOff2; iX++ )
00228                     {
00229                         dfTotalR += pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2];
00230                         dfTotalI += pafSrcScanline[iX*2+(iY-nSrcYOff)*nSrcWidth*2+1];
00231                         nCount++;
00232                     }
00233                 }
00234                 
00235                 CPLAssert( nCount > 0 );
00236                 if( nCount == 0 )
00237                 {
00238                     pafDstScanline[iDstPixel*2] = 0.0;
00239                     pafDstScanline[iDstPixel*2+1] = 0.0;
00240                 }
00241                 else
00242                 {
00243                     pafDstScanline[iDstPixel*2  ] = dfTotalR / nCount;
00244                     pafDstScanline[iDstPixel*2+1] = dfTotalI / nCount;
00245                 }
00246             }
00247         }
00248 
00249         poOverview->RasterIO( GF_Write, 0, iDstLine, nOXSize, 1, 
00250                               pafDstScanline, nOXSize, 1, GDT_CFloat32, 
00251                               0, 0 );
00252     }
00253 
00254     CPLFree( pafDstScanline );
00255 
00256     return CE_None;
00257 }
00258 
00259 /************************************************************************/
00260 /*                  GDALRegenerateCascadingOverviews()                  */
00261 /*                                                                      */
00262 /*      Generate a list of overviews in order from largest to           */
00263 /*      smallest, computing each from the next larger.                  */
00264 /************************************************************************/
00265 
00266 static CPLErr
00267 GDALRegenerateCascadingOverviews( 
00268     GDALRasterBand *poSrcBand, int nOverviews, GDALRasterBand **papoOvrBands, 
00269     const char * pszResampling, 
00270     GDALProgressFunc pfnProgress, void * pProgressData )
00271 
00272 {
00273 /* -------------------------------------------------------------------- */
00274 /*      First, we must put the overviews in order from largest to       */
00275 /*      smallest.                                                       */
00276 /* -------------------------------------------------------------------- */
00277     int   i, j;
00278 
00279     for( i = 0; i < nOverviews-1; i++ )
00280     {
00281         for( j = 0; j < nOverviews - i - 1; j++ )
00282         {
00283 
00284             if( papoOvrBands[j]->GetXSize() 
00285                 * (float) papoOvrBands[j]->GetYSize() <
00286                 papoOvrBands[j+1]->GetXSize()
00287                 * (float) papoOvrBands[j+1]->GetYSize() )
00288             {
00289                 GDALRasterBand * poTempBand;
00290 
00291                 poTempBand = papoOvrBands[j];
00292                 papoOvrBands[j] = papoOvrBands[j+1];
00293                 papoOvrBands[j+1] = poTempBand;
00294             }
00295         }
00296     }
00297 
00298 /* -------------------------------------------------------------------- */
00299 /*      Count total pixels so we can prepare appropriate scaled         */
00300 /*      progress functions.                                             */
00301 /* -------------------------------------------------------------------- */
00302     double       dfTotalPixels = 0.0;
00303 
00304     for( i = 0; i < nOverviews; i++ )
00305     {
00306         dfTotalPixels += papoOvrBands[i]->GetXSize()
00307             * (double) papoOvrBands[i]->GetYSize();
00308     }
00309 
00310 /* -------------------------------------------------------------------- */
00311 /*      Generate all the bands.                                         */
00312 /* -------------------------------------------------------------------- */
00313     double      dfPixelsProcessed = 0.0;
00314 
00315     for( i = 0; i < nOverviews; i++ )
00316     {
00317         void    *pScaledProgressData;
00318         double  dfPixels;
00319         GDALRasterBand *poBaseBand;
00320         CPLErr  eErr;
00321 
00322         if( i == 0 )
00323             poBaseBand = poSrcBand;
00324         else
00325             poBaseBand = papoOvrBands[i-1];
00326 
00327         dfPixels = papoOvrBands[i]->GetXSize() 
00328             * (double) papoOvrBands[i]->GetYSize();
00329 
00330         pScaledProgressData = GDALCreateScaledProgress( 
00331             dfPixelsProcessed / dfTotalPixels,
00332             (dfPixelsProcessed + dfPixels) / dfTotalPixels, 
00333             pfnProgress, pProgressData );
00334 
00335         eErr = GDALRegenerateOverviews( poBaseBand, 1, papoOvrBands + i, 
00336                                         pszResampling, 
00337                                         GDALScaledProgress, 
00338                                         pScaledProgressData );
00339         GDALDestroyScaledProgress( pScaledProgressData );
00340 
00341         if( eErr != CE_None )
00342             return eErr;
00343 
00344         dfPixelsProcessed += dfPixels;
00345     }
00346 
00347     return CE_None;
00348 }
00349 
00350 /************************************************************************/
00351 /*                      GDALRegenerateOverviews()                       */
00352 /************************************************************************/
00353 CPLErr 
00354 GDALRegenerateOverviews( GDALRasterBand *poSrcBand,
00355                          int nOverviews, GDALRasterBand **papoOvrBands, 
00356                          const char * pszResampling, 
00357                          GDALProgressFunc pfnProgress, void * pProgressData )
00358 
00359 {
00360     int    nFullResYChunk, nWidth;
00361     int    nFRXBlockSize, nFRYBlockSize;
00362     GDALDataType eType;
00363 
00364 /* -------------------------------------------------------------------- */
00365 /*      If we are operating on multiple overviews, and using            */
00366 /*      averaging, lets do them in cascading order to reduce the        */
00367 /*      amount of computation.                                          */
00368 /* -------------------------------------------------------------------- */
00369     if( EQUALN(pszResampling,"AVER",4) && nOverviews > 1 )
00370         return GDALRegenerateCascadingOverviews( poSrcBand, 
00371                                                  nOverviews, papoOvrBands,
00372                                                  pszResampling, 
00373                                                  pfnProgress,
00374                                                  pProgressData );
00375 
00376 /* -------------------------------------------------------------------- */
00377 /*      Setup one horizontal swath to read from the raw buffer.         */
00378 /* -------------------------------------------------------------------- */
00379     float *pafChunk;
00380 
00381     poSrcBand->GetBlockSize( &nFRXBlockSize, &nFRYBlockSize );
00382     
00383     if( nFRYBlockSize < 4 || nFRYBlockSize > 256 )
00384         nFullResYChunk = 32;
00385     else
00386         nFullResYChunk = nFRYBlockSize;
00387 
00388     if( GDALDataTypeIsComplex( poSrcBand->GetRasterDataType() ) )
00389         eType = GDT_CFloat32;
00390     else
00391         eType = GDT_Float32;
00392 
00393     nWidth = poSrcBand->GetXSize();
00394     pafChunk = (float *) 
00395         VSIMalloc((GDALGetDataTypeSize(eType)/8) * nFullResYChunk * nWidth );
00396 
00397     if( pafChunk == NULL )
00398     {
00399         CPLError( CE_Failure, CPLE_OutOfMemory, 
00400                   "Out of memory in GDALRegenerateOverviews()." );
00401 
00402         return CE_Failure;
00403     }
00404     
00405 /* -------------------------------------------------------------------- */
00406 /*      Loop over image operating on chunks.                            */
00407 /* -------------------------------------------------------------------- */
00408     int  nChunkYOff = 0;
00409 
00410     for( nChunkYOff = 0; 
00411          nChunkYOff < poSrcBand->GetYSize(); 
00412          nChunkYOff += nFullResYChunk )
00413     {
00414         if( !pfnProgress( nChunkYOff / (double) poSrcBand->GetYSize(), 
00415                           NULL, pProgressData ) )
00416         {
00417             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
00418             return CE_Failure;
00419         }
00420 
00421         if( nFullResYChunk + nChunkYOff > poSrcBand->GetYSize() )
00422             nFullResYChunk = poSrcBand->GetYSize() - nChunkYOff;
00423         
00424         /* read chunk */
00425         poSrcBand->RasterIO( GF_Read, 0, nChunkYOff, nWidth, nFullResYChunk, 
00426                              pafChunk, nWidth, nFullResYChunk, eType,
00427                              0, 0 );
00428         
00429         for( int iOverview = 0; iOverview < nOverviews; iOverview++ )
00430         {
00431             if( eType == GDT_Float32 )
00432                 GDALDownsampleChunk32R(nWidth, poSrcBand->GetYSize(), 
00433                                        pafChunk, nChunkYOff, nFullResYChunk,
00434                                        papoOvrBands[iOverview], pszResampling);
00435             else
00436                 GDALDownsampleChunkC32R(nWidth, poSrcBand->GetYSize(), 
00437                                        pafChunk, nChunkYOff, nFullResYChunk,
00438                                        papoOvrBands[iOverview], pszResampling);
00439         }
00440     }
00441 
00442     VSIFree( pafChunk );
00443     
00444 /* -------------------------------------------------------------------- */
00445 /*      It can be important to flush out data to overviews.             */
00446 /* -------------------------------------------------------------------- */
00447     for( int iOverview = 0; iOverview < nOverviews; iOverview++ )
00448         papoOvrBands[iOverview]->FlushCache();
00449 
00450     pfnProgress( 1.0, NULL, pProgressData );
00451 
00452     return CE_None;
00453 }

doxygen1.2.3-20001105 Dimitri van Heesch, © 1997-2000