1 /**
2 * @brief
3 *
4 * This file is a part of PFSTOOLS package.
5 * ----------------------------------------------------------------------
6 * Copyright (C) 2003,2004 Rafal Mantiuk and Grzegorz Krawczyk
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * ----------------------------------------------------------------------
22 *
23 * @author Rafal Mantiuk, <mantiuk@mpi-sb.mpg.de>
24 *
25 * $Id: luminancerange_widget.cpp,v 1.6 2013/12/21 19:42:28 rafm Exp $
26 */
27
28 #include <config.h>
29
30 #include <qpainter.h>
31 #include <qcursor.h>
32 #include <QPaintEvent>
33 #include <QMouseEvent>
34
35 #include <math.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 //#include <algorithm>
40 #include "luminancerange_widget.h"
41 #include "histogram.h"
42
43 static const float exposureStep = 0.25f;
44 static const float shrinkStep = 0.1f;
45 static const float minWindowSize = 0.1f;
46
47 static const int dragZoneMargin = 5; // How many pizels from the range window border should draging be activated
48
49 #define min(x,y) ( (x)<(y) ? (x) : (y) )
50 #define max(x,y) ( (x)>(y) ? (x) : (y) )
51
LuminanceRangeWidget(QWidget * parent)52 LuminanceRangeWidget::LuminanceRangeWidget( QWidget *parent ):
53 QFrame( parent ), histogram( NULL ), histogramImage( NULL ),
54 showVP( false )
55 {
56 setFrameShape( QFrame::Box );
57
58 setMouseTracking( true );
59
60 minValue = -6;
61 maxValue = 8;
62 windowMin = 0;
63 windowMax = 2;
64
65 mouseDragStart = -1;
66 dragShift = 0;
67
68 }
69
~LuminanceRangeWidget()70 LuminanceRangeWidget::~LuminanceRangeWidget()
71 {
72 delete histogram;
73
74 }
75
76
sizeHint() const77 QSize LuminanceRangeWidget::sizeHint () const
78 {
79 return QSize( 300, 22 );
80 }
81
82 #define getWindowX( x ) ((int)((x-minValue) / (maxValue-minValue) * (float)fRect.width()) + fRect.left())
83
paintEvent(QPaintEvent * pe)84 void LuminanceRangeWidget::paintEvent( QPaintEvent *pe )
85 {
86 {
87 QPainter p( this );
88
89 QRect fRect = getPaintRect();
90
91 if( fRect.width() < 50 ) // Does not make sense to paint anything
92 return;
93
94 // Paint range window
95 {
96 int x1, x2;
97 x1 = getWindowX( draggedMin() );
98 x2 = getWindowX( draggedMax() );
99 QColor selectionColor = mouseDragStart == DRAGNOTSTARTED ?
100 QColor( 0, 100, 255 ) : QColor( 0, 150, 255 );
101 p.fillRect( x1, fRect.top(), x2-x1, fRect.height(), QBrush( selectionColor ) );
102 }
103
104 // Paint histogram
105 if( histogramImage != NULL ) {
106 if( histogram == NULL || histogram->getBins() != fRect.width() ) {
107 delete histogram;
108 // Build histogram from at least 5000 pixels
109 int accuracy = histogramImage->getRows()*histogramImage->getCols()/5000;
110 if( accuracy < 1 ) accuracy = 1;
111 histogram = new Histogram( fRect.width(), accuracy );
112 histogram->computeLog( histogramImage, minValue, maxValue );
113 }
114
115 float maxP = histogram->getMaxP();
116 int i = 0;
117 p.setPen( Qt::green );
118 for( int x = fRect.left(); i < histogram->getBins(); x++, i++ ) {
119 if( histogram->getP(i) > 0 ) {
120 int barSize = (int)((float)fRect.height() * histogram->getP(i)/maxP);
121 p.drawLine( x, fRect.bottom(), x, fRect.bottom() - barSize );
122 }
123
124 }
125
126 }
127
128 // Paint scale
129 QFont labelFont( "SansSerif", 8 );
130 p.setFont( labelFont );
131 p.setPen( Qt::black );
132 QRect textBounding = p.boundingRect( fRect, Qt::AlignHCenter|Qt::AlignBottom, "-8" );
133 for( float x = ceil( minValue ); x <= floor( maxValue ); x++ ) {
134 int rx = getWindowX(x);
135 p.drawLine( rx, fRect.top(), rx, textBounding.top() );
136 char str[10];
137 sprintf( str, "%g", x );
138 p.drawText( rx-20, textBounding.top(), 40, textBounding.height(),
139 Qt::AlignHCenter|Qt::AlignBottom, str );
140 }
141
142
143 // Paint value pointer
144 if( showVP )
145 {
146 int x = getWindowX( valuePointer );
147 if( fRect.contains( x, fRect.y() ) ) {
148 p.setPen( Qt::yellow );
149 p.drawLine( x, fRect.top(), x, fRect.bottom() );
150 }
151
152 }
153
154 }
155 QFrame::paintEvent(pe);
156 }
157
draggedMin()158 float LuminanceRangeWidget::draggedMin()
159 {
160 if( mouseDragStart == DRAGNOTSTARTED ) return windowMin;
161 if( dragMode == DRAG_MIN ) {
162 float draggedPos = windowMin+dragShift;
163 return min( draggedPos, windowMax - minWindowSize );
164 } else if( dragMode == DRAG_MINMAX ) {
165 return windowMin+dragShift;
166 }
167 return windowMin;
168 }
169
draggedMax()170 float LuminanceRangeWidget::draggedMax()
171 {
172 if( mouseDragStart == DRAGNOTSTARTED ) return windowMax;
173 if( dragMode == DRAG_MAX ) {
174 float draggedPos = windowMax+dragShift;
175 return max( draggedPos, windowMin + minWindowSize );
176 } else if( dragMode == DRAG_MINMAX ) {
177 return windowMax+dragShift;
178 }
179 return windowMax;
180 }
181
182
183
mousePressEvent(QMouseEvent * me)184 void LuminanceRangeWidget::mousePressEvent ( QMouseEvent * me )
185 {
186 if( dragMode == DRAG_NO ) return;
187
188 mouseDragStart = me->x();
189 dragShift = 0;
190 update();
191 }
192
mouseReleaseEvent(QMouseEvent *)193 void LuminanceRangeWidget::mouseReleaseEvent ( QMouseEvent * )
194 {
195
196 float newWindowMin = draggedMin();
197 float newWindowMax = draggedMax();
198 mouseDragStart = DRAGNOTSTARTED;
199 windowMin = newWindowMin;
200 windowMax = newWindowMax;
201 dragShift = 0;
202 update();
203 updateRangeWindow();
204 }
205
mouseMoveEvent(QMouseEvent * me)206 void LuminanceRangeWidget::mouseMoveEvent( QMouseEvent *me )
207 {
208 // printf( "MouseButton: %d\n", me->button() );
209
210 if( (me->buttons() & Qt::LeftButton) != 0 && dragMode != DRAG_NO ) {
211
212 if( mouseDragStart != DRAGNOTSTARTED ) {
213 QRect fRect = getPaintRect();
214
215 int windowCordShift = me->x() - mouseDragStart;
216 dragShift = (float)windowCordShift / (float)fRect.width() * (maxValue - minValue);
217 update();
218 }
219
220 } else {
221
222 QRect fRect = rect();
223 int winBegPos = getWindowX( windowMin );
224 int winEndPos = getWindowX( windowMax );
225 if( abs( me->x() - winBegPos ) < dragZoneMargin ) {
226 setCursor( QCursor( Qt::SplitHCursor ) );
227 dragMode = DRAG_MIN;
228 } else if( abs( me->x() - winEndPos ) < dragZoneMargin ) {
229 setCursor( QCursor( Qt::SplitHCursor ) );
230 dragMode = DRAG_MAX;
231 } else if( me->x() > winBegPos && me->x() < winEndPos ) {
232 setCursor( QCursor( Qt::SizeHorCursor ) );
233 dragMode = DRAG_MINMAX;
234 } else {
235 unsetCursor();
236 dragMode = DRAG_NO;
237 }
238
239 }
240
241 }
242
decreaseExposure()243 void LuminanceRangeWidget::decreaseExposure()
244 {
245 windowMin -= exposureStep;
246 windowMax -= exposureStep;
247 update();
248 updateRangeWindow();
249 }
250
increaseExposure()251 void LuminanceRangeWidget::increaseExposure()
252 {
253 windowMin += exposureStep;
254 windowMax += exposureStep;
255 update();
256 updateRangeWindow();
257 }
258
extendRange()259 void LuminanceRangeWidget::extendRange()
260 {
261 if( windowMax - windowMin > 10 ) return;
262 windowMin -= shrinkStep;
263 windowMax += shrinkStep;
264 update();
265 updateRangeWindow();
266 }
267
shrinkRange()268 void LuminanceRangeWidget::shrinkRange()
269 {
270 if( windowMax - windowMin < 0.19 ) return;
271 windowMin += shrinkStep;
272 windowMax -= shrinkStep;
273 update();
274 updateRangeWindow();
275 }
276
setHistogramImage(const pfs::Array2D * image)277 void LuminanceRangeWidget::setHistogramImage( const pfs::Array2D *image )
278 {
279 histogramImage = image;
280 delete histogram;
281 histogram = NULL;
282 update();
283 }
284
fitToDynamicRange()285 void LuminanceRangeWidget::fitToDynamicRange()
286 {
287 if( histogramImage != NULL ) {
288 float min = 99999999;
289 float max = -99999999;
290
291 int size = histogramImage->getRows()*histogramImage->getCols();
292 for( int i = 0; i < size; i++ ) {
293 float v = (*histogramImage)(i);
294 if( v > max ) max = v;
295 else if( v < min ) min = v;
296 }
297
298 if( min <= 0.000001 ) min = 0.000001; // If data contains negative values
299
300 windowMin = log10( min );
301 windowMax = log10( max );
302
303 if( windowMax - windowMin < 0.5 ) { // Window too small
304 float m = (windowMin + windowMax)/2.f;
305 windowMax = m + 0.25;
306 windowMin = m - 0.25;
307 }
308 update();
309 updateRangeWindow();
310 }
311 }
312
lowDynamicRange()313 void LuminanceRangeWidget::lowDynamicRange()
314 {
315 windowMin = -2.0f;
316 windowMax = 0.0f;
317
318 update();
319 updateRangeWindow();
320 }
321
getPaintRect() const322 QRect LuminanceRangeWidget::getPaintRect() const
323 {
324 QRect fRect = frameRect();
325 fRect.setLeft( fRect.left()+1 );
326 fRect.setTop( fRect.top()+1 );
327 fRect.setBottom( fRect.bottom()-1 );
328 fRect.setRight( fRect.right()-1 );
329 return fRect;
330 }
331
showValuePointer(float value)332 void LuminanceRangeWidget::showValuePointer( float value )
333 {
334 QRect fRect = getPaintRect();
335 int oldx = showVP ? getWindowX( valuePointer ) : -1;
336
337 valuePointer = value;
338 showVP = true;
339
340 int newx = getWindowX( valuePointer );
341 if( oldx == -1 ) oldx = newx;
342
343 QRect updateRect( min( oldx, newx ), fRect.top(),
344 max( oldx, newx ) - min(oldx, newx )+1, fRect.height() );
345
346
347 update( updateRect );
348 }
349
setRangeWindowMinMax(float min,float max)350 void LuminanceRangeWidget::setRangeWindowMinMax( float min, float max )
351 {
352 assert( min < max );
353 windowMin = min;
354 windowMax = max;
355 update();
356 updateRangeWindow();
357 }
358
359
hideValuePointer()360 void LuminanceRangeWidget::hideValuePointer()
361 {
362 showVP = false;
363 update();
364 }
365
366
367
368