Skip to content
Permalink
Browse files

[FEATURE] Implement raster auto-stretching when updating canvas

This commit implements the improvements described at:
https://lists.osgeo.org/pipermail/qgis-developer/2016-September/044393.html

The QgsRasterMinMaxWidget now offers a seetting to specify that the statistics
should be computed each time the canvas extent changes.

Other changes:
- the content of the QgsRasterMinMaxWidget is now persistant.
- there is no longer any Load button. The global Apply / OK button of the raster
  properties dialog has this effect.
- the default "limits" for single band raster is now MinMax and not CumulativeCut
- the default "limits" can be configured for single band, multi band single byte and
  multi band multi byte
- "Strech using current extent" honours the "limits" instead of forcing min/max.
  • Loading branch information
rouault committed Dec 16, 2016
1 parent cad7a8f commit 532eb58d1f4003a9bcb77ad2119ab8d1255ff7b6
Showing with 1,917 additions and 889 deletions.
  1. +20 −1 doc/api_break.dox
  2. +1 −0 python/core/core.sip
  3. +0 −11 python/core/raster/qgsraster.sip
  4. +1 −6 python/core/raster/qgsrasterlayer.sip
  5. +127 −0 python/core/raster/qgsrasterminmaxorigin.sip
  6. +6 −20 python/core/raster/qgsrasterrenderer.sip
  7. +0 −2 python/core/raster/qgssinglebandpseudocolorrenderer.sip
  8. +2 −1 python/gui/raster/qgsmultibandcolorrendererwidget.sip
  9. +28 −3 python/gui/raster/qgsrasterminmaxwidget.sip
  10. +2 −8 python/gui/raster/qgsrasterrendererwidget.sip
  11. +2 −1 python/gui/raster/qgssinglebandgrayrendererwidget.sip
  12. +3 −1 python/gui/raster/qgssinglebandpseudocolorrendererwidget.sip
  13. +6 −8 src/app/qgisapp.cpp
  14. +2 −1 src/app/qgisapp.h
  15. +33 −0 src/app/qgslayerstylingwidget.cpp
  16. +55 −23 src/app/qgsoptions.cpp
  17. +2 −0 src/app/qgsoptions.h
  18. +2 −0 src/app/qgsrasterlayerproperties.cpp
  19. +2 −0 src/core/CMakeLists.txt
  20. +7 −6 src/core/raster/qgscontrastenhancement.h
  21. +0 −33 src/core/raster/qgsraster.cpp
  22. +0 −12 src/core/raster/qgsraster.h
  23. +253 −56 src/core/raster/qgsrasterlayer.cpp
  24. +56 −6 src/core/raster/qgsrasterlayer.h
  25. +3 −0 src/core/raster/qgsrasterlayerrenderer.cpp
  26. +205 −0 src/core/raster/qgsrasterminmaxorigin.cpp
  27. +159 −0 src/core/raster/qgsrasterminmaxorigin.h
  28. +13 −147 src/core/raster/qgsrasterrenderer.cpp
  29. +10 −20 src/core/raster/qgsrasterrenderer.h
  30. +44 −3 src/core/raster/qgssinglebandpseudocolorrenderer.cpp
  31. +0 −4 src/core/raster/qgssinglebandpseudocolorrenderer.h
  32. +68 −11 src/gui/raster/qgsmultibandcolorrendererwidget.cpp
  33. +13 −1 src/gui/raster/qgsmultibandcolorrendererwidget.h
  34. +136 −49 src/gui/raster/qgsrasterminmaxwidget.cpp
  35. +47 −4 src/gui/raster/qgsrasterminmaxwidget.h
  36. +7 −8 src/gui/raster/qgsrasterrendererwidget.h
  37. +45 −2 src/gui/raster/qgsrendererrasterpropertieswidget.cpp
  38. +3 −0 src/gui/raster/qgsrendererrasterpropertieswidget.h
  39. +58 −11 src/gui/raster/qgssinglebandgrayrendererwidget.cpp
  40. +11 −3 src/gui/raster/qgssinglebandgrayrendererwidget.h
  41. +46 −17 src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp
  42. +10 −6 src/gui/raster/qgssinglebandpseudocolorrendererwidget.h
  43. +1 −1 src/plugins/georeferencer/qgsgeorefplugingui.cpp
  44. +92 −142 src/ui/qgsoptionsbase.ui
  45. +179 −170 src/ui/qgsrasterminmaxwidgetbase.ui
  46. +66 −87 src/ui/qgssinglebandpseudocolorrendererwidgetbase.ui
  47. +31 −3 tests/src/core/testqgsrasterlayer.cpp
  48. +60 −1 tests/src/python/test_qgsrasterlayer.py
@@ -1311,6 +1311,14 @@ QgsProject {#qgis_api_break_3_0_QgsProject}
- clearProperties() was removed. Use clear() instead.


QgsRaster {#qgis_api_break_3_0_QgsRaster}
---------

- QgsRaster::ContrastEnhancementLimits has been removed, use QgsRasterMinMaxOrigin::Limits
- QgsRaster::contrastEnhancementLimitsAsString() has been removed, use QgsRasterMinMaxOrigin::limitsString()
- QgsRaster::contrastEnhancementLimitsFromString() has been removed, use QgsRasterMinMaxOrigin::limitsFromString()


QgsRasterCalcNode {#qgis_api_break_3_0_QgsRasterCalcNode}
-----------------

@@ -1341,13 +1349,18 @@ QgsRasterLayer {#qgis_api_break_3_0_QgsRasterLayer}
- setDrawingStyle() was removed. Use setRendererForDrawingStyle() or setRenderer() instead.
- previewAsPixmap() was removed. Use previewAsImage() instead.
- updateProgress() had no effect and was removed.

- CUMULATIVE_CUT_LOWER and CUMULATIVE_CUT_UPPER have been moved to QgsRasterMinMaxOrigin
- the second parameter of setContrastEnhancement() has changed type. It is now QgsRasterMinMaxOrigin::Limits

QgsRasterProjector {#qgis_api_break_3_0_QgsRasterProjector}
------------------

- extentSize() now takes a QgsCoordinateTransform reference, not a pointer. An invalid QgsCoordinateTransform should be used instead of a null pointer if no transformation is required.

QgsRasterRenderer
-----------------

- MinMaxOrigin enum, minMaxOriginName(), minMaxOriginLabel(), minMaxOriginFromName() removed. Use minMaxOrigin() instead

QgsRelation {#qgis_api_break_3_0_QgsRelation}
-----------
@@ -1428,6 +1441,12 @@ QgsSimpleMarkerSymbolLayerWidget {#qgis_api_break_3_0_QgsSimpleMarkerSymb
- setName() was removed.


QgsSingleBandPseudoColorRenderer {#qgis_api_break_3_0_QgsSingleBandPseudoColorRenderer}
--------------------------------

- classificationMinMaxOrigin() and setClassificationMinMaxOrigin() removed. Use minMaxOrigin() and setMinMaxOrigin()


QgsSingleSymbolRendererWidget {#qgis_api_break_3_0_QgsSingleSymbolRendererWidget}
-----------------------------

@@ -274,6 +274,7 @@
%Include raster/qgsrasterinterface.sip
%Include raster/qgsrasteriterator.sip
%Include raster/qgsrasterlayer.sip
%Include raster/qgsrasterminmaxorigin.sip
%Include raster/qgsrasternuller.sip
%Include raster/qgsrasterpipe.sip
%Include raster/qgsrasterprojector.sip
@@ -62,14 +62,6 @@ class QgsRaster
PyramidsErdas,
};

/** \brief Contrast enhancement limits */
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};

/** \brief This enumerator describes the different kinds of drawing we can do */
enum DrawingStyle
@@ -87,9 +79,6 @@ class QgsRaster
SingleBandColorDataStyle // ARGB values rendered directly
};

static QString contrastEnhancementLimitsAsString( QgsRaster::ContrastEnhancementLimits theLimits );
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( const QString& theLimits );

/** Get value representable by given data type.
* Supported are numerical types Byte, UInt16, Int16, UInt32, Int32, Float32, Float64.
* @param value
@@ -10,11 +10,6 @@ class QgsRasterLayer : QgsMapLayer
%End

public:
/** \brief Default cumulative cut lower limit */
static const double CUMULATIVE_CUT_LOWER;

/** \brief Default cumulative cut upper limit */
static const double CUMULATIVE_CUT_UPPER;

/** \brief Default sample size (number of pixels) for estimated statistics/histogram calculation */
static const double SAMPLE_SIZE;
@@ -165,7 +160,7 @@ class QgsRasterLayer : QgsMapLayer


void setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax,
QgsRasterMinMaxOrigin::Limits theLimits = QgsRasterMinMaxOrigin::MinMax,
const QgsRectangle& theExtent = QgsRectangle(),
int theSampleSize = QgsRasterLayer::SAMPLE_SIZE,
bool theGenerateLookupTableFlag = true );
@@ -0,0 +1,127 @@
/** \class QgsRasterMinMaxOrigin
* This class describes the origin of min/max values. It does not store by
* itself the min/max values.
*/

class QgsRasterMinMaxOrigin
{
%TypeHeaderCode
#include <qgsrasterminmaxorigin.h>
%End
public:
//! \brief Default cumulative cut lower limit
static const double CUMULATIVE_CUT_LOWER;

//! \brief Default cumulative cut upper limit
static const double CUMULATIVE_CUT_UPPER;

//! \brief Default standard deviation factor
static const double DEFAULT_STDDEV_FACTOR;

//! \brief This enumerator describes the limits used to compute min/max values
enum Limits
{
//! User defined.
None /PyName=None_/,
//! Real min-max values
MinMax,
//! Range is [ mean - stdDevFactor() * stddev, mean + stdDevFactor() * stddev ]
StdDev,
//! Range is [ min + cumulativeCutLower() * (max - min), min + cumulativeCutUpper() * (max - min) ]
CumulativeCut
};

//! \brief This enumerator describes the extent used to compute min/max values
enum Extent
{
//! Whole raster is used to compute statistics.
WholeRaster,
//! Current extent of the canvas (at the time of computation) is used to compute statistics.
CurrentCanvas,
//! Constantly updated extent of the canvas is used to compute statistics.
UpdatedCanvas
};

//! \brief This enumerator describes the accuracy used to compute statistics.
enum StatAccuracy
{
//! Exact statistics.
Exact,
//! Approximated statistics.
Estimated
};

//! \brief Default constructor.
QgsRasterMinMaxOrigin();

//! \brief Equality operator.
bool operator ==( const QgsRasterMinMaxOrigin& other ) const;

//////// Getter methods /////////////////////

//! \brief Return limits.
QgsRasterMinMaxOrigin::Limits limits() const;

//! \brief Return extent.
QgsRasterMinMaxOrigin::Extent extent() const;

//! \brief Return statistic accuracy.
QgsRasterMinMaxOrigin::StatAccuracy statAccuracy() const;

//! \brief Return lower bound of cumulative cut method (between 0 and 1).
double cumulativeCutLower() const;

//! \brief Return upper bound of cumulative cut method (between 0 and 1).
double cumulativeCutUpper() const;

//! \brief Return factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
double stdDevFactor() const;

//////// Setter methods /////////////////////

//! \brief Set limits.
void setLimits(QgsRasterMinMaxOrigin::Limits theLimits);

//! \brief Set extent.
void setExtent(QgsRasterMinMaxOrigin::Extent theExtent);

//! \brief Set statistics accuracy.
void setStatAccuracy(QgsRasterMinMaxOrigin::StatAccuracy theAccuracy);

//! \brief Set lower bound of cumulative cut method (between 0 and 1).
void setCumulativeCutLower(double val);

//! \brief Set upper bound of cumulative cut method (between 0 and 1).
void setCumulativeCutUpper(double val);

//! \brief Set factor f so that the min/max range is [ mean - f * stddev , mean + f * stddev ]
void setStdDevFactor(double val);

//////// XML serialization /////////////////////

//! \brief Serialize object.
void writeXml( QDomDocument& doc, QDomElement& parentElem ) const;

//! \brief Deserialize object.
void readXml( const QDomElement& elem );

//////// Static methods /////////////////////

//! \brief Return a string to serialize Limits
static QString limitsString( QgsRasterMinMaxOrigin::Limits theLimits );

//! \brief Deserialize Limits
static QgsRasterMinMaxOrigin::Limits limitsFromString( const QString& theLimits );

//! \brief Return a string to serialize Extent
static QString extentString( QgsRasterMinMaxOrigin::Extent theExtent );

//! \brief Deserialize Extent
static QgsRasterMinMaxOrigin::Extent extentFromString( const QString& theExtent );

//! \brief Return a string to serialize StatAccuracy
static QString statAccuracyString( QgsRasterMinMaxOrigin::StatAccuracy theAccuracy );

//! \brief Deserialize StatAccuracy
static QgsRasterMinMaxOrigin::StatAccuracy statAccuracyFromString( const QString& theAccuracy );
};
@@ -6,22 +6,6 @@ class QgsRasterRenderer : QgsRasterInterface
%End

public:
// Origin of min / max values
enum MinMaxOrigin
{
MinMaxUnknown,
MinMaxUser, // entered by user
// method
MinMaxMinMax,
MinMaxCumulativeCut,
MinMaxStdDev,
// Extent
MinMaxFullExtent,
MinMaxSubExtent,
// Precision
MinMaxEstimated,
MinMaxExact
};

static const QRgb NODATA_COLOR;

@@ -60,14 +44,16 @@ class QgsRasterRenderer : QgsRasterInterface
/** Copies common properties like opacity / transparency data from other renderer.
* Useful when cloning renderers.
* @note added in 2.16 */
void copyCommonProperties( const QgsRasterRenderer* other );
void copyCommonProperties( const QgsRasterRenderer* other, bool copyMinMaxOrigin = true );

/** Returns a list of band numbers used by the renderer*/
virtual QList<int> usesBands() const;

static QString minMaxOriginName( int theOrigin );
static QString minMaxOriginLabel( int theOrigin );
static int minMaxOriginFromName( const QString& theName );
//! Returns const reference to origin of min/max values
const QgsRasterMinMaxOrigin& minMaxOrigin() const;

//! Sets origin of min/max values
void setMinMaxOrigin( const QgsRasterMinMaxOrigin& theOrigin );

protected:

@@ -40,8 +40,6 @@ class QgsSingleBandPseudoColorRenderer: QgsRasterRenderer
double classificationMax() const;
void setClassificationMin( double min );
void setClassificationMax( double max );
int classificationMinMaxOrigin() const;
void setClassificationMinMaxOrigin( int origin );

private:

@@ -19,7 +19,8 @@ class QgsMultiBandColorRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 );
void doComputations();

public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin );
void loadMinMax( int theBandNo, double theMin, double theMax );
};
@@ -37,9 +37,34 @@ class QgsRasterMinMaxWidget: QWidget
/** Return the selected sample size. */
int sampleSize();

// Load programmaticaly with current values
void load();
//! \brief Set the "source" of min/max values.
void setFromMinMaxOrigin( const QgsRasterMinMaxOrigin& );

//! \brief Return a QgsRasterMinMaxOrigin object with the widget values.
QgsRasterMinMaxOrigin minMaxOrigin();

//! Hide updated extent radio button
void hideUpdatedExtent();

//! Load programmaticaly with current values
void doComputations();

//! Uncheck cumulative cut, min/max, std-dev radio buttons
void userHasSetManualMinMaxValues();

//! Return if the widget is collaped.
bool isCollapsed() const;

//! Set collapsed state of widget
void setCollapsed(bool b);

signals:
void load( int theBandNo, double theMin, double theMax, int origin );
/**
* Emitted when something on the widget has changed.
* All widgets will fire this event to notify of an internal change.
*/
void widgetChanged();

//! signal emitted when new min/max values are computed from statistics.
void load( int theBandNo, double theMin, double theMax );
};
@@ -7,14 +7,6 @@ class QgsRasterRendererWidget: QWidget
QgsRasterRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent );
virtual ~QgsRasterRendererWidget();

enum LoadMinMaxAlgo
{
Estimate,
Actual,
CurrentExtent,
CumulativeCut // 2 - 98% cumulative cut
};

virtual QgsRasterRenderer* renderer() = 0 /Factory/;

void setRasterLayer( QgsRasterLayer* layer );
@@ -42,6 +34,8 @@ class QgsRasterRendererWidget: QWidget
virtual QString stdDev();
virtual void setStdDev( const QString& value );
virtual int selectedBand( int index = 0 );
virtual void doComputations();
virtual QgsRasterMinMaxWidget* minMaxWidget();

signals:
/**
@@ -19,7 +19,8 @@ class QgsSingleBandGrayRendererWidget: QgsRasterRendererWidget
void setMin( const QString& value, int index = 0 );
void setMax( const QString& value, int index = 0 );
int selectedBand( int index = 0 );
void doComputations();

public slots:
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin );
void loadMinMax( int theBandNo, double theMin, double theMax );
};
@@ -21,12 +21,14 @@ class QgsSingleBandPseudoColorRendererWidget : QgsRasterRendererWidget

void setFromRenderer( const QgsRasterRenderer* r );

void doComputations();

public slots:

/** Executes the single band pseudo raster classficiation
*/
void classify();
void loadMinMax( int theBandNo, double theMin, double theMax, int theOrigin );
void loadMinMax( int theBandNo, double theMin, double theMax );

};

1 comment on commit 532eb58

@nirvn

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn commented on 532eb58 Dec 23, 2016

@rouault following this set of commits, QGIS fails to renderer a multi band raster using single band gray renderer.

Steps to reproduce:

  • add a 3-band raster (tested with a sentinel 2 image here)
  • open the style dock
  • switch renderer from multiband color to singleband grayscale
  • notice the layer is renderer entirely black
Please sign in to comment.
You can’t perform that action at this time.