Skip to content

Commit

Permalink
continues removing of stats from raster layer
Browse files Browse the repository at this point in the history
  • Loading branch information
blazek committed Jul 28, 2012
1 parent 42dc71f commit 540df9c
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 132 deletions.
5 changes: 2 additions & 3 deletions python/core/qgsrasterbandstats.sip
Expand Up @@ -13,9 +13,8 @@ class QgsRasterBandStats
QString bandName;
/** \brief The gdal band number (starts at 1)*/
int bandNumber;
/** \brief A flag to indicate whether this RasterBandStats struct
* is completely populated */
bool statsGathered;
/** \brief Collected statistics */
int statsGathered;
/** \brief The minimum cell value in the raster band. NO_DATA values
* are ignored. This does not use the gdal GetMinimum function. */
double minimumValue;
Expand Down
107 changes: 57 additions & 50 deletions src/core/qgsrasterdataprovider.cpp
Expand Up @@ -423,18 +423,20 @@ QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo )
}
#endif

QgsRasterBandStats QgsRasterDataProvider::statisticsDefaults( int theBandNo,
void QgsRasterDataProvider::initStatistics( QgsRasterBandStats &theStatistics,
int theBandNo,
int theStats,
const QgsRectangle & theExtent,
int theSampleSize )
{
QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) );

QgsRasterBandStats myRasterBandStats;
myRasterBandStats.bandName = generateBandName( theBandNo );
myRasterBandStats.bandNumber = theBandNo;
theStatistics.bandName = generateBandName( theBandNo );
theStatistics.bandNumber = theBandNo;
theStatistics.statsGathered = theStats;

QgsRectangle myExtent = theExtent.isEmpty() ? extent() : theExtent;
myRasterBandStats.extent = myExtent;
theStatistics.extent = myExtent;

if ( theSampleSize > 0 )
{
Expand All @@ -452,39 +454,39 @@ QgsRasterBandStats QgsRasterDataProvider::statisticsDefaults( int theBandNo,
}
QgsDebugMsg( QString( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ) );

myRasterBandStats.width = static_cast <int>( myExtent.width() / xRes );
myRasterBandStats.height = static_cast <int>( myExtent.height() / yRes );
theStatistics.width = static_cast <int>( myExtent.width() / xRes );
theStatistics.height = static_cast <int>( myExtent.height() / yRes );
}
else
{
if ( capabilities() & Size )
{
myRasterBandStats.width = xSize();
myRasterBandStats.height = ySize();
theStatistics.width = xSize();
theStatistics.height = ySize();
}
else
{
myRasterBandStats.width = 1000;
myRasterBandStats.height = 1000;
theStatistics.width = 1000;
theStatistics.height = 1000;
}
}
QgsDebugMsg( QString( "myRasterBandStats.width = %1 myRasterBandStats.height = %2" ).arg( myRasterBandStats.width ).arg( myRasterBandStats.height ) );

return myRasterBandStats;
QgsDebugMsg( QString( "theStatistics.width = %1 theStatistics.height = %2" ).arg( theStatistics.width ).arg( theStatistics.height ) );
}

bool QgsRasterDataProvider::hasStatistics( int theBandNo,
int theStats,
const QgsRectangle & theExtent,
int theSampleSize )
{
QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) );
QgsDebugMsg( QString( "theBandNo = %1 theStats = %2 theSampleSize = %3" ).arg( theBandNo ).arg( theStats ).arg( theSampleSize ) );
if ( mStatistics.size() == 0 ) return false;

QgsRasterBandStats myRasterBandStats = statisticsDefaults( theBandNo, theExtent, theSampleSize );
QgsRasterBandStats myRasterBandStats;
initStatistics( myRasterBandStats, theBandNo, theStats, theExtent, theSampleSize );

foreach( QgsRasterBandStats stats, mStatistics )
{
if ( stats == myRasterBandStats )
if ( stats.contains( myRasterBandStats ) )
{
QgsDebugMsg( "Has cached statistics." );
return true;
Expand All @@ -495,15 +497,20 @@ bool QgsRasterDataProvider::hasStatistics( int theBandNo,

// Find cached
QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo,
int theStats,
const QgsRectangle & theExtent,
int theSampleSize )
{
QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) );
QgsRasterBandStats myRasterBandStats = statisticsDefaults( theBandNo, theExtent, theSampleSize );
QgsDebugMsg( QString( "theBandNo = %1 theStats = %2 theSampleSize = %3" ).arg( theBandNo ).arg( theStats ).arg( theSampleSize ) );

// TODO: null values set on raster layer!!!

QgsRasterBandStats myRasterBandStats;
initStatistics( myRasterBandStats, theBandNo, theStats, theExtent, theSampleSize );

foreach( QgsRasterBandStats stats, mStatistics )
{
if ( stats == myRasterBandStats )
if ( stats.contains( myRasterBandStats ) )
{
QgsDebugMsg( "Using cached statistics." );
return stats;
Expand Down Expand Up @@ -618,57 +625,57 @@ QgsRasterBandStats QgsRasterDataProvider::bandStatistics( int theBandNo,

CPLFree( myData );

myRasterBandStats.statsGathered = true;
myRasterBandStats.statsGathered = QgsRasterBandStats::All;
mStatistics.append( myRasterBandStats );

return myRasterBandStats;
}

QgsRasterHistogram QgsRasterDataProvider::histogramDefaults( int theBandNo,
void QgsRasterDataProvider::initHistogram( QgsRasterHistogram &theHistogram,
int theBandNo,
int theBinCount,
double theMinimum, double theMaximum,
const QgsRectangle & theExtent,
int theSampleSize,
bool theIncludeOutOfRange )
{
QgsRasterHistogram myHistogram;
myHistogram.bandNumber = theBandNo;
myHistogram.minimum = theMinimum;
myHistogram.maximum = theMaximum;
myHistogram.includeOutOfRange = theIncludeOutOfRange;
theHistogram.bandNumber = theBandNo;
theHistogram.minimum = theMinimum;
theHistogram.maximum = theMaximum;
theHistogram.includeOutOfRange = theIncludeOutOfRange;

int mySrcDataType = srcDataType( theBandNo );

if ( qIsNaN( myHistogram.minimum ) )
if ( qIsNaN( theHistogram.minimum ) )
{
if ( mySrcDataType == QgsRasterDataProvider::Byte )
{
myHistogram.minimum = 0; // see histogram() for shift for rounding
theHistogram.minimum = 0; // see histogram() for shift for rounding
}
else
{
// We need statistcs -> avoid histogramDefaults in hasHistogram if possible
// TODO: use approximated statistics if aproximated histogram is requested
// (theSampleSize > 0)
QgsRasterBandStats stats = bandStatistics( theBandNo, theExtent, theSampleSize );
myHistogram.minimum = stats.minimumValue;
QgsRasterBandStats stats = bandStatistics( theBandNo, QgsRasterBandStats::Min, theExtent, theSampleSize );
theHistogram.minimum = stats.minimumValue;
}
}
if ( qIsNaN( myHistogram.maximum ) )
if ( qIsNaN( theHistogram.maximum ) )
{
if ( mySrcDataType == QgsRasterDataProvider::Byte )
{
myHistogram.maximum = 255;
theHistogram.maximum = 255;
}
else
{
QgsRasterBandStats stats = bandStatistics( theBandNo, theExtent, theSampleSize );
myHistogram.maximum = stats.maximumValue;
QgsRasterBandStats stats = bandStatistics( theBandNo, QgsRasterBandStats::Max, theExtent, theSampleSize );
theHistogram.maximum = stats.maximumValue;
}
}

QgsRectangle myExtent = theExtent.isEmpty() ? extent() : theExtent;
myHistogram.extent = myExtent;
theHistogram.extent = myExtent;

if ( theSampleSize > 0 )
{
Expand All @@ -686,23 +693,23 @@ QgsRasterHistogram QgsRasterDataProvider::histogramDefaults( int theBandNo,
}
QgsDebugMsg( QString( "xRes = %1 yRes = %2" ).arg( xRes ).arg( yRes ) );

myHistogram.width = static_cast <int>( myExtent.width() / xRes );
myHistogram.height = static_cast <int>( myExtent.height() / yRes );
theHistogram.width = static_cast <int>( myExtent.width() / xRes );
theHistogram.height = static_cast <int>( myExtent.height() / yRes );
}
else
{
if ( capabilities() & Size )
{
myHistogram.width = xSize();
myHistogram.height = ySize();
theHistogram.width = xSize();
theHistogram.height = ySize();
}
else
{
myHistogram.width = 1000;
myHistogram.height = 1000;
theHistogram.width = 1000;
theHistogram.height = 1000;
}
}
QgsDebugMsg( QString( "myHistogram.width = %1 myHistogram.height = %2" ).arg( myHistogram.width ).arg( myHistogram.height ) );
QgsDebugMsg( QString( "theHistogram.width = %1 theHistogram.height = %2" ).arg( theHistogram.width ).arg( theHistogram.height ) );

int myBinCount = theBinCount;
if ( myBinCount == 0 )
Expand All @@ -714,14 +721,12 @@ QgsRasterHistogram QgsRasterDataProvider::histogramDefaults( int theBandNo,
else
{
// There is no best default value, to display something reasonable in histogram chart, binCount should be small, OTOH, to get precise data for cumulative cut, the number should be big. Because it is easier to define fixed lower value for the chart, we calc optimum binCount for higher resolution (to avoid calculating that where histogram() is used. In any any case, it does not make sense to use more than width*height;
myBinCount = myHistogram.width * myHistogram.height;
myBinCount = theHistogram.width * theHistogram.height;
if ( myBinCount > 1000 ) myBinCount = 1000;
}
}
myHistogram.binCount = myBinCount;
QgsDebugMsg( QString( "myHistogram.binCount = %1" ).arg( myHistogram.binCount ) );

return myHistogram;
theHistogram.binCount = myBinCount;
QgsDebugMsg( QString( "theHistogram.binCount = %1" ).arg( theHistogram.binCount ) );
}

bool QgsRasterDataProvider::hasHistogram( int theBandNo,
Expand All @@ -736,7 +741,8 @@ bool QgsRasterDataProvider::hasHistogram( int theBandNo,
// do other checks which dont need statistics before histogramDefaults()
if ( mHistograms.size() == 0 ) return false;

QgsRasterHistogram myHistogram = histogramDefaults( theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );
QgsRasterHistogram myHistogram;
initHistogram( myHistogram, theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );

foreach( QgsRasterHistogram histogram, mHistograms )
{
Expand All @@ -758,7 +764,8 @@ QgsRasterHistogram QgsRasterDataProvider::histogram( int theBandNo,
{
QgsDebugMsg( QString( "theBandNo = %1 theBinCount = %2 theMinimum = %3 theMaximum = %4 theSampleSize = %5" ).arg( theBandNo ).arg( theBinCount ).arg( theMinimum ).arg( theMaximum ).arg( theSampleSize ) );

QgsRasterHistogram myHistogram = histogramDefaults( theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );
QgsRasterHistogram myHistogram;
initHistogram( myHistogram, theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );

// Find cached
foreach( QgsRasterHistogram histogram, mHistograms )
Expand Down
24 changes: 14 additions & 10 deletions src/core/qgsrasterdataprovider.h
Expand Up @@ -359,16 +359,19 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast

/** \brief Get band statistics.
* @param theBandNo The band (number).
* @param theStats Requested statistics
* @param theExtent Extent used to calc histogram, if empty, whole raster extent is used.
* @param theSampleSize Approximate number of cells in sample. If 0, all cells (whole raster will be used). If raster does not have exact size (WCS without exact size for example), provider decides size of sample.
* @return Band statistics.
*/
virtual QgsRasterBandStats bandStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

/** \brief Returns true if histogram is available (cached, already calculated), the parameters are the same as in histogram() */
virtual bool hasStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

Expand Down Expand Up @@ -551,18 +554,19 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
QList <QgsRasterHistogram> mHistograms;

/** Fill in histogram defaults if not specified */
virtual QgsRasterHistogram histogramDefaults( int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );
void initHistogram( QgsRasterHistogram &theHistogram, int theBandNo,
int theBinCount = 0,
double theMinimum = std::numeric_limits<double>::quiet_NaN(),
double theMaximum = std::numeric_limits<double>::quiet_NaN(),
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0,
bool theIncludeOutOfRange = false );

/** Fill in statistics defaults if not specified */
virtual QgsRasterBandStats statisticsDefaults( int theBandNo,
const QgsRectangle & theExtent = QgsRectangle(),
int theBinCount = 0 );
void initStatistics( QgsRasterBandStats &theStatistics, int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theBinCount = 0 );

};
#endif
25 changes: 19 additions & 6 deletions src/core/raster/qgsrasterbandstats.h
Expand Up @@ -33,10 +33,23 @@
class CORE_EXPORT QgsRasterBandStats
{
public:
enum Stats
{
None = 0,
Min = 1,
Max = 1 << 1,
Range = 1 << 2,
Sum = 1 << 3,
Mean = 1 << 4,
StdDev = 1 << 5,
SumOfSquares = 1 << 6,
All = Min | Max | Range | Sum | Mean | StdDev | SumOfSquares
};

QgsRasterBandStats()
{
bandName = "";
statsGathered = false;
statsGathered = None;
minimumValue = std::numeric_limits<double>::max();
maximumValue = std::numeric_limits<double>::min();
range = 0.0;
Expand All @@ -50,12 +63,13 @@ class CORE_EXPORT QgsRasterBandStats
}

/*! Compares region, size etc. not collected statistics */
bool operator==( const QgsRasterBandStats &s ) const
bool contains( const QgsRasterBandStats &s ) const
{
return ( s.bandNumber == bandNumber &&
s.extent == extent &&
s.width == width &&
s.height == height );
s.height == height &&
s.statsGathered == ( statsGathered & s.statsGathered ) );
}

/** \brief The name of the band that these stats belong to. */
Expand Down Expand Up @@ -88,9 +102,8 @@ class CORE_EXPORT QgsRasterBandStats
/** \brief The standard deviation of the cell values. */
double stdDev;

/** \brief A flag to indicate whether this RasterBandStats struct
* is completely populated */
bool statsGathered;
/** \brief Collected statistics */
int statsGathered;

/** \brief The sum of all cells in the band. NO_DATA values are excluded. */
double sum;
Expand Down

0 comments on commit 540df9c

Please sign in to comment.