continues removing of stats from raster layer

This commit is contained in:
Radim Blazek 2012-07-28 19:41:47 +02:00
parent 42dc71ff88
commit 540df9cb0d
12 changed files with 211 additions and 132 deletions

View File

@ -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;

View File

@ -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 )
{
@ -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;
@ -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;
@ -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 )
{
@ -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 )
@ -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,
@ -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 )
{
@ -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 )

View File

@ -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 );
@ -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

View File

@ -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;
@ -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. */
@ -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;

View File

@ -287,6 +287,7 @@ unsigned int QgsRasterLayer::bandCount() const
const QString QgsRasterLayer::bandName( int theBandNo )
{
#if 0
if ( theBandNo <= mRasterStatsList.size() && theBandNo > 0 )
{
//vector starts at base 0, band counts at base1!
@ -296,23 +297,30 @@ const QString QgsRasterLayer::bandName( int theBandNo )
{
return QString( "" );
}
#endif
return dataProvider()->generateBandName( theBandNo );
}
int QgsRasterLayer::bandNumber( QString const & theBandName ) const
{
for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
if ( !mDataProvider ) return 0;
for ( int myIterator = 1; myIterator <= dataProvider()->bandCount(); ++myIterator )
{
//find out the name of this band
#if 0
QgsRasterBandStats myRasterBandStats = mRasterStatsList[myIterator];
QgsDebugMsg( "myRasterBandStats.bandName: " + myRasterBandStats.bandName + " :: theBandName: "
+ theBandName );
if ( myRasterBandStats.bandName == theBandName )
#endif
QString myBandName = dataProvider()->generateBandName( myIterator );
if ( myBandName == theBandName )
{
QgsDebugMsg( "********** band " + QString::number( myRasterBandStats.bandNumber ) +
QgsDebugMsg( "********** band " + QString::number( myIterator ) +
" was found in bandNumber " + theBandName );
return myRasterBandStats.bandNumber;
return myIterator;
}
}
QgsDebugMsg( "********** no band was found in bandNumber " + theBandName );
@ -612,11 +620,13 @@ bool QgsRasterLayer::copySymbologySettings( const QgsMapLayer& theOther )
/**
* @param theBandNo the band number
* @return pointer to the color table
* @return ointer to the color table
*/
QList<QgsColorRampShader::ColorRampItem>* QgsRasterLayer::colorTable( int theBandNo )
QList<QgsColorRampShader::ColorRampItem> QgsRasterLayer::colorTable( int theBandNo )
{
return &( mRasterStatsList[theBandNo-1].colorTable );
//return &( mRasterStatsList[theBandNo-1].colorTable );
if ( !mDataProvider ) return QList<QgsColorRampShader::ColorRampItem>();
return dataProvider()->colorTable( theBandNo );
}
/**
@ -1707,6 +1717,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
mBandCount = mDataProvider->bandCount( );
for ( int i = 1; i <= mBandCount; i++ )
{
#if 0
QgsRasterBandStats myRasterBandStats;
myRasterBandStats.bandName = mDataProvider->generateBandName( i );
myRasterBandStats.bandNumber = i;
@ -1718,6 +1729,7 @@ void QgsRasterLayer::setDataProvider( QString const & provider )
myRasterBandStats.colorTable = ct;
mRasterStatsList.push_back( myRasterBandStats );
#endif
//Build a new contrast enhancement for the band and store in list
//QgsContrastEnhancement myContrastEnhancement(( QgsContrastEnhancement::QgsRasterDataType )mDataProvider->dataType( i ) );
@ -1814,7 +1826,7 @@ void QgsRasterLayer::closeDataProvider()
mPipe.remove( mDataProvider );
mDataProvider = 0;
mRasterStatsList.clear();
//mRasterStatsList.clear();
mContrastEnhancementList.clear();
mHasPyramids = false;
@ -2066,12 +2078,15 @@ void QgsRasterLayer::setNoDataValue( double theNoDataValue )
mNoDataValue = theNoDataValue;
mValidNoDataValue = true;
//Basically set the raster stats as invalid
// TODO! No data value must be set on provider and stats cleared
#if 0
QList<QgsRasterBandStats>::iterator myIterator = mRasterStatsList.begin();
while ( myIterator != mRasterStatsList.end() )
{
( *myIterator ).statsGathered = false;
++myIterator;
}
#endif
}
}
@ -2651,12 +2666,14 @@ QString QgsRasterLayer::validateBandName( QString const & theBandName )
return TRSTRING_NOT_SET;
}
if ( !mDataProvider ) return TRSTRING_NOT_SET;
//check that a valid band name was passed
QgsDebugMsg( "Looking through raster band stats for matching band name" );
for ( int myIterator = 0; myIterator < mRasterStatsList.size(); ++myIterator )
for ( int myIterator = 1; myIterator < mDataProvider->bandCount(); ++myIterator )
{
//find out the name of this band
if ( mRasterStatsList[myIterator].bandName == theBandName )
if ( mDataProvider->generateBandName( myIterator ) == theBandName );
{
QgsDebugMsg( "Matching band name found" );
return theBandName;
@ -2664,6 +2681,7 @@ QString QgsRasterLayer::validateBandName( QString const & theBandName )
}
QgsDebugMsg( "No matching band name found in raster band stats" );
#if 0
QgsDebugMsg( "Testing for non zero-buffered names" );
//TODO Remove test in v2.0 or earlier
QStringList myBandNameComponents = theBandName.split( " " );
@ -2702,6 +2720,7 @@ QString QgsRasterLayer::validateBandName( QString const & theBandName )
}
}
}
#endif
//if no matches were found default to not set
QgsDebugMsg( "All checks failed, returning '" + QSTRING_NOT_SET + "'" );

View File

@ -430,7 +430,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
bool copySymbologySettings( const QgsMapLayer& theOther );
/** \brief Get a pointer to the color table */
QList<QgsColorRampShader::ColorRampItem>* colorTable( int theBandNoInt );
QList<QgsColorRampShader::ColorRampItem> colorTable( int theBandNoInt );
/** Returns the data provider */
QgsRasterDataProvider* dataProvider();
@ -530,7 +530,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
/** \brief Returns the number of raster units per each raster pixel. In a world file, this is normally the first row (without the sign) */
double rasterUnitsPerPixel();
const RasterStatsList rasterStatsList() const { return mRasterStatsList; }
//const RasterStatsList rasterStatsList() const { return mRasterStatsList; }
/** \brief Read color table from GDAL raster band */
// Keep this for QgsRasterLayerProperties
@ -844,7 +844,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
RasterPyramidList mPyramidList;
/** \brief A collection of stats - one for each band in the layer */
RasterStatsList mRasterStatsList;
//RasterStatsList mRasterStatsList;
LayerType mRasterType;

View File

@ -91,11 +91,11 @@ void QgsPalettedRendererWidget::setFromRenderer( const QgsRasterRenderer* r )
else
{
//read default palette settings from layer
QList<QgsColorRampShader::ColorRampItem>* itemList =
QList<QgsColorRampShader::ColorRampItem> itemList =
mRasterLayer->colorTable( mBandComboBox->itemData( mBandComboBox->currentIndex() ).toInt() );
QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList->constBegin();
QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
int index = 0;
for ( ; itemIt != itemList->constEnd(); ++itemIt )
for ( ; itemIt != itemList.constEnd(); ++itemIt )
{
QTreeWidgetItem* item = new QTreeWidgetItem( mTreeWidget );
item->setText( 0, QString::number( index ) );

View File

@ -406,9 +406,9 @@ void QgsRasterHistogramWidget::refreshHistogram()
if ( ! mySelectedBands.contains( myIteratorInt ) )
continue;
}
QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( myIteratorInt );
// mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
int sampleSize = 250000; // number of sample cells
//QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( myIteratorInt );
// mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
QgsRasterHistogram myHistogram = mRasterLayer->dataProvider()->histogram( myIteratorInt, BINCOUNT, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN(), QgsRectangle(), sampleSize );
QwtPlotCurve * mypCurve = new QwtPlotCurve( tr( "Band %1" ).arg( myIteratorInt ) );
@ -424,8 +424,10 @@ void QgsRasterHistogramWidget::refreshHistogram()
// calculate first bin x value and bin step size if not Byte data
if ( mRasterLayer->dataProvider()->srcDataType( myIteratorInt ) != QgsRasterDataProvider::Byte )
{
myBinXStep = myRasterBandStats.range / BINCOUNT;
myBinX = myRasterBandStats.minimumValue + myBinXStep / 2.0;
//myBinXStep = myRasterBandStats.range / BINCOUNT;
//myBinX = myRasterBandStats.minimumValue + myBinXStep / 2.0;
myBinXStep = ( myHistogram.maximum - myHistogram.minimum ) / BINCOUNT;
myBinX = myHistogram.minimum + myBinXStep / 2.0;
}
else
{
@ -451,13 +453,13 @@ void QgsRasterHistogramWidget::refreshHistogram()
mypCurve->setData( myX2Data, myY2Data );
#endif
mypCurve->attach( mpPlot );
if ( myFirstIteration || mHistoMin > myRasterBandStats.minimumValue )
if ( myFirstIteration || mHistoMin > myHistogram.minimum )
{
mHistoMin = myRasterBandStats.minimumValue;
mHistoMin = myHistogram.minimum;
}
if ( myFirstIteration || mHistoMax < myRasterBandStats.maximumValue )
if ( myFirstIteration || mHistoMax < myHistogram.maximum )
{
mHistoMax = myRasterBandStats.maximumValue;
mHistoMax = myHistogram.maximum;
}
QgsDebugMsg( QString( "computed histo min = %1 max = %2" ).arg( mHistoMin ).arg( mHistoMax ) );
myFirstIteration = false;

View File

@ -19,10 +19,10 @@
#include "qgsrasterminmaxwidget.h"
QgsRasterMinMaxWidget::QgsRasterMinMaxWidget( QgsRasterLayer* theLayer, QWidget *parent ):
QWidget( parent )
,mLayer ( theLayer )
QWidget( parent )
, mLayer( theLayer )
{
QgsDebugMsg("Entered.");
QgsDebugMsg( "Entered." );
setupUi( this );
}
@ -32,12 +32,12 @@ QgsRasterMinMaxWidget::~QgsRasterMinMaxWidget()
void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked()
{
QgsDebugMsg("Entered.");
QgsDebugMsg( "Entered." );
foreach ( int myBand, mBands )
foreach( int myBand, mBands )
{
QgsDebugMsg( QString("myBand = %1").arg(myBand));
if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() )
QgsDebugMsg( QString( "myBand = %1" ).arg( myBand ) );
if ( myBand < 1 || myBand > mLayer->dataProvider()->bandCount() )
{
continue;
}
@ -46,10 +46,10 @@ void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked()
QgsRectangle myExtent; // empty == full
if ( mCurrentExtentRadioButton->isChecked() )
{
{
myExtent = mExtent; // current
}
QgsDebugMsg( QString("myExtent.isEmpty() = %1").arg(myExtent.isEmpty()) );
QgsDebugMsg( QString( "myExtent.isEmpty() = %1" ).arg( myExtent.isEmpty() ) );
int mySampleSize = 0; // 0 == exact
if ( mEstimateRadioButton->isChecked() )
@ -59,24 +59,24 @@ void QgsRasterMinMaxWidget::on_mLoadPushButton_clicked()
if ( mCumulativeCutRadioButton->isChecked() )
{
mLayer->dataProvider()->cumulativeCut ( myBand, 0.02, 0.98, myMin, myMax, myExtent, mySampleSize );
}
mLayer->dataProvider()->cumulativeCut( myBand, 0.02, 0.98, myMin, myMax, myExtent, mySampleSize );
}
else if ( mMinMaxRadioButton->isChecked() )
{
// TODO: consider provider minimum/maximumValue() (has to be defined well in povider)
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, myExtent, mySampleSize );
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Min | QgsRasterBandStats::Max, myExtent, mySampleSize );
myMin = myRasterBandStats.minimumValue;
myMax = myRasterBandStats.maximumValue;
}
else if ( mStdDevRadioButton->isChecked() )
{
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, myExtent, mySampleSize );
QgsRasterBandStats myRasterBandStats = mLayer->dataProvider()->bandStatistics( myBand, QgsRasterBandStats::Mean, myExtent, mySampleSize );
double myStdDev = mStdDevSpinBox->value();
myMin = myRasterBandStats.mean - ( myStdDev * myRasterBandStats.stdDev );
myMax = myRasterBandStats.mean + ( myStdDev * myRasterBandStats.stdDev );
}
emit load ( myBand, myMin, myMax );
emit load( myBand, myMin, myMax );
}
}

View File

@ -1258,7 +1258,8 @@ bool QgsGdalProvider::hasHistogram( int theBandNo,
return true;
}
QgsRasterHistogram myHistogram = histogramDefaults( theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );
QgsRasterHistogram myHistogram;
initHistogram( myHistogram, theBandNo, theBinCount, theMinimum, theMaximum, theExtent, theSampleSize, theIncludeOutOfRange );
// If not cached, check if supported by GDAL
if ( myHistogram.extent != extent() )
@ -1329,7 +1330,8 @@ QgsRasterHistogram QgsGdalProvider::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 )
@ -2002,21 +2004,28 @@ QGISEXTERN bool isValidRasterFileName( QString const & theFileNameQString, QStri
}
bool QgsGdalProvider::hasStatistics( int theBandNo,
int theStats,
const QgsRectangle & theExtent,
int theSampleSize )
{
QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) );
// First check if cached in mStatistics
if ( QgsRasterDataProvider::hasStatistics( theBandNo, theExtent, theSampleSize ) )
if ( QgsRasterDataProvider::hasStatistics( theBandNo, theStats, theExtent, theSampleSize ) )
{
return true;
}
QgsRasterBandStats myRasterBandStats = statisticsDefaults( theBandNo, theExtent, theSampleSize );
QgsRasterBandStats myRasterBandStats;
initStatistics( myRasterBandStats, theBandNo, theStats, theExtent, theSampleSize );
// If not cached, check if supported by GDAL
if ( myRasterBandStats.extent != extent() )
int supportedStats = QgsRasterBandStats::Min | QgsRasterBandStats::Max
| QgsRasterBandStats::Range | QgsRasterBandStats::Mean
| QgsRasterBandStats::StdDev;
if ( myRasterBandStats.extent != extent() ||
( theStats & ( ~supportedStats ) ) )
{
QgsDebugMsg( "Not supported by GDAL." );
return false;
@ -2041,13 +2050,19 @@ bool QgsGdalProvider::hasStatistics( int theBandNo,
// Params in GDALGetRasterStatistics must not be NULL otherwise GDAL returns
// without error even if stats are not cached
double pdfMin;
double pdfMax;
double pdfMean;
double pdfStdDev;
double dfMin, dfMax, dfMean, dfStdDev;
double *pdfMin = &dfMin;
double *pdfMax = &dfMax;
double *pdfMean = &dfMean;
double *pdfStdDev = &dfStdDev;
if ( !( theStats & QgsRasterBandStats::Min ) ) pdfMin = NULL;
if ( !( theStats & QgsRasterBandStats::Max ) ) pdfMax = NULL;
if ( !( theStats & QgsRasterBandStats::Mean ) ) pdfMean = NULL;
if ( !( theStats & QgsRasterBandStats::StdDev ) ) pdfStdDev = NULL;
// try to fetch the cached stats (bForce=FALSE)
CPLErr myerval = GDALGetRasterStatistics( myGdalBand, bApproxOK, FALSE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev );
CPLErr myerval = GDALGetRasterStatistics( myGdalBand, bApproxOK, FALSE, pdfMin, pdfMax, pdfMean, pdfStdDev );
if ( CE_None == myerval ) // CE_Warning if cached not found
{
@ -2058,29 +2073,40 @@ bool QgsGdalProvider::hasStatistics( int theBandNo,
return false;
}
QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, const QgsRectangle & theExtent, int theSampleSize )
QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, int theStats, const QgsRectangle & theExtent, int theSampleSize )
{
QgsDebugMsg( QString( "theBandNo = %1 theSampleSize = %2" ).arg( theBandNo ).arg( theSampleSize ) );
// TODO: null values set on raster layer!!!
// Currently there is no API in GDAL to collect statistics of specified extent
// or with defined sample size. We check first if we have cached stats, if not,
// and it is not possible to use GDAL we call generic provider method,
// otherwise we use GDAL (faster, cache)
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( "Using cached statistics." );
return stats;
}
}
if ( myRasterBandStats.extent != extent() )
int supportedStats = QgsRasterBandStats::Min | QgsRasterBandStats::Max
| QgsRasterBandStats::Range | QgsRasterBandStats::Mean
| QgsRasterBandStats::StdDev;
QgsDebugMsg( QString( "theStats = %1 supportedStats = %2" ).arg( theStats, 0, 2 ).arg( supportedStats, 0, 2 ) );
if ( myRasterBandStats.extent != extent() ||
( theStats & ( ~supportedStats ) ) )
{
QgsDebugMsg( "Using generic statistics." );
return QgsRasterDataProvider::bandStatistics( theBandNo, theExtent, theSampleSize );
return QgsRasterDataProvider::bandStatistics( theBandNo, theStats, theExtent, theSampleSize );
}
QgsDebugMsg( "Using GDAL statistics." );
@ -2131,10 +2157,14 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, const QgsRect
//calculate the mean
myRasterBandStats.mean = pdfMean;
myRasterBandStats.sum = 0; //not available via gdal
myRasterBandStats.elementCount = mWidth * mHeight;
//myRasterBandStats.elementCount = mWidth * mHeight;
// Sum of non NULL
myRasterBandStats.elementCount = 0; //not available via gdal
myRasterBandStats.sumOfSquares = 0; //not available via gdal
myRasterBandStats.stdDev = pdfStdDev;
myRasterBandStats.statsGathered = true;
myRasterBandStats.statsGathered = QgsRasterBandStats::Min | QgsRasterBandStats::Max
| QgsRasterBandStats::Range | QgsRasterBandStats::Mean
| QgsRasterBandStats::StdDev;
#ifdef QGISDEBUG
QgsDebugMsg( "************ STATS **************" );
@ -2145,9 +2175,6 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo, const QgsRect
QgsDebugMsg( QString( "MEAN %1" ).arg( myRasterBandStats.mean ) );
QgsDebugMsg( QString( "STDDEV %1" ).arg( myRasterBandStats.stdDev ) );
#endif
myRasterBandStats.statsGathered = true;
}
mStatistics.append( myRasterBandStats );

View File

@ -239,10 +239,12 @@ class QgsGdalProvider : public QgsRasterDataProvider
static QStringList subLayers( GDALDatasetH dataset );
bool hasStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );
QgsRasterBandStats bandStatistics( int theBandNo,
int theStats = QgsRasterBandStats::All,
const QgsRectangle & theExtent = QgsRectangle(),
int theSampleSize = 0 );

View File

@ -183,26 +183,32 @@ void TestQgsRasterLayer::landsatBasic875Qml()
}
void TestQgsRasterLayer::checkDimensions()
{
mReport += "<h2>Check Dimensions</h2>\n";
QVERIFY( mpRasterLayer->width() == 10 );
QVERIFY( mpRasterLayer->height() == 10 );
// regression check for ticket #832
// note bandStatistics call is base 1
QVERIFY( mpRasterLayer->dataProvider()->bandStatistics( 1 ).elementCount == 100 );
mReport += "<h2>Check Dimensions</h2>\n";
// TODO: elementCount is not collected by GDAL, use other stats.
//QVERIFY( mpRasterLayer->dataProvider()->bandStatistics( 1 ).elementCount == 100 );
mReport += "<p>Passed</p>";
}
void TestQgsRasterLayer::checkStats()
{
QgsRasterBandStats myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1 );
mReport += "<h2>Check Stats</h2>\n";
QgsRasterBandStats myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev );
QVERIFY( mpRasterLayer->width() == 10 );
QVERIFY( mpRasterLayer->height() == 10 );
QVERIFY( myStatistics.elementCount == 100 );
//QVERIFY( myStatistics.elementCount == 100 );
QVERIFY( myStatistics.minimumValue == 0 );
QVERIFY( myStatistics.maximumValue == 9 );
QVERIFY( myStatistics.mean == 4.5 );
QVERIFY( fabs( myStatistics.stdDev - 2.87228132326901431 )
double stdDev = 2.87228132326901431;
// TODO: verify why GDAL stdDev is so different from generic (2.88675)
mReport += QString( "stdDev = %1 expected = %2<br>\n" ).arg( myStatistics.stdDev ).arg( stdDev );
QVERIFY( fabs( myStatistics.stdDev - stdDev )
< 0.0000000000000001 );
mReport += "<h2>Check Stats</h2>\n";
mReport += "<p>Passed</p>";
}