Skip to content

Commit cf58d3e

Browse files
committed
verify that raster has cached histogram, compute on demand
1 parent 6b474fe commit cf58d3e

8 files changed

+213
-31
lines changed

src/app/qgsrasterlayerproperties.cpp

+88-21
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,9 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
330330
QMenu* menu = new QMenu( this );
331331
menu->setSeparatorsCollapsible( false );
332332
btnHistoActions->setMenu( menu );
333+
QActionGroup* group;
333334

334-
QActionGroup* group = new QActionGroup( this );
335+
group = new QActionGroup( this );
335336
group->setExclusive( false );
336337
connect( group, SIGNAL( triggered( QAction* ) ), this, SLOT( histoActionTriggered( QAction* ) ) );
337338
QAction* action;
@@ -365,6 +366,13 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
365366
action->setCheckable( true );
366367
action->setChecked( true );
367368
menu->addAction( action );
369+
370+
menu->addSeparator( );
371+
group = new QActionGroup( this );
372+
connect( group, SIGNAL( triggered( QAction* ) ), this, SLOT( histoActionTriggered( QAction* ) ) );
373+
action = new QAction( tr( "Compute Histogram" ), group );
374+
action->setData( QVariant( "Compute Histogram" ) );
375+
menu->addAction( action );
368376
}
369377

370378
// update based on lyr's current state
@@ -1194,16 +1202,85 @@ void QgsRasterLayerProperties::on_tabBar_currentChanged( int theTab )
11941202
}
11951203
}
11961204

1197-
void QgsRasterLayerProperties::refreshHistogram()
1205+
void QgsRasterLayerProperties::on_btnHistoCompute_clicked()
11981206
{
1199-
#if !defined(QWT_VERSION) || QWT_VERSION<0x060000
1200-
mpPlot->clear();
1201-
#endif
1202-
// mHistogramProgress->show();
1207+
// Histogram computation can be called either by clicking the "Compute Histogram" button
1208+
// which is only visible if there is no cached histogram or by calling the
1209+
// "Compute Histogram" action. Due to limitations in the gdal api, it is not possible
1210+
// to re-calculate the histogramif it has already been calculated
1211+
QgsDebugMsg( "Entered" );
1212+
computeHistogram( true );
1213+
refreshHistogram();
1214+
}
1215+
1216+
bool QgsRasterLayerProperties::computeHistogram( bool forceComputeFlag )
1217+
{
1218+
const int BINCOUNT = RASTER_HISTOGRAM_BINS; // 256 - defined in qgsrasterdataprovider.h
1219+
bool myIgnoreOutOfRangeFlag = true;
1220+
bool myThoroughBandScanFlag = false;
1221+
int myBandCountInt = mRasterLayer->bandCount();
1222+
1223+
// if forceComputeFlag = false make sure raster has cached histogram, else return false
1224+
if ( ! forceComputeFlag )
1225+
{
1226+
for ( int myIteratorInt = 1;
1227+
myIteratorInt <= myBandCountInt;
1228+
++myIteratorInt )
1229+
{
1230+
if ( ! mRasterLayer->hasCachedHistogram( myIteratorInt, BINCOUNT ) )
1231+
{
1232+
QgsDebugMsg( QString( "band %1 does not have cached histo" ).arg( myIteratorInt ) );
1233+
return false;
1234+
}
1235+
}
1236+
}
1237+
1238+
// compute histogram
12031239
stackedWidget2->setCurrentIndex( 1 );
12041240
connect( mRasterLayer, SIGNAL( progressUpdate( int ) ), mHistogramProgress, SLOT( setValue( int ) ) );
12051241
QApplication::setOverrideCursor( Qt::WaitCursor );
1242+
1243+
for ( int myIteratorInt = 1;
1244+
myIteratorInt <= myBandCountInt;
1245+
++myIteratorInt )
1246+
{
1247+
mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
1248+
}
1249+
1250+
disconnect( mRasterLayer, SIGNAL( progressUpdate( int ) ), mHistogramProgress, SLOT( setValue( int ) ) );
1251+
// mHistogramProgress->hide();
1252+
stackedWidget2->setCurrentIndex( 0 );
1253+
QApplication::restoreOverrideCursor();
1254+
1255+
return true;
1256+
}
1257+
1258+
void QgsRasterLayerProperties::refreshHistogram()
1259+
{
1260+
// Explanation:
1261+
// We use the gdal histogram creation routine is called for each selected
1262+
// layer. Currently the hist is hardcoded to create 256 bins. Each bin stores
1263+
// the total number of cells that fit into the range defined by that bin.
1264+
//
1265+
// The graph routine below determines the greatest number of pixels in any given
1266+
// bin in all selected layers, and the min. It then draws a scaled line between min
1267+
// and max - scaled to image height. 1 line drawn per selected band
1268+
//
1269+
const int BINCOUNT = RASTER_HISTOGRAM_BINS; // 256 - defined in qgsrasterdataprovider.h
1270+
int myBandCountInt = mRasterLayer->bandCount();
1271+
12061272
QgsDebugMsg( "entered." );
1273+
1274+
if ( ! computeHistogram( false ) )
1275+
{
1276+
QgsDebugMsg( QString( "raster does not have cached histo" ) );
1277+
stackedWidget2->setCurrentIndex( 2 );
1278+
return;
1279+
}
1280+
1281+
#if !defined(QWT_VERSION) || QWT_VERSION<0x060000
1282+
mpPlot->clear();
1283+
#endif
12071284
//ensure all children get removed
12081285
mpPlot->setAutoDelete( true );
12091286
mpPlot->setTitle( QObject::tr( "Raster Histogram" ) );
@@ -1216,20 +1293,6 @@ void QgsRasterLayerProperties::refreshHistogram()
12161293
// add a grid
12171294
QwtPlotGrid * myGrid = new QwtPlotGrid();
12181295
myGrid->attach( mpPlot );
1219-
// Explanation:
1220-
// We use the gdal histogram creation routine is called for each selected
1221-
// layer. Currently the hist is hardcoded
1222-
// to create 256 bins. Each bin stores the total number of cells that
1223-
// fit into the range defined by that bin.
1224-
//
1225-
// The graph routine below determines the greatest number of pixels in any given
1226-
// bin in all selected layers, and the min. It then draws a scaled line between min
1227-
// and max - scaled to image height. 1 line drawn per selected band
1228-
//
1229-
const int BINCOUNT = 256;
1230-
bool myIgnoreOutOfRangeFlag = true;
1231-
bool myThoroughBandScanFlag = false;
1232-
int myBandCountInt = mRasterLayer->bandCount();
12331296

12341297
// make colors list
12351298
mHistoColors.clear();
@@ -1327,7 +1390,7 @@ void QgsRasterLayerProperties::refreshHistogram()
13271390
++myIteratorInt )
13281391
{
13291392
QgsRasterBandStats myRasterBandStats = mRasterLayer->bandStatistics( myIteratorInt );
1330-
mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
1393+
// mRasterLayer->populateHistogram( myIteratorInt, BINCOUNT, myIgnoreOutOfRangeFlag, myThoroughBandScanFlag );
13311394
QwtPlotCurve * mypCurve = new QwtPlotCurve( tr( "Band %1" ).arg( myIteratorInt ) );
13321395
mypCurve->setCurveAttribute( QwtPlotCurve::Fitted );
13331396
mypCurve->setRenderHint( QwtPlotItem::RenderAntialiased );
@@ -1938,6 +2001,10 @@ void QgsRasterLayerProperties::histoActionTriggered( QAction* action )
19382001
updateHistoMarkers();
19392002
}
19402003
}
2004+
else if ( actionName == "Compute Histogram" )
2005+
{
2006+
on_btnHistoCompute_clicked();
2007+
}
19412008
else
19422009
{
19432010
return;

src/app/qgsrasterlayerproperties.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
119119
void histoActionTriggered( QAction* );
120120
/** Draw the min/max markers on the histogram plot. */
121121
void updateHistoMarkers();
122+
/** Button to compute the histogram, appears when no cached histogram is available. */
123+
void on_btnHistoCompute_clicked();
122124

123125
signals:
124126
/** emitted when changes to layer were saved to update legend */
@@ -182,6 +184,9 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
182184
QwtPlotMarker* mHistoMarkerMax;
183185
double mHistoMin;
184186
double mHistoMax;
185-
QVector<QColor> mHistoColors;
187+
QVector<QColor> mHistoColors;
188+
189+
/** \brief Compute the histogram on demand. */
190+
bool computeHistogram( bool forceComputeFlag );
186191
};
187192
#endif

src/core/qgsrasterdataprovider.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class QgsPoint;
3838
class QByteArray;
3939

4040
#define TINY_VALUE std::numeric_limits<double>::epsilon() * 20
41-
41+
#define RASTER_HISTOGRAM_BINS 256
4242

4343
/** \ingroup core
4444
* Base class for raster data providers.
@@ -347,15 +347,25 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider
347347
return QStringList();
348348
}
349349

350+
/** \brief test if the requested histogram is already available */
351+
352+
virtual bool hasCachedHistogram( int theBandNoInt, int theBinCountInt = RASTER_HISTOGRAM_BINS )
353+
{
354+
Q_UNUSED( theBandNoInt ); Q_UNUSED( theBinCountInt ); return false;
355+
}
356+
350357
/** \brief Populate the histogram vector for a given band */
351358

352359
virtual void populateHistogram( int theBandNoInt,
353360
QgsRasterBandStats & theBandStats,
354-
int theBinCountInt = 256,
361+
int theBinCountInt = RASTER_HISTOGRAM_BINS,
355362
bool theIgnoreOutOfRangeFlag = true,
356363
bool theThoroughBandScanFlag = false
357364
)
358-
{ Q_UNUSED( theBandNoInt ); Q_UNUSED( theBandStats ); Q_UNUSED( theBinCountInt ); Q_UNUSED( theIgnoreOutOfRangeFlag ); Q_UNUSED( theThoroughBandScanFlag ); }
365+
{
366+
Q_UNUSED( theBandNoInt ); Q_UNUSED( theBandStats ); Q_UNUSED( theBinCountInt );
367+
Q_UNUSED( theIgnoreOutOfRangeFlag ); Q_UNUSED( theThoroughBandScanFlag );
368+
}
359369

360370
/** \brief Create pyramid overviews */
361371
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,

src/core/raster/qgsrasterlayer.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,15 @@ QPixmap QgsRasterLayer::paletteAsPixmap( int theBandNumber )
14211421
}
14221422
}
14231423

1424+
/*
1425+
* @param theBandNoInt - which band to compute the histogram for
1426+
* @param theBinCountInt - how many 'bins' to categorise the data into
1427+
*/
1428+
bool QgsRasterLayer::hasCachedHistogram( int theBandNo, int theBinCount )
1429+
{
1430+
return mDataProvider->hasCachedHistogram( theBandNo, theBinCount );
1431+
}
1432+
14241433
/*
14251434
* @param theBandNoInt - which band to compute the histogram for
14261435
* @param theBinCountInt - how many 'bins' to categorise the data into

src/core/raster/qgsrasterlayer.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -633,10 +633,15 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
633633
const QString & theResamplingMethod = "NEAREST",
634634
bool theTryInternalFlag = false );
635635

636+
/** \brief test if the requested histogram is already available */
637+
638+
bool hasCachedHistogram( int theBandNoInt,
639+
int theBinCountInt = RASTER_HISTOGRAM_BINS );
640+
636641
/** \brief Populate the histogram vector for a given band */
637642

638643
void populateHistogram( int theBandNoInt,
639-
int theBinCountInt = 256,
644+
int theBinCountInt = RASTER_HISTOGRAM_BINS,
640645
bool theIgnoreOutOfRangeFlag = true,
641646
bool theThoroughBandScanFlag = false );
642647

src/providers/gdal/qgsgdalprovider.cpp

+29-3
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
#include "gdalwarper.h"
5050
#include "ogr_spatialref.h"
5151
#include "cpl_conv.h"
52-
#include "cpl_string.h"
5352

5453

5554
static QString PROVIDER_KEY = "gdal";
@@ -1421,7 +1420,33 @@ QStringList QgsGdalProvider::subLayers( GDALDatasetH dataset )
14211420
return subLayers;
14221421
}
14231422

1424-
void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & theBandStats, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
1423+
bool QgsGdalProvider::hasCachedHistogram( int theBandNo, int theBinCount )
1424+
{
1425+
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
1426+
if ( ! myGdalBand )
1427+
return false;
1428+
1429+
// get default histo
1430+
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 )
1440+
VSIFree( myHistogramArray );
1441+
1442+
// if there was any error/warning assume the histogram is not valid or non-existent
1443+
if ( myError != CE_None )
1444+
return false;
1445+
return true;
1446+
1447+
}
1448+
1449+
void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & theBandStats, int theBinCount, bool theIgnoreOutOfRangeFlag, bool theHistogramEstimatedFlag )
14251450
{
14261451
GDALRasterBandH myGdalBand = GDALGetRasterBand( mGdalDataset, theBandNo );
14271452
//QgsRasterBandStats myRasterBandStats = bandStatistics( theBandNo );
@@ -1457,10 +1482,11 @@ void QgsGdalProvider::populateHistogram( int theBandNo, QgsRasterBandStats & t
14571482
myProg.type = ProgressHistogram;
14581483
myProg.provider = this;
14591484
double myerval = ( theBandStats.maximumValue - theBandStats.minimumValue ) / theBinCount;
1485+
14601486
GDALGetRasterHistogram( myGdalBand, theBandStats.minimumValue - 0.1*myerval,
14611487
theBandStats.maximumValue + 0.1*myerval, theBinCount, myHistogramArray,
14621488
theIgnoreOutOfRangeFlag, theHistogramEstimatedFlag, progressCallback,
1463-
&myProg ); //this is the arg for our custome gdal progress callback
1489+
&myProg ); //this is the arg for our custom gdal progress callback
14641490

14651491
for ( int myBin = 0; myBin < theBinCount; myBin++ )
14661492
{

src/providers/gdal/qgsgdalprovider.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,10 @@ class QgsGdalProvider : public QgsRasterDataProvider
244244
*/
245245
QgsRasterBandStats bandStatistics( int theBandNo );
246246

247+
bool hasCachedHistogram( int theBandNoInt, int theBinCountInt = RASTER_HISTOGRAM_BINS );
247248
void populateHistogram( int theBandNoInt,
248249
QgsRasterBandStats & theBandStats,
249-
int theBinCountInt = 256,
250+
int theBinCountInt = RASTER_HISTOGRAM_BINS,
250251
bool theIgnoreOutOfRangeFlag = true,
251252
bool theThoroughBandScanFlag = false
252253
);

src/ui/qgsrasterlayerpropertiesbase.ui

+60-1
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ p, li { white-space: pre-wrap; }
932932
<item row="0" column="0" colspan="2">
933933
<widget class="QwtPlot" name="mpPlot"/>
934934
</item>
935-
<item row="1" column="0">
935+
<item row="2" column="0">
936936
<widget class="QStackedWidget" name="stackedWidget2">
937937
<property name="sizePolicy">
938938
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@@ -1288,8 +1288,67 @@ p, li { white-space: pre-wrap; }
12881288
</item>
12891289
</layout>
12901290
</widget>
1291+
<widget class="QWidget" name="page">
1292+
<layout class="QHBoxLayout" name="horizontalLayout">
1293+
<property name="spacing">
1294+
<number>0</number>
1295+
</property>
1296+
<property name="margin">
1297+
<number>0</number>
1298+
</property>
1299+
<item>
1300+
<spacer name="horizontalSpacer_20">
1301+
<property name="orientation">
1302+
<enum>Qt::Horizontal</enum>
1303+
</property>
1304+
<property name="sizeHint" stdset="0">
1305+
<size>
1306+
<width>40</width>
1307+
<height>20</height>
1308+
</size>
1309+
</property>
1310+
</spacer>
1311+
</item>
1312+
<item>
1313+
<widget class="QPushButton" name="btnHistoCompute">
1314+
<property name="text">
1315+
<string>Compute Histogram</string>
1316+
</property>
1317+
</widget>
1318+
</item>
1319+
<item>
1320+
<spacer name="horizontalSpacer_19">
1321+
<property name="orientation">
1322+
<enum>Qt::Horizontal</enum>
1323+
</property>
1324+
<property name="sizeHint" stdset="0">
1325+
<size>
1326+
<width>40</width>
1327+
<height>20</height>
1328+
</size>
1329+
</property>
1330+
</spacer>
1331+
</item>
1332+
</layout>
1333+
</widget>
12911334
</widget>
12921335
</item>
1336+
<item row="1" column="0">
1337+
<spacer name="verticalSpacer">
1338+
<property name="orientation">
1339+
<enum>Qt::Vertical</enum>
1340+
</property>
1341+
<property name="sizeType">
1342+
<enum>QSizePolicy::Fixed</enum>
1343+
</property>
1344+
<property name="sizeHint" stdset="0">
1345+
<size>
1346+
<width>20</width>
1347+
<height>10</height>
1348+
</size>
1349+
</property>
1350+
</spacer>
1351+
</item>
12931352
</layout>
12941353
</widget>
12951354
</widget>

0 commit comments

Comments
 (0)