Skip to content

Commit 1145bd2

Browse files
committedMar 14, 2013
[FEATURE] brightness and contrast filter for rasters
1 parent 1294190 commit 1145bd2

File tree

10 files changed

+417
-8
lines changed

10 files changed

+417
-8
lines changed
 

‎src/app/qgisapp.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
#include "qgsrasterlayer.h"
170170
#include "qgsrasterlayerproperties.h"
171171
#include "qgsrasternuller.h"
172+
#include "qgsbrightnesscontrastfilter.h"
172173
#include "qgsrasterrenderer.h"
173174
#include "qgsrasterlayersaveasdialog.h"
174175
#include "qgsrectangle.h"
@@ -1050,6 +1051,10 @@ void QgisApp::createActions()
10501051
connect( mActionFullHistogramStretch, SIGNAL( triggered() ), this, SLOT( fullHistogramStretch() ) );
10511052
connect( mActionLocalCumulativeCutStretch, SIGNAL( triggered() ), this, SLOT( localCumulativeCutStretch() ) );
10521053
connect( mActionFullCumulativeCutStretch, SIGNAL( triggered() ), this, SLOT( fullCumulativeCutStretch() ) );
1054+
connect( mActionIncreaseBrightness, SIGNAL( triggered() ), this, SLOT( increaseBrightness() ) );
1055+
connect( mActionDecreaseBrightness, SIGNAL( triggered() ), this, SLOT( decreaseBrightness() ) );
1056+
connect( mActionIncreaseContrast, SIGNAL( triggered() ), this, SLOT( increaseContrast() ) );
1057+
connect( mActionDecreaseContrast, SIGNAL( triggered() ), this, SLOT( decreaseContrast() ) );
10531058

10541059
// Vector Menu Items
10551060
connect( mActionOSMDownload, SIGNAL( triggered() ), this, SLOT( osmDownloadDialog() ) );
@@ -1675,6 +1680,10 @@ void QgisApp::setTheme( QString theThemeName )
16751680
mActionHelpContents->setIcon( QgsApplication::getThemeIcon( "/mActionHelpContents.png" ) );
16761681
mActionLocalHistogramStretch->setIcon( QgsApplication::getThemeIcon( "/mActionLocalHistogramStretch.png" ) );
16771682
mActionFullHistogramStretch->setIcon( QgsApplication::getThemeIcon( "/mActionFullHistogramStretch.png" ) );
1683+
//~ mActionIncreaseBrightness->setIcon( QgsApplication::getThemeIcon( "/mActionIncreaseBrightness.png" ) );
1684+
//~ mActionDecreaseBrightness->setIcon( QgsApplication::getThemeIcon( "/mActionDecreaseBrightness.png" ) );
1685+
//~ mActionIncreaseContrast->setIcon( QgsApplication::getThemeIcon( "/mActionIncreaseContrast.png" ) );
1686+
//~ mActionDecreaseContrast->setIcon( QgsApplication::getThemeIcon( "/mActionDecreaseContrast.png" ) );
16781687
mActionZoomActualSize->setIcon( QgsApplication::getThemeIcon( "/mActionZoomNative.png" ) );
16791688
mActionQgisHomePage->setIcon( QgsApplication::getThemeIcon( "/mActionQgisHomePage.png" ) );
16801689
mActionAbout->setIcon( QgsApplication::getThemeIcon( "/mActionHelpAbout.png" ) );
@@ -6454,6 +6463,63 @@ void QgisApp::histogramStretch( bool visibleAreaOnly, QgsRasterLayer::ContrastEn
64546463
mMapCanvas->refresh();
64556464
}
64566465

6466+
void QgisApp::increaseBrightness()
6467+
{
6468+
adjustBrightnessContrast( 1 );
6469+
}
6470+
6471+
void QgisApp::decreaseBrightness()
6472+
{
6473+
adjustBrightnessContrast( -1 );
6474+
}
6475+
6476+
void QgisApp::increaseContrast()
6477+
{
6478+
adjustBrightnessContrast( 1, false );
6479+
}
6480+
6481+
void QgisApp::decreaseContrast()
6482+
{
6483+
adjustBrightnessContrast( -1, false );
6484+
}
6485+
6486+
6487+
void QgisApp::adjustBrightnessContrast( int delta, bool updateBrightness )
6488+
{
6489+
QgsMapLayer * myLayer = mMapLegend->currentLayer();
6490+
6491+
if ( !myLayer )
6492+
{
6493+
QMessageBox::information( this,
Code has comments. Press enter to view.
6494+
tr( "No Layer Selected" ),
6495+
tr( "To change brightness or contrast, you need to have a raster layer selected." ) );
6496+
return;
6497+
}
6498+
6499+
QgsRasterLayer* myRasterLayer = qobject_cast<QgsRasterLayer *>( myLayer );
6500+
if ( !myRasterLayer )
6501+
{
6502+
QMessageBox::information( this,
6503+
tr( "No Raster Layer Selected" ),
6504+
tr( "To change brightness or contrast, you need to have a raster layer selected." ) );
6505+
return;
6506+
}
6507+
6508+
QgsBrightnessContrastFilter* brightnessFilter = myRasterLayer->brightnessFilter();
6509+
6510+
if ( updateBrightness )
6511+
{
6512+
brightnessFilter->setBrightness( brightnessFilter->brightness() + delta );
6513+
}
6514+
else
6515+
{
6516+
brightnessFilter->setContrast( brightnessFilter->contrast() + delta );
6517+
}
6518+
6519+
myRasterLayer->setCacheImage( NULL );
6520+
mMapCanvas->refresh();
6521+
}
6522+
64576523
void QgisApp::helpContents()
64586524
{
64596525
openURL( "index.html" );

‎src/app/qgisapp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,22 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
670670
void localCumulativeCutStretch();
671671
/** Perform a full extent cumulative cut stretch */
672672
void fullCumulativeCutStretch();
673+
/**Increase raster brightness
674+
* Valid for non wms raster layers only.
675+
* @note Added in QGIS 2.0 */
676+
void increaseBrightness();
677+
/**Decrease raster brightness
678+
* Valid for non wms raster layers only.
679+
* @note Added in QGIS 2.0 */
680+
void decreaseBrightness();
681+
/**Increase raster contrast
682+
* Valid for non wms raster layers only.
683+
* @note Added in QGIS 2.0 */
684+
void increaseContrast();
685+
/**Decrease raster contrast
686+
* Valid for non wms raster layers only.
687+
* @note Added in QGIS 2.0 */
688+
void decreaseContrast();
673689
//! plugin manager
674690
void showPluginManager();
675691
//! load python support if possible
@@ -1143,6 +1159,10 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
11431159
/**Do histogram stretch for singleband gray / multiband color rasters*/
11441160
void histogramStretch( bool visibleAreaOnly = false, QgsRasterLayer::ContrastEnhancementLimits theLimits = QgsRasterLayer::ContrastEnhancementMinMax );
11451161

1162+
/**Apply raster brightness
1163+
* @note Added in QGIS 2.0 */
1164+
void adjustBrightnessContrast( int delta, bool updateBrightness = true );
1165+
11461166
QgisAppStyleSheet* mStyleSheetBuilder;
11471167

11481168
// actions for menus and toolbars -----------------

‎src/core/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ SET(QGIS_CORE_SRCS
4040
symbology-ng/qgspointdisplacementrenderer.cpp
4141
symbology-ng/qgsvectorfieldsymbollayer.cpp
4242
symbology-ng/qgscolorbrewerpalette.cpp
43-
43+
4444
diagram/qgsdiagram.cpp
4545
diagram/qgspiediagram.cpp
4646
diagram/qgstextdiagram.cpp
4747
diagram/qgshistogramdiagram.cpp
48-
48+
4949
qgis.cpp
5050
qgsapplication.cpp
5151
qgsattributeaction.cpp
@@ -204,6 +204,7 @@ SET(QGIS_CORE_SRCS
204204
raster/qgssinglebandcolordatarenderer.cpp
205205
raster/qgssinglebandgrayrenderer.cpp
206206
raster/qgssinglebandpseudocolorrenderer.cpp
207+
raster/qgsbrightnesscontrastfilter.cpp
207208

208209
renderer/qgscontinuouscolorrenderer.cpp
209210
renderer/qgsgraduatedsymbolrenderer.cpp
@@ -446,7 +447,7 @@ SET(QGIS_CORE_HDRS
446447
diagram/qgstextdiagram.h
447448
diagram/qgshistogramdiagram.h
448449

449-
450+
450451
composer/qgslegendmodel.h
451452
composer/qgscomposerlegenditem.h
452453

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/***************************************************************************
2+
qgsbrightnesscontrastfilter.cpp
3+
---------------------
4+
begin : February 2013
5+
copyright : (C) 2013 by Alexander Bruy
6+
email : alexander dot bruy at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsrasterdataprovider.h"
19+
#include "qgsbrightnesscontrastfilter.h"
20+
21+
#include <QDomDocument>
22+
#include <QDomElement>
23+
24+
25+
QgsBrightnessContrastFilter::QgsBrightnessContrastFilter( QgsRasterInterface* input )
26+
: QgsRasterInterface( input ),
27+
mBrightness( 0 ),
28+
mContrast( 0 )
29+
{
30+
}
31+
32+
QgsBrightnessContrastFilter::~QgsBrightnessContrastFilter()
33+
{
34+
}
35+
36+
QgsRasterInterface * QgsBrightnessContrastFilter::clone() const
37+
{
38+
QgsDebugMsg( "Entered" );
39+
QgsBrightnessContrastFilter * filter = new QgsBrightnessContrastFilter( 0 );
40+
filter->setBrightness( mBrightness );
41+
return filter;
42+
}
43+
44+
int QgsBrightnessContrastFilter::bandCount() const
45+
{
46+
if ( mOn )
47+
{
48+
return 1;
49+
}
50+
51+
if ( mInput )
52+
{
53+
return mInput->bandCount();
54+
}
55+
56+
return 0;
57+
}
58+
59+
QGis::DataType QgsBrightnessContrastFilter::dataType( int bandNo ) const
60+
{
61+
if ( mOn )
62+
{
63+
return QGis::ARGB32_Premultiplied;
64+
}
65+
66+
if ( mInput )
67+
{
68+
return mInput->dataType( bandNo );
69+
}
70+
71+
return QGis::UnknownDataType;
72+
}
73+
74+
bool QgsBrightnessContrastFilter::setInput( QgsRasterInterface* input )
75+
{
76+
QgsDebugMsg( "Entered" );
77+
78+
// Brightness filter can only work with single band ARGB32_Premultiplied
79+
if ( !input )
80+
{
81+
QgsDebugMsg( "No input" );
82+
return false;
83+
}
84+
85+
if ( !mOn )
86+
{
87+
// In off mode we can connect to anything
88+
QgsDebugMsg( "OK" );
89+
mInput = input;
90+
return true;
91+
}
92+
93+
if ( input->bandCount() < 1 )
94+
{
95+
QgsDebugMsg( "No input band" );
96+
return false;
97+
}
98+
99+
if ( input->dataType( 1 ) != QGis::ARGB32_Premultiplied &&
100+
input->dataType( 1 ) != QGis::ARGB32 )
101+
{
102+
QgsDebugMsg( "Unknown input data type" );
103+
return false;
104+
}
105+
106+
mInput = input;
107+
QgsDebugMsg( "OK" );
108+
return true;
109+
}
110+
111+
QgsRasterBlock * QgsBrightnessContrastFilter::block( int bandNo, QgsRectangle const & extent, int width, int height )
112+
{
113+
Q_UNUSED( bandNo );
114+
QgsDebugMsg( "Entered" );
115+
116+
QgsRasterBlock *outputBlock = new QgsRasterBlock();
117+
if ( !mInput )
118+
{
119+
return outputBlock;
120+
}
121+
122+
// At this moment we know that we read rendered image
123+
int bandNumber = 1;
124+
QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, width, height );
125+
if ( !inputBlock || inputBlock->isEmpty() )
126+
{
127+
QgsDebugMsg( "No raster data!" );
128+
delete inputBlock;
129+
return outputBlock;
130+
}
131+
132+
if ( mBrightness == 0 && mContrast == 0 )
133+
{
134+
QgsDebugMsg( "No brightness changes." );
135+
delete outputBlock;
136+
return inputBlock;
137+
}
138+
139+
if ( !outputBlock->reset( QGis::ARGB32_Premultiplied, width, height ) )
140+
{
141+
delete inputBlock;
142+
return outputBlock;
143+
}
144+
145+
// adjust image
146+
QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
147+
QRgb myColor;
148+
int r, g, b;
149+
150+
double f = ( 259 * ( mContrast + 255 ) ) / ( 255 * ( 259 - mContrast ) );
151+
152+
for ( size_t i = 0; i < ( size_t )width*height; i++ )
153+
{
154+
if ( inputBlock->color( i ) == myNoDataColor )
155+
{
156+
outputBlock->setColor( i, myNoDataColor );
157+
continue;
158+
}
159+
160+
myColor = inputBlock->color( i );
161+
r = qBound( 0, qRound( f * ( qBound( 0, qRed( myColor ) + mBrightness, 255 ) - 128 ) + 128 ), 255 );
162+
g = qBound( 0, qRound( f * ( qBound( 0, qGreen( myColor ) + mBrightness, 255 ) - 128 ) + 128 ), 255 );
163+
b = qBound( 0, qRound( f * ( qBound( 0, qBlue( myColor ) + mBrightness, 255 ) - 128 ) + 128 ), 255 );
164+
165+
outputBlock->setColor( i, qRgb( r, g, b ) );
166+
}
167+
168+
delete inputBlock;
169+
return outputBlock;
170+
}
171+
172+
void QgsBrightnessContrastFilter::writeXML( QDomDocument& doc, QDomElement& parentElem )
173+
{
174+
if ( parentElem.isNull() )
175+
{
176+
return;
177+
}
178+
179+
QDomElement filterElem = doc.createElement( "brightnesscontrast" );
180+
181+
filterElem.setAttribute( "brightness", QString::number( mBrightness ) );
182+
filterElem.setAttribute( "contrast", QString::number( mContrast ) );
183+
parentElem.appendChild( filterElem );
184+
}
185+
186+
void QgsBrightnessContrastFilter::readXML( const QDomElement& filterElem )
187+
{
188+
if ( filterElem.isNull() )
189+
{
190+
return;
191+
}
192+
193+
mBrightness = filterElem.attribute( "brightness", "0" ).toInt();
194+
mContrast = filterElem.attribute( "contrast", "0" ).toInt();
195+
}

3 commit comments

Comments
 (3)

timlinux commented on Mar 15, 2013

@timlinux
Member

Hi Alex

I was just playing with this a little - dont you think it would be more useful to have a combo and/or slider widget so that these values can be set precisely? At the moment it requires a lot of clicking - often without any perceptible change in my test image.

Regards

Tim

alexbruy commented on Mar 15, 2013

@alexbruy
ContributorAuthor

Hi Tim

I already thinking about adding sliders to raster properties dialog to allow more precise way to set this parameters.

timlinux commented on Mar 15, 2013

@timlinux
Member

Hi

I already thinking about adding sliders to raster properties dialog to allow more precise way to set this parameters.

Great. Note I think they should be accompanied by spin boxes to allow precise value entry too.

Please sign in to comment.