Skip to content

Commit 3d02fbe

Browse files
committedMar 26, 2013
[FEATURE] Option to convert a raster to grayscale with choice of desaturation mode (lightness, luminosity, average) (fix #5837)
1 parent 030960e commit 3d02fbe

File tree

5 files changed

+136
-18
lines changed

5 files changed

+136
-18
lines changed
 

‎src/app/qgsrasterlayerproperties.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
8787
connect( sliderSaturation, SIGNAL( valueChanged( int ) ), spinBoxSaturation, SLOT( setValue( int ) ) );
8888
connect( spinBoxSaturation, SIGNAL( valueChanged( int ) ), sliderSaturation, SLOT( setValue( int ) ) );
8989

90+
// enable or disable saturation slider and spin box depending on grayscale combo choice
91+
connect( comboGrayscale, SIGNAL( currentIndexChanged( int ) ), this, SLOT( toggleSaturationControls( int ) ) );
92+
9093
// enable or disable Build Pyramids button depending on selection in pyramid list
9194
connect( lbxPyramidResolutions, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleBuildPyramidsButton() ) );
9295

@@ -255,6 +258,10 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
255258
if ( hueSaturationFilter )
256259
{
257260
sliderSaturation->setValue( hueSaturationFilter->saturation() );
261+
comboGrayscale->setCurrentIndex(( int ) hueSaturationFilter->grayscaleMode() );
262+
263+
// Set initial state of saturation controls based on grayscale mode choice
264+
toggleSaturationControls( hueSaturationFilter->grayscaleMode() == QgsHueSaturationFilter::GrayscaleOff );
258265
}
259266

260267
//blend mode
@@ -820,6 +827,7 @@ void QgsRasterLayerProperties::apply()
820827
if ( hueSaturationFilter )
821828
{
822829
hueSaturationFilter->setSaturation( sliderSaturation->value() );
830+
hueSaturationFilter->setGrayscaleMode(( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
823831
}
824832

825833

@@ -1456,6 +1464,23 @@ void QgsRasterLayerProperties::sliderTransparency_valueChanged( int theValue )
14561464
lblTransparencyPercent->setText( QString::number( myInt ) + "%" );
14571465
}//sliderTransparency_valueChanged
14581466

1467+
void QgsRasterLayerProperties::toggleSaturationControls( int theValue )
1468+
{
1469+
// Enable or disable saturation controls based on choice of grayscale mode
1470+
if ( theValue == 0 )
1471+
{
1472+
// Grayscale set to off, enable controls
1473+
sliderSaturation->setEnabled( true );
1474+
spinBoxSaturation->setEnabled( true );
1475+
}
1476+
else
1477+
{
1478+
// A grayscale mode is selected, disable saturation controls
1479+
sliderSaturation->setEnabled( false );
1480+
spinBoxSaturation->setEnabled( false );
1481+
}
1482+
}
1483+
14591484
QLinearGradient QgsRasterLayerProperties::redGradient()
14601485
{
14611486
//define a gradient

‎src/app/qgsrasterlayerproperties.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
103103
/**Enable or disable Build pyramids button depending on selection in pyramids list*/
104104
void toggleBuildPyramidsButton();
105105

106+
/**Enable or disable saturation controls depending on choice of grayscale mode */
107+
void toggleSaturationControls( int theValue );
108+
106109
/** Update items in pipe list */
107110
void pipeItemClicked( QTreeWidgetItem * item, int column );
108111

‎src/core/raster/qgshuesaturationfilter.cpp

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424

2525
QgsHueSaturationFilter::QgsHueSaturationFilter( QgsRasterInterface* input )
2626
: QgsRasterInterface( input ),
27-
mSaturation( 0 )
27+
mSaturation( 0 ),
28+
mGrayscaleMode( QgsHueSaturationFilter::GrayscaleOff )
2829
{
2930
}
3031

@@ -128,9 +129,9 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
128129
return outputBlock;
129130
}
130131

131-
if ( mSaturation == 0 )
132+
if ( mSaturation == 0 && mGrayscaleMode == GrayscaleOff )
132133
{
133-
QgsDebugMsg( "No saturation change." );
134+
QgsDebugMsg( "No hue/saturation change." );
134135
delete outputBlock;
135136
return inputBlock;
136137
}
@@ -144,7 +145,8 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
144145
// adjust image
145146
QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
146147
QColor myColor;
147-
int h, s, v;
148+
int h, s, l;
149+
int r, g, b;
148150

149151
// Scale saturation value to [0-2], where 0 = desaturated
150152
double saturationScale = (( double ) mSaturation / 100 ) + 1;
@@ -157,24 +159,56 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
157159
continue;
158160
}
159161

160-
// Get current color in hsv
162+
// Get hsv and rgb for color
161163
myColor = QColor( inputBlock->color( i ) );
162-
myColor.getHsv( &h, &s, &v );
164+
myColor.getHsl( &h, &s, &l );
165+
myColor.getRgb( &r, &g, &b );
163166

164-
if ( saturationScale < 1 )
167+
switch ( mGrayscaleMode )
165168
{
166-
// Lowering the saturation. Use a simple linear relationship
167-
s = qMin(( int )( s * saturationScale ), 255 );
168-
}
169-
else
170-
{
171-
// Raising the saturation. Use a saturation curve to prevent
172-
// clipping at maximum saturation with ugly results.
173-
s = qMin(( int )( 255. * ( 1 - pow( 1 - (( double )s / 255. ) , saturationScale * 2 ) ) ), 255 );
169+
case GrayscaleLightness:
170+
{
171+
// Lightness mode, set saturation to zero
172+
s = 0;
173+
myColor = QColor::fromHsl( h, s, l );
174+
break;
175+
}
176+
case GrayscaleLuminosity:
177+
{
178+
// Grayscale by weighted rgb components
179+
int luminosity = 0.21 * r + 0.72 * g + 0.07 * b;
180+
r = g = b = luminosity;
181+
myColor = QColor::fromRgb( r, g, b );
182+
break;
183+
}
184+
case GrayscaleAverage:
185+
{
186+
// Grayscale by average of rgb components
187+
int average = ( r + g + b ) / 3;
188+
r = g = b = average;
189+
myColor = QColor::fromRgb( r, g, b );
190+
break;
191+
}
192+
case GrayscaleOff:
193+
{
194+
// Not being made grayscale, do saturation change
195+
if ( saturationScale < 1 )
196+
{
197+
// Lowering the saturation. Use a simple linear relationship
198+
s = qMin(( int )( s * saturationScale ), 255 );
199+
}
200+
else
201+
{
202+
// Raising the saturation. Use a saturation curve to prevent
203+
// clipping at maximum saturation with ugly results.
204+
s = qMin(( int )( 255. * ( 1 - pow( 1 - (( double )s / 255. ) , saturationScale * 2 ) ) ), 255 );
205+
}
206+
myColor = QColor::fromHsl( h, s, l );
207+
break;
208+
}
174209
}
175210

176211
// Convert back to rgb
177-
myColor = QColor::fromHsv( h, s, v );
178212
outputBlock->setColor( i, myColor.rgb() );
179213
}
180214

@@ -192,6 +226,7 @@ void QgsHueSaturationFilter::writeXML( QDomDocument& doc, QDomElement& parentEle
192226
QDomElement filterElem = doc.createElement( "huesaturation" );
193227

194228
filterElem.setAttribute( "saturation", QString::number( mSaturation ) );
229+
filterElem.setAttribute( "grayscaleMode", QString::number( mGrayscaleMode ) );
195230
parentElem.appendChild( filterElem );
196231
}
197232

@@ -203,4 +238,5 @@ void QgsHueSaturationFilter::readXML( const QDomElement& filterElem )
203238
}
204239

205240
mSaturation = filterElem.attribute( "saturation", "0" ).toInt();
241+
mGrayscaleMode = ( QgsHueSaturationFilter::GrayscaleMode )filterElem.attribute( "grayscaleMode", "0" ).toInt();
206242
}

‎src/core/raster/qgshuesaturationfilter.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ class QDomElement;
2929
class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
3030
{
3131
public:
32+
33+
// Available modes for converting a raster to grayscale
34+
enum GrayscaleMode
35+
{
36+
GrayscaleOff,
37+
GrayscaleLightness,
38+
GrayscaleLuminosity,
39+
GrayscaleAverage
40+
};
41+
3242
QgsHueSaturationFilter( QgsRasterInterface *input = 0 );
3343
~QgsHueSaturationFilter();
3444

@@ -45,6 +55,9 @@ class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
4555
void setSaturation( int saturation ) { mSaturation = qBound( -100, saturation, 100 ); }
4656
int saturation() const { return mSaturation; }
4757

58+
void setGrayscaleMode( QgsHueSaturationFilter::GrayscaleMode grayscaleMode ) { mGrayscaleMode = grayscaleMode; }
59+
QgsHueSaturationFilter::GrayscaleMode grayscaleMode() const { return mGrayscaleMode; }
60+
4861
void writeXML( QDomDocument& doc, QDomElement& parentElem );
4962

5063
/**Sets base class members from xml. Usually called from create() methods of subclasses*/
@@ -54,6 +67,9 @@ class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
5467
/**Current saturation value. Range: -100 (desaturated) ... 0 (no change) ... 100 (increased)*/
5568
int mSaturation;
5669

70+
/**Current grayscale mode*/
71+
QgsHueSaturationFilter::GrayscaleMode mGrayscaleMode;
72+
5773
};
5874

5975
#endif // QGSHUESATURATIONFILTER_H

‎src/ui/qgsrasterlayerpropertiesbase.ui

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@
263263
<bool>true</bool>
264264
</property>
265265
<layout class="QGridLayout" name="_7">
266-
<item row="0" column="0">
266+
<item row="0" column="1">
267267
<widget class="QSlider" name="sliderSaturation">
268268
<property name="sizePolicy">
269269
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -288,7 +288,7 @@
288288
</property>
289289
</widget>
290290
</item>
291-
<item row="0" column="1">
291+
<item row="0" column="2">
292292
<widget class="QSpinBox" name="spinBoxSaturation">
293293
<property name="minimum">
294294
<number>-100</number>
@@ -304,6 +304,44 @@
304304
</property>
305305
</widget>
306306
</item>
307+
<item row="0" column="0">
308+
<widget class="QLabel" name="labelSaturation">
309+
<property name="text">
310+
<string>Saturation</string>
311+
</property>
312+
</widget>
313+
</item>
314+
<item row="0" column="4">
315+
<widget class="QLabel" name="labelGrayscale">
316+
<property name="text">
317+
<string>Grayscale</string>
318+
</property>
319+
</widget>
320+
</item>
321+
<item row="0" column="5">
322+
<widget class="QComboBox" name="comboGrayscale">
323+
<item>
324+
<property name="text">
325+
<string>Off</string>
326+
</property>
327+
</item>
328+
<item>
329+
<property name="text">
330+
<string>By lightness</string>
331+
</property>
332+
</item>
333+
<item>
334+
<property name="text">
335+
<string>By luminosity</string>
336+
</property>
337+
</item>
338+
<item>
339+
<property name="text">
340+
<string>By average</string>
341+
</property>
342+
</item>
343+
</widget>
344+
</item>
307345
</layout>
308346
</widget>
309347
</item>

0 commit comments

Comments
 (0)
Please sign in to comment.