Quantum GIS API Documentation  1.8
src/analysis/raster/qgsninecellfilter.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           qgsninecellfilter.h  -  description
00003                              -------------------
00004     begin                : August 6th, 2009
00005     copyright            : (C) 2009 by Marco Hugentobler
00006     email                : marco dot hugentobler at karto dot baug dot ethz dot ch
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "qgsninecellfilter.h"
00019 #include "cpl_string.h"
00020 #include <QProgressDialog>
00021 
00022 #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
00023 #define TO8(x) (x).toUtf8().constData()
00024 #else
00025 #define TO8(x) (x).toLocal8Bit().constData()
00026 #endif
00027 
00028 QgsNineCellFilter::QgsNineCellFilter( const QString& inputFile, const QString& outputFile, const QString& outputFormat )
00029     : mInputFile( inputFile ), mOutputFile( outputFile ), mOutputFormat( outputFormat ), mCellSizeX( -1 ), mCellSizeY( -1 ),
00030     mInputNodataValue( -1 ), mOutputNodataValue( -1 ), mZFactor( 1.0 )
00031 {
00032 
00033 }
00034 
00035 QgsNineCellFilter::QgsNineCellFilter()
00036 {
00037 
00038 }
00039 
00040 QgsNineCellFilter::~QgsNineCellFilter()
00041 {
00042 
00043 }
00044 
00045 int QgsNineCellFilter::processRaster( QProgressDialog* p )
00046 {
00047   GDALAllRegister();
00048 
00049   //open input file
00050   int xSize, ySize;
00051   GDALDatasetH  inputDataset = openInputFile( xSize, ySize );
00052   if ( inputDataset == NULL )
00053   {
00054     return 1; //opening of input file failed
00055   }
00056 
00057   //output driver
00058   GDALDriverH outputDriver = openOutputDriver();
00059   if ( outputDriver == 0 )
00060   {
00061     return 2;
00062   }
00063 
00064   GDALDatasetH outputDataset = openOutputFile( inputDataset, outputDriver );
00065   if ( outputDataset == NULL )
00066   {
00067     return 3; //create operation on output file failed
00068   }
00069 
00070   //open first raster band for reading (operation is only for single band raster)
00071   GDALRasterBandH rasterBand = GDALGetRasterBand( inputDataset, 1 );
00072   if ( rasterBand == NULL )
00073   {
00074     GDALClose( inputDataset );
00075     GDALClose( outputDataset );
00076     return 4;
00077   }
00078   mInputNodataValue = GDALGetRasterNoDataValue( rasterBand, NULL );
00079 
00080   GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 );
00081   if ( outputRasterBand == NULL )
00082   {
00083     GDALClose( inputDataset );
00084     GDALClose( outputDataset );
00085     return 5;
00086   }
00087   //try to set -9999 as nodata value
00088   GDALSetRasterNoDataValue( outputRasterBand, -9999 );
00089   mOutputNodataValue = GDALGetRasterNoDataValue( outputRasterBand, NULL );
00090 
00091   if ( ySize < 3 ) //we require at least three rows (should be true for most datasets)
00092   {
00093     GDALClose( inputDataset );
00094     GDALClose( outputDataset );
00095     return 6;
00096   }
00097 
00098   //keep only three scanlines in memory at a time
00099   float* scanLine1 = ( float * ) CPLMalloc( sizeof( float ) * xSize );
00100   float* scanLine2 = ( float * ) CPLMalloc( sizeof( float ) * xSize );
00101   float* scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize );
00102 
00103   float* resultLine = ( float * ) CPLMalloc( sizeof( float ) * xSize );
00104 
00105   if ( p )
00106   {
00107     p->setMaximum( ySize );
00108   }
00109 
00110   //values outside the layer extent (if the 3x3 window is on the border) are sent to the processing method as (input) nodata values
00111   for ( int i = 0; i < ySize; ++i )
00112   {
00113     if ( p )
00114     {
00115       p->setValue( i );
00116     }
00117 
00118     if ( p && p->wasCanceled() )
00119     {
00120       break;
00121     }
00122 
00123     if ( i == 0 )
00124     {
00125       //fill scanline 1 with (input) nodata for the values above the first row and feed scanline2 with the first row
00126       for ( int a = 0; a < xSize; ++a )
00127       {
00128         scanLine1[a] = mInputNodataValue;
00129       }
00130       GDALRasterIO( rasterBand, GF_Read, 0, 0, xSize, 1, scanLine2, xSize, 1, GDT_Float32, 0, 0 );
00131     }
00132     else
00133     {
00134       //normally fetch only scanLine3 and release scanline 1 if we move forward one row
00135       CPLFree( scanLine1 );
00136       scanLine1 = scanLine2;
00137       scanLine2 = scanLine3;
00138       scanLine3 = ( float * ) CPLMalloc( sizeof( float ) * xSize );
00139     }
00140 
00141     if ( i == ySize - 1 ) //fill the row below the bottom with nodata values
00142     {
00143       for ( int a = 0; a < xSize; ++a )
00144       {
00145         scanLine3[a] = mInputNodataValue;
00146       }
00147     }
00148     else
00149     {
00150       GDALRasterIO( rasterBand, GF_Read, 0, i + 1, xSize, 1, scanLine3, xSize, 1, GDT_Float32, 0, 0 );
00151     }
00152 
00153     for ( int j = 0; j < xSize; ++j )
00154     {
00155       if ( j == 0 )
00156       {
00157         resultLine[j] = processNineCellWindow( &mInputNodataValue, &scanLine1[j], &scanLine1[j+1], &mInputNodataValue, &scanLine2[j],
00158                                                &scanLine2[j+1], &mInputNodataValue, &scanLine3[j], &scanLine3[j+1] );
00159       }
00160       else if ( j == xSize - 1 )
00161       {
00162         resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &mInputNodataValue, &scanLine2[j-1], &scanLine2[j],
00163                                                &mInputNodataValue, &scanLine3[j-1], &scanLine3[j], &mInputNodataValue );
00164       }
00165       else
00166       {
00167         resultLine[j] = processNineCellWindow( &scanLine1[j-1], &scanLine1[j], &scanLine1[j+1], &scanLine2[j-1], &scanLine2[j],
00168                                                &scanLine2[j+1], &scanLine3[j-1], &scanLine3[j], &scanLine3[j+1] );
00169       }
00170     }
00171 
00172     GDALRasterIO( outputRasterBand, GF_Write, 0, i, xSize, 1, resultLine, xSize, 1, GDT_Float32, 0, 0 );
00173   }
00174 
00175   if ( p )
00176   {
00177     p->setValue( ySize );
00178   }
00179 
00180   CPLFree( resultLine );
00181   CPLFree( scanLine1 );
00182   CPLFree( scanLine2 );
00183   CPLFree( scanLine3 );
00184 
00185   GDALClose( inputDataset );
00186 
00187   if ( p && p->wasCanceled() )
00188   {
00189     //delete the dataset without closing (because it is faster)
00190     GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() );
00191     return 7;
00192   }
00193   GDALClose( outputDataset );
00194 
00195   return 0;
00196 }
00197 
00198 GDALDatasetH QgsNineCellFilter::openInputFile( int& nCellsX, int& nCellsY )
00199 {
00200   GDALDatasetH inputDataset = GDALOpen( TO8( mInputFile ), GA_ReadOnly );
00201   if ( inputDataset != NULL )
00202   {
00203     nCellsX = GDALGetRasterXSize( inputDataset );
00204     nCellsY = GDALGetRasterYSize( inputDataset );
00205 
00206     //we need at least one band
00207     if ( GDALGetRasterCount( inputDataset ) < 1 )
00208     {
00209       GDALClose( inputDataset );
00210       return NULL;
00211     }
00212   }
00213   return inputDataset;
00214 }
00215 
00216 GDALDriverH QgsNineCellFilter::openOutputDriver()
00217 {
00218   char **driverMetadata;
00219 
00220   //open driver
00221   GDALDriverH outputDriver = GDALGetDriverByName( mOutputFormat.toLocal8Bit().data() );
00222 
00223   if ( outputDriver == NULL )
00224   {
00225     return outputDriver; //return NULL, driver does not exist
00226   }
00227 
00228   driverMetadata = GDALGetMetadata( outputDriver, NULL );
00229   if ( !CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) )
00230   {
00231     return NULL; //driver exist, but it does not support the create operation
00232   }
00233 
00234   return outputDriver;
00235 }
00236 
00237 GDALDatasetH QgsNineCellFilter::openOutputFile( GDALDatasetH inputDataset, GDALDriverH outputDriver )
00238 {
00239   if ( inputDataset == NULL )
00240   {
00241     return NULL;
00242   }
00243 
00244   int xSize = GDALGetRasterXSize( inputDataset );
00245   int ySize = GDALGetRasterYSize( inputDataset );;
00246 
00247   //open output file
00248   char **papszOptions = NULL;
00249   GDALDatasetH outputDataset = GDALCreate( outputDriver, mOutputFile.toLocal8Bit().data(), xSize, ySize, 1, GDT_Float32, papszOptions );
00250   if ( outputDataset == NULL )
00251   {
00252     return outputDataset;
00253   }
00254 
00255   //get geotransform from inputDataset
00256   double geotransform[6];
00257   if ( GDALGetGeoTransform( inputDataset, geotransform ) != CE_None )
00258   {
00259     GDALClose( outputDataset );
00260     return NULL;
00261   }
00262   GDALSetGeoTransform( outputDataset, geotransform );
00263 
00264   //make sure mCellSizeX and mCellSizeY are always > 0
00265   mCellSizeX = geotransform[1];
00266   if ( mCellSizeX < 0 )
00267   {
00268     mCellSizeX = -mCellSizeX;
00269   }
00270   mCellSizeY = geotransform[5];
00271   if ( mCellSizeY < 0 )
00272   {
00273     mCellSizeY = -mCellSizeY;
00274   }
00275 
00276   const char* projection = GDALGetProjectionRef( inputDataset );
00277   GDALSetProjection( outputDataset, projection );
00278 
00279   return outputDataset;
00280 }
00281 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines