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