Skip to content

Commit e74a28b

Browse files
committed
fix histogram and stats compute (set bapprox=false) for gdal provider ; fix histogram display for non-Byte data
1 parent 3c13f3c commit e74a28b

File tree

4 files changed

+77
-208
lines changed

4 files changed

+77
-208
lines changed

src/app/qgsrasterlayerproperties.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,8 +1300,7 @@ void QgsRasterLayerProperties::refreshHistogram()
13001300

13011301
if ( ! computeHistogram( false ) )
13021302
{
1303-
// TODO - check raster min/max and min/max of default histogram
1304-
QgsDebugMsg( QString( "raster does not have cached histo" ) );
1303+
QgsDebugMsg( QString( "raster does not have cached histogram" ) );
13051304
stackedWidget2->setCurrentIndex( 2 );
13061305
return;
13071306
}
@@ -1419,6 +1418,8 @@ void QgsRasterLayerProperties::refreshHistogram()
14191418
bool myFirstIteration = true;
14201419
/* get selected band list, if mHistoShowBands != ShowAll */
14211420
QList< int > mySelectedBands = histoSelectedBands();
1421+
double myBinXStep = 1;
1422+
double myBinX = 0;
14221423

14231424
for ( int myIteratorInt = 1;
14241425
myIteratorInt <= myBandCountInt;
@@ -1442,15 +1443,28 @@ void QgsRasterLayerProperties::refreshHistogram()
14421443
QVector<double> myX2Data;
14431444
QVector<double> myY2Data;
14441445
#endif
1446+
// calculate first bin x value and bin step size if not Byte data
1447+
if ( mRasterLayer->dataProvider()->srcDataType( myIteratorInt ) != QgsRasterDataProvider::Byte )
1448+
{
1449+
myBinXStep = myRasterBandStats.range / BINCOUNT;
1450+
myBinX = myRasterBandStats.minimumValue + myBinXStep / 2.0;
1451+
}
1452+
else
1453+
{
1454+
myBinXStep = 1;
1455+
myBinX = 0;
1456+
}
1457+
14451458
for ( int myBin = 0; myBin < BINCOUNT; myBin++ )
14461459
{
14471460
int myBinValue = myRasterBandStats.histogramVector->at( myBin );
14481461
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
1449-
data << QPointF( myBin, myBinValue );
1462+
data << QPointF( myBinX, myBinValue );
14501463
#else
1451-
myX2Data.append( double( myBin ) );
1464+
myX2Data.append( double( myBinX ) );
14521465
myY2Data.append( double( myBinValue ) );
14531466
#endif
1467+
myBinX += myBinXStep;
14541468
}
14551469
#if defined(QWT_VERSION) && QWT_VERSION>=0x060000
14561470
mypCurve->setSamples( data );
@@ -1472,9 +1486,10 @@ void QgsRasterLayerProperties::refreshHistogram()
14721486
// for x axis use band pixel values rather than gdal hist. bin values
14731487
// subtract -0.5 to prevent rounding errors
14741488
// see http://www.gdal.org/classGDALRasterBand.html#3f8889607d3b2294f7e0f11181c201c8
1489+
// fix x range for non-Byte data
14751490
mpPlot->setAxisScale( QwtPlot::xBottom,
1476-
mHistoMin - 0.5,
1477-
mHistoMax + 0.5 );
1491+
mHistoMin - myBinXStep / 2,
1492+
mHistoMax + myBinXStep / 2 );
14781493

14791494
mpPlot->replot();
14801495

@@ -1982,7 +1997,6 @@ void QgsRasterLayerProperties::histoActionTriggered( QAction* action )
19821997
// Load actions
19831998
else if ( actionName.left( 5 ) == "Load " )
19841999
{
1985-
QgsRasterBandStats myRasterBandStats;
19862000
QVector<int> myBands;
19872001
double minMaxValues[2];
19882002
bool ok = false;

src/core/raster/qgsrasterlayer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
371371
return myNullReturnStats;
372372
}
373373

374+
// TODO this is buggy - because the stats might have changed (e.g. theIgnoreOutOfRangeFlag in populateHistogram())
375+
// should have a pointer to the stats instead
374376
QgsRasterBandStats myRasterBandStats = mRasterStatsList[theBandNo - 1];
375377
myRasterBandStats.bandNumber = theBandNo;
376378

@@ -384,6 +386,7 @@ const QgsRasterBandStats QgsRasterLayer::bandStatistics( int theBandNo )
384386
QgsDebugMsg( "adding stats to stats collection at position " + QString::number( theBandNo - 1 ) );
385387
//add this band to the class stats map
386388
mRasterStatsList[theBandNo - 1] = myRasterBandStats;
389+
387390
emit drawingProgress( mHeight, mHeight ); //reset progress
388391
QgsDebugMsg( "Stats collection completed returning" );
389392
return myRasterBandStats;
@@ -1422,7 +1425,7 @@ QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
14221425
}
14231426

14241427
/*
1425-
* @param theBandNoInt - which band to compute the histogram for
1428+
* @param theBandNoInt - which band to find out if has a cached histogram
14261429
* @param theBinCountInt - how many 'bins' to categorise the data into
14271430
*/
14281431
bool QgsRasterLayer::hasCachedHistogram( int theBandNo, int theBinCount )

src/providers/gdal/qgsgdalprovider.cpp

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,24 +1426,25 @@ bool QgsGdalProvider::hasCachedHistogram( int theBandNo, int theBinCount )
14261426
if ( ! myGdalBand )
14271427
return false;
14281428

1429-
// get default histo
1429+
// get default histogram with force=false to see if there is a cached histo
14301430
double myMinVal, myMaxVal;
1431-
QgsRasterBandStats theBandStats = bandStatistics( theBandNo );
1432-
double myerval = ( theBandStats.maximumValue - theBandStats.minimumValue ) / theBinCount;
1433-
myMinVal = theBandStats.minimumValue - 0.1*myerval;
1434-
myMaxVal = theBandStats.maximumValue + 0.1*myerval;
1435-
int *myHistogramArray=0;
1436-
CPLErr myError = GDALGetDefaultHistogram( myGdalBand, &myMinVal, &myMaxVal,
1437-
&theBinCount, &myHistogramArray, false,
1438-
NULL, NULL );
1439-
if( myHistogramArray )
1431+
int myBinCount;
1432+
int *myHistogramArray = 0;
1433+
CPLErr myError = GDALGetDefaultHistogram( myGdalBand, &myMinVal, &myMaxVal,
1434+
&myBinCount, &myHistogramArray, false,
1435+
NULL, NULL );
1436+
if ( myHistogramArray )
14401437
VSIFree( myHistogramArray );
14411438

14421439
// if there was any error/warning assume the histogram is not valid or non-existent
14431440
if ( myError != CE_None )
14441441
return false;
1445-
return true;
14461442

1443+
// make sure the cached histo has the same number of bins than requested
1444+
if ( myBinCount != theBinCount )
1445+
return false;
1446+
1447+
return true;
14471448
}
14481449

14491450
void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & theBandStats, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
@@ -1460,34 +1461,58 @@ void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & the
14601461
theIgnoreOutOfRangeFlag != theBandStats.isHistogramOutOfRange ||
14611462
theHistogramEstimatedFlag != theBandStats.isHistogramEstimated )
14621463
{
1464+
QgsDebugMsg( "Computing histogram" );
14631465
theBandStats.histogramVector->clear();
14641466
theBandStats.isHistogramEstimated = theHistogramEstimatedFlag;
14651467
theBandStats.isHistogramOutOfRange = theIgnoreOutOfRangeFlag;
14661468
int *myHistogramArray = new int[theBinCount];
14671469

1468-
#if 0
1469-
CPLErr GDALRasterBand::GetHistogram(
1470-
double dfMin,
1471-
double dfMax,
1472-
int nBuckets,
1473-
int * panHistogram,
1474-
int bIncludeOutOfRange,
1475-
int bApproxOK,
1476-
GDALProgressFunc pfnProgress,
1477-
void * pProgressData
1478-
)
1479-
#endif
1480-
14811470
QgsGdalProgress myProg;
14821471
myProg.type = ProgressHistogram;
14831472
myProg.provider = this;
1484-
double myerval = ( theBandStats.maximumValue - theBandStats.minimumValue ) / theBinCount;
14851473

1474+
#if 0 // this is the old method
1475+
1476+
double myerval = ( theBandStats.maximumValue - theBandStats.minimumValue ) / theBinCount;
14861477
GDALGetRasterHistogram( myGdalBand, theBandStats.minimumValue - 0.1*myerval,
14871478
theBandStats.maximumValue + 0.1*myerval, theBinCount, myHistogramArray,
14881479
theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag, progressCallback,
14891480
&myProg ); //this is the arg for our custom gdal progress callback
14901481

1482+
#else // this is the new method, which gets a "Default" histogram
1483+
1484+
// calculate min/max like in GDALRasterBand::GetDefaultHistogram, but don't call it directly
1485+
// because there is no bApproxOK argument - that is lacking from the API
1486+
double myMinVal, myMaxVal;
1487+
const char* pszPixelType = GDALGetMetadataItem( myGdalBand, "PIXELTYPE", "IMAGE_STRUCTURE" );
1488+
int bSignedByte = ( pszPixelType != NULL && EQUAL( pszPixelType, "SIGNEDBYTE" ) );
1489+
1490+
if ( GDALGetRasterDataType( myGdalBand ) == GDT_Byte && !bSignedByte )
1491+
{
1492+
myMinVal = -0.5;
1493+
myMaxVal = 255.5;
1494+
}
1495+
else
1496+
{
1497+
CPLErr eErr = CE_Failure;
1498+
double dfHalfBucket = 0;
1499+
eErr = GDALGetRasterStatistics( myGdalBand, TRUE, TRUE, &myMinVal, &myMaxVal, NULL, NULL );
1500+
if ( eErr != CE_None )
1501+
return;
1502+
dfHalfBucket = ( myMaxVal - myMinVal ) / ( 2 * theBinCount );
1503+
myMinVal -= dfHalfBucket;
1504+
myMaxVal += dfHalfBucket;
1505+
}
1506+
1507+
CPLErr myError = GDALGetRasterHistogram( myGdalBand, myMinVal, myMaxVal,
1508+
theBinCount, myHistogramArray,
1509+
theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag, progressCallback,
1510+
&myProg ); //this is the arg for our custom gdal progress callback
1511+
if ( myError != CE_None )
1512+
return;
1513+
1514+
#endif
1515+
14911516
for ( int myBin = 0; myBin < theBinCount; myBin++ )
14921517
{
14931518
if ( myHistogramArray[myBin] < 0 ) //can't have less than 0 pixels of any value
@@ -2063,7 +2088,8 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo )
20632088
{
20642089
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
20652090
QgsRasterBandStats myRasterBandStats;
2066-
int bApproxOK = true;
2091+
// int bApproxOK = true;
2092+
int bApproxOK = false; //as we asked for stats, don't get approx values
20672093
double pdfMin;
20682094
double pdfMax;
20692095
double pdfMean;
@@ -2072,16 +2098,6 @@ QgsRasterBandStats QgsGdalProvider::bandStatistics( int theBandNo )
20722098
myProg.type = ProgressHistogram;
20732099
myProg.provider = this;
20742100

2075-
// double myerval =
2076-
// GDALComputeRasterStatistics (
2077-
// myGdalBand, bApproxOK, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev,
2078-
// progressCallback, &myProg ) ;
2079-
// double myerval =
2080-
// GDALGetRasterStatistics ( myGdalBand, bApproxOK, TRUE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev);
2081-
// double myerval =
2082-
// GDALGetRasterStatisticsProgress ( myGdalBand, bApproxOK, TRUE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev,
2083-
// progressCallback, &myProg );
2084-
20852101
// try to fetch the cached stats (bForce=FALSE)
20862102
CPLErr myerval =
20872103
GDALGetRasterStatistics( myGdalBand, bApproxOK, FALSE, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev );

0 commit comments

Comments
 (0)