1 /**
2 * @brief PFS library - additional utilities
3 *
4 * This file is a part of PFSTOOLS package.
5 * ----------------------------------------------------------------------
6 * Copyright (C) 2006 Radoslaw Mantiuk
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library 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 GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * ----------------------------------------------------------------------
22 *
23 * @author Radoslaw Mantiuk, <radoslaw.mantiuk@gmail.com>
24 * @author Oliver Barth <obarth@mpi-inf.mpg.de>
25 */
26
27 #include <stdio.h>
28 #include <vector>
29 #include <algorithm>
30 #include <math.h>
31
32 #include "pfs.h"
33
34 #include "m_histogram.h"
35
36 #define BORDER_SIDE 20
37 #define BORDER_BOTTOM 30
38 #define BORDER_TOP 5
39 #define SLIDER_WIDTH 16
40 #define SCALE_BORDER_TOP 3
41 #define SCALE_BORDER_BOTTOM 3
42 #define MIN_LUM 0.00000001f
43 #define MAX_LUM 100000000.0f
44
45 // WHITE
46 #define W_R 1.0
47 #define W_G 1.0
48 #define W_B 1.0
49 #define W_A 0.45
50
51 // RED
52 #define R_R 1.0
53 #define R_G 0.1
54 #define R_B 0.1
55 #define R_A 0.9
56
57 // GREEN
58 #define G_R 0.1
59 #define G_G 0.75
60 #define G_B 0.1
61 #define G_A 0.9
62
63 // BLUE
64 #define B_R 0.25
65 #define B_G 0.25
66 #define B_B 1.0
67 #define B_A 0.9
68
69
70
71
72 /**
73 */
M_Histogram()74 M_Histogram::M_Histogram() : Module() {
75
76 // set inital height
77 height = 150 ;
78
79 // set background color of the widget to black
80 winBackgroundColor = new float[4];
81 for(int i=0; i<3; i++)
82 winBackgroundColor[i] = 0.0f;
83 // no transparency please
84 winBackgroundColor[3] = 1.0f;
85
86 // array for the frequency analysis
87 frequencyValues = NULL ;
88
89 // set a fixed size of bins
90 bins = 20000 ;
91
92 // set sigma values for pre- and postsmoothing
93 // gauss_data = (float)bins/1000 ; // take this for an adaptive approach , experimental
94 gauss_data = 2.5 ;
95 gauss_display = 2.5 ;
96
97 // enabled smoothing of the intensity scale values by default
98 is_scale_gaussed = 1 ;
99
100 // disable smoothing of the intensity scale values
101 is_scale_show_max_hue = 0 ;
102 // amplifiy the intensity values by default for better visibility
103 scale_amplifier = 0.5 ;
104
105 // set the default channel
106 channel = "XYZ" ;
107
108 // invalidate the calculated maximum frequency
109 frequencyMax = -1;
110
111 // set the inital slider position
112 sliderPosMin = 0;
113 sliderPosMax = 0;
114
115 // set the predefined luminance range
116 lumMin = MIN_LUM;
117 lumMax = MAX_LUM;
118 logLumMin = log10(lumMin);
119 logLumMax = log10(lumMax);
120
121 // set inital hover state
122 hoverState = NONE;
123
124 virtualWidth = 1.0 ;
125 virtualOffset = 0.5 ;
126
127 abort_update = 0;
128 }
129
130
131 const float hist_color_max = 1.0f;
132 const float hist_color_min = 0.2f;
133 const float hist_color_alpha = 0.9f;
134
135
~M_Histogram()136 M_Histogram::~M_Histogram()
137 {
138 delete [] frequencyValues;
139 }
140
redraw(void)141 void M_Histogram::redraw(void) {
142 if(frequencyValues == NULL) return ;
143
144 Module::redrawStart();
145
146 drawHistogram();
147 drawScale();
148 drawSlider();
149 drawStatistic();
150
151 Module::redrawEnd();
152 }
153
154
155
156 /** Draws histogram.
157 */
drawHistogram()158 void M_Histogram::drawHistogram() {
159
160 if(frequencyValues == NULL)
161 return;
162
163 if( frequencyMax == -1)
164 frequencyMax = getMaxFrequency();
165 int offsetX = BORDER_SIDE;
166 int offsetY = BORDER_BOTTOM;
167 // if(virtualWidth <= 1) virtualOffset = 0.5 ;
168 float offset = -virtualOffset * (virtualWidth -1.0) * (float)bins ;
169 float barHeight = 0;
170 float center = 0 ;
171 float strech = ((float)width- BORDER_SIDE*2)/(float)bins ;
172 float relative_height ;
173 float c_pos = lum2pos(center) ;
174
175 glEnable(GL_BLEND);
176
177 int array_pos ;
178 int ch = 0 ;
179 if(!(strcmp(channel, "XYZ") == 0))
180 switch(channel[0]) {
181 case 'X': ch = 1 ; break ;
182 case 'Y': ch = 2 ; break ;
183 case 'Z': ch = 3 ; break ;
184 }
185
186
187 float valX = log10(rawX);
188 float valY = log10(rawY);
189 float valZ = log10(rawZ);
190 int indexX = (int)round((valX - logLumMin) / (logLumMax - logLumMin) * (float)bins);
191 int indexY = (int)round((valY - logLumMin) / (logLumMax - logLumMin) * (float)bins);
192 int indexZ = (int)round((valZ - logLumMin) / (logLumMax - logLumMin) * (float)bins);
193 if(rawPosX == -1 || rawPosY == -1){
194 indexX = -1 ;
195 indexY = -1 ;
196 indexZ = -1 ;
197 }
198
199
200 for(int pos = offsetX; pos< width-BORDER_SIDE; pos++) {
201
202
203 switch(ch) {
204 case 0: glColor4f(W_R, W_G, W_B, W_A); break ;
205 case 1: glColor4f(R_R, R_G, R_B, R_A); break ;
206 case 2: glColor4f(G_R, G_G, G_B, G_A); break ;
207 case 3: glColor4f(B_R, B_G, B_B, B_A); break ;
208 }
209
210
211 int ch_offset = 0 ;
212 if(!is_scale_gaussed) ch_offset = 4 ;
213
214 // GAUSS DISPLAY HIST
215 float relative_height = 0 ;
216 float his_width = (float)(width-BORDER_SIDE*2) ;
217 float painter = (float)(pos-BORDER_SIDE) / his_width ;
218 float fbins = (float)bins ;
219
220 float ext_g_weight = 0 ;
221 float ext_g_sigma = gauss_display ;
222 if(!is_scale_gaussed) ext_g_sigma = 0.01 ;
223 float ext_g_width = ceil(ext_g_sigma * 3) ;
224
225 for(int k = -ext_g_width ; k <= ext_g_width ; k++){
226 array_pos =(int) (painter * fbins - offset + k * fbins / his_width) /virtualWidth ;
227 if(array_pos < 0 || array_pos >= bins) continue ;
228 float ext_gaussian = 1.0/(ext_g_sigma*sqrt(2.0*M_PI)) * exp(-0.5*pow((float)k/ext_g_sigma,2.0)) ;
229 ext_g_weight += ext_gaussian ;
230 relative_height += ((float)frequencyValues[ch + ch_offset][array_pos]) / frequencyMax * ext_gaussian;
231 }
232
233 relative_height /= ext_g_weight;
234
235 if( relative_height > 1){
236 relative_height = 1;
237 }
238 barHeight = ((float)height - BORDER_BOTTOM -BORDER_TOP) * relative_height;
239
240 // DRAW HIST
241 if(barHeight > 0)
242 glRectf(pos, offsetY, pos+1, offsetY + barHeight);
243
244
245
246 // DRAW SCALE
247 array_pos = floor((painter * fbins - offset)/virtualWidth) ;
248 int array_pos_min =floor( ((float)(pos-BORDER_SIDE) / his_width * fbins - offset)/virtualWidth) ;
249 int array_pos_max =floor( ((float)(pos+1-BORDER_SIDE) / his_width * fbins - offset)/virtualWidth) ;
250 if(array_pos_min == array_pos_max) array_pos_max++ ;
251
252 int r = 0 ;
253 int g = 0 ;
254 int b = 0 ;
255
256 if(ch == 0){
257 if(indexX >= array_pos_min && indexX < array_pos_max) r = 1.0 ;
258 if(indexY >= array_pos_min && indexY < array_pos_max) g = 1.0 ;
259 if(indexZ >= array_pos_min && indexZ < array_pos_max) b = 1.0 ;
260 }else{
261 r = 1.0 ;
262 g = 1.0 ;
263 b = 1.0 ;
264 }
265
266 if( (indexX >= array_pos_min && indexX < array_pos_max && (ch == 0 || ch == 1))
267 || (indexY >= array_pos_min && indexY < array_pos_max && (ch == 0 || ch == 2))
268 || (indexZ >= array_pos_min && indexZ < array_pos_max && (ch == 0 || ch == 3))
269 ){
270 glColor4f(r, g, b, 0.75);
271 glRectf(pos, offsetY, pos+1, offsetY + (float)height - BORDER_BOTTOM -BORDER_TOP);
272 }
273
274 if(array_pos > 0 && array_pos < bins) {
275
276 // for ch == 0
277 float cr, cg, cb, sum, weight ;
278
279 // for ch > 0
280 float value ;
281 float hue = 0 ;
282 if(ch > 0) value = frequencyValues[ch + ch_offset][array_pos] ;
283 // dont waste time, go to the next round
284 if(ch > 0 && value == 0) continue ;
285 if(ch > 0) hue = is_scale_show_max_hue?1.0:pow(value / frequencyMax,scale_amplifier) ;
286
287 switch(ch) {
288 case 0:
289 cr = frequencyValues[1 + ch_offset][array_pos] ;
290 cg = frequencyValues[2 + ch_offset][array_pos] ;
291 cb = frequencyValues[3 + ch_offset][array_pos] ;
292 sum = (cr + cg +cb) / 3.0 ;
293 // dont waste time, go to the next round
294 if(sum == 0) continue ;
295 weight = cr ;
296 if(cg > weight) weight = cg ;
297 if(cb > weight) weight = cb ;
298 cr /= weight ;
299 cg /= weight ;
300 cb /= weight ;
301 hue = is_scale_show_max_hue?1.0:pow(sum / frequencyMax,scale_amplifier) ;
302 glColor4f(cr, cg, cb, hue);
303 break ;
304 case 1: glColor4f(R_R, R_G, R_B, hue); break ;
305 case 2: glColor4f(G_R, G_G, G_B, hue); break ;
306 case 3: glColor4f(B_R, B_G, B_B, hue); break ;
307 }
308 glRectf(pos, SCALE_BORDER_BOTTOM, pos+1, 0 + BORDER_BOTTOM-1 -SCALE_BORDER_TOP);
309 }
310 }
311
312 glDisable(GL_BLEND);
313 }
314
315
316
317 /** Draws scale
318 */
drawScale()319 void M_Histogram::drawScale() {
320
321 glColor3f(1.0f, 1.0f, 1.0f);
322
323 float pos;
324 int offsetX = BORDER_SIDE ;
325 int offsetY = BORDER_BOTTOM;
326 int k1 = 0;
327
328 // if(virtualWidth <= 1) virtualOffset = 0.5 ;
329 float offset = -virtualOffset * (virtualWidth -1.0) * (width- BORDER_SIDE*2) ;
330
331 for( float i = (float)logLumMin; i <= (float)logLumMax; i=i+0.25) {
332
333 pos = lum2pos( pow(10, (float)i)) * ((float)width- BORDER_SIDE*2);
334
335 pos *= virtualWidth ;
336 pos += offset ;
337
338 int hh = 2;
339 if( round(i) == i) hh = 4;
340 glRectf( offsetX + pos, offsetY - hh, offsetX + pos + 1, offsetY + hh -1);
341
342 if( round(i) == i) {
343 if( i < 0 ) {
344 glRasterPos2f( offsetX + pos - 9, offsetY - 15);
345 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, '-');
346 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, '8' - (k1++));
347 }
348 else if( i == 0 ) {
349 glRasterPos2f( offsetX + pos - 1, offsetY - 15);
350 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, '0' + i);
351 }
352 else {
353 glRasterPos2f( offsetX + pos - 2, offsetY - 15);
354 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, '0' + i);
355 }
356 }
357
358 }
359 glRectf( offsetX + (0 * virtualWidth) + offset, offsetY, offsetX + pos + 1, offsetY-1);
360 }
361
362
363
364 /** Draws slider
365 */
drawSlider()366 void M_Histogram::drawSlider()
367 {
368
369 // if(virtualWidth <= 1) virtualOffset = 0.5 ;
370 float offset = -virtualOffset * (virtualWidth -1.0) * (width- BORDER_SIDE*2) ;
371
372 float minValue = (width- BORDER_SIDE*2) * sliderPosMin;
373 float maxValue = (width- BORDER_SIDE*2) * sliderPosMax;
374 int sliderHeight = height -BORDER_BOTTOM -BORDER_TOP ;
375
376 int offsetX = BORDER_SIDE;
377 int offsetY = height -BORDER_TOP;
378
379 glEnable(GL_BLEND);
380 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
381 glMatrixMode(GL_MODELVIEW) ;
382
383 // BOTTOM
384 glPushMatrix();
385 glLoadName(BOTTOM);
386 glColor4f(1.0f, 0.0f, 0.0f, 0.8f);
387 glBegin(GL_QUADS);
388 glVertex3f(offsetX-BORDER_SIDE, 0, -0.5f);
389 glVertex3f(offsetX-BORDER_SIDE, -Y_BAR/2, -0.5f);
390 glVertex3f(offsetX + width - BORDER_SIDE, -Y_BAR/2, -0.5f);
391 glVertex3f(offsetX + width - BORDER_SIDE, 0, -0.5f);
392 glEnd();
393 glPopMatrix();
394
395 offsetX += offset ;
396 minValue *= virtualWidth ;
397 maxValue *= virtualWidth ;
398
399
400 // SLIDER
401 if(minValue-SLIDER_WIDTH>0){
402 glLoadName(WHOLE_SLIDER);
403 glColor4f(1.0f, 0.0f, 0.0f, 0.25f);
404 glBegin(GL_QUADS);
405 glVertex3f(offsetX + 0, offsetY, -0.5f);
406 glVertex3f(offsetX + 0, offsetY - sliderHeight, -0.5f);
407 glVertex3f(offsetX + minValue-SLIDER_WIDTH, offsetY - sliderHeight, -0.5f);
408 glVertex3f(offsetX + minValue-SLIDER_WIDTH, offsetY, -0.5f);
409 glEnd();
410 }
411
412 if(maxValue+SLIDER_WIDTH < (width-2*BORDER_SIDE) * virtualWidth ){
413 glLoadName(WHOLE_SLIDER);
414 glColor4f(1.0f, 0.0f, 0.0f, 0.25f);
415 glBegin(GL_QUADS);
416 glVertex3f(offsetX + maxValue+SLIDER_WIDTH, offsetY, -0.5f);
417 glVertex3f(offsetX + maxValue+SLIDER_WIDTH, offsetY - sliderHeight, -0.5f);
418 glVertex3f(offsetX + (width-2*BORDER_SIDE) * virtualWidth , offsetY - sliderHeight, -0.5f);
419 glVertex3f(offsetX + (width-2*BORDER_SIDE) * virtualWidth , offsetY, -0.5f);
420 glEnd();
421 }
422
423 glLoadName(WHOLE_SLIDER);
424 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
425 glBegin(GL_QUADS);
426 glVertex3f(offsetX + minValue, offsetY, -0.5f);
427 glVertex3f(offsetX + minValue, offsetY - sliderHeight, -0.5f);
428 glVertex3f(offsetX + maxValue, offsetY - sliderHeight, -0.5f);
429 glVertex3f(offsetX + maxValue, offsetY, -0.5f);
430 glEnd();
431
432 // LEFT
433 glPushMatrix();
434 glLoadName(LEFT_BAR);
435 glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
436 glBegin(GL_QUADS);
437 glVertex3f(offsetX + minValue-SLIDER_WIDTH, offsetY, -0.5f);
438 glVertex3f(offsetX + minValue-SLIDER_WIDTH, offsetY - sliderHeight, -0.5f);
439 glVertex3f(offsetX + minValue, offsetY - sliderHeight, -0.5f);
440 glVertex3f(offsetX + minValue, offsetY, -0.5f);
441 glEnd();
442
443 // RIGHT
444 glPushMatrix();
445 glLoadName(RIGHT_BAR);
446 glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
447 glBegin(GL_QUADS);
448 glVertex3f(offsetX + maxValue, offsetY, -0.5f);
449 glVertex3f(offsetX + maxValue, offsetY - sliderHeight, -0.5f);
450 glVertex3f(offsetX + maxValue+SLIDER_WIDTH, offsetY - sliderHeight, -0.5f);
451 glVertex3f(offsetX + maxValue+SLIDER_WIDTH, offsetY, -0.5f);
452 glEnd();
453 glPopMatrix();
454
455
456
457 // BACK + SCALE
458 offsetX = BORDER_SIDE;
459 offsetY = height ;
460 glPushMatrix();
461 glLoadName(BACK);
462 glColor4f(0.0f, 1.0f, 0.0f, 0.0f);
463 glBegin(GL_QUADS);
464 glVertex3f(0, 0, -0.5f);
465 glVertex3f(0, offsetY, -0.5f);
466 glVertex3f(offsetX + width - BORDER_SIDE, offsetY, -0.5f);
467 glVertex3f(offsetX + width - BORDER_SIDE, 0, -0.5f);
468 glEnd();
469 glPopMatrix();
470
471
472 glDisable(GL_BLEND);
473 }
474
475
476 /** Draws statistic of a current image.
477 */
drawStatistic()478 void M_Histogram::drawStatistic() {
479
480 int offsetX = width - 24*8 -BORDER_SIDE;
481 int offsetY = height - 13 -BORDER_TOP ;
482
483 glColor3f(0.5f, 1.0f, 0.5f);
484
485 glRasterPos2f( offsetX, offsetY );
486
487 char ss[200];
488 sprintf( ss, "logLum.:<%.3f, %.3f>"
489 , log10(pos2lum(sliderPosMin)), log10(pos2lum(sliderPosMax)));
490
491 int len = (int) strlen(ss);
492
493
494
495 for (int i = 0; i < len; i++) {
496 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, ss[i]);
497 }
498 }
499
setChannel(const char * ch)500 void M_Histogram::setChannel(const char* ch) {
501 channel = ch;
502 }
503
504
505
506
clearChannel(int ch,void CB (void))507 void M_Histogram::clearChannel(int ch, void CB(void)) {
508
509 if(frequencyValues == NULL) return ;
510
511
512
513 #pragma omp parallel for
514 for( int i = 0; i < bins; i++ ){
515 if(abort_update == 1) continue ;
516 frequencyValues[ch][i] = 0;
517 frequencyValues[ch+4][i] = 0;
518 }
519
520 #pragma omp parallel for
521 for( int i = 0; i < bins; i++ ){
522 if(abort_update == 1) continue ;
523 frequencyValues[8][i] = 0;
524 }
525 CB() ;
526
527 }
528
529
530
531
532
533
534
535
536 /** Creates histogram. Histogram will have 'width' bins.
537 */
computeFrequency(int ch,const pfs::Array2D * image,void CB (void))538 void M_Histogram::computeFrequency(int ch, const pfs::Array2D *image,void CB(void)) {
539
540 dbs("Histogram::computeFrequency") ;
541
542 if(ch == 0 && image == NULL){
543
544
545 #pragma omp parallel for
546 for( int i = 0; i < bins; i++ ){
547 if(abort_update == 1) continue ;
548 frequencyValues[0][i] =
549 frequencyValues[1][i]
550 +frequencyValues[2][i]
551 +frequencyValues[3][i] ;
552 frequencyValues[0][i] = ceil((float)frequencyValues[0][i] / 3.0) ;
553
554 frequencyValues[4][i] =
555 frequencyValues[5][i]
556 +frequencyValues[6][i]
557 +frequencyValues[7][i] ;
558 frequencyValues[4][i] = (float)frequencyValues[4][i] / 3.0 ;
559 if(i % 10 == 0) CB() ;
560 }
561 return ;
562 }
563
564
565 const int size = image->getRows()*image->getCols();
566
567
568 if(frequencyValues == NULL){
569 // binborder = new float[bins+1];
570 frequencyValues = new int*[9];
571
572 frequencyValues[0] = new int[bins];
573 frequencyValues[1] = new int[bins];
574 frequencyValues[2] = new int[bins];
575 frequencyValues[3] = new int[bins];
576
577 frequencyValues[4] = new int[bins];
578 frequencyValues[5] = new int[bins];
579 frequencyValues[6] = new int[bins];
580 frequencyValues[7] = new int[bins];
581
582 frequencyValues[8] = new int[bins];
583 // for( int i = 0; i < bins; i++ ){
584 // frequencyValues[0][i] = 0;
585 // frequencyValues[1][i] = 0;
586 // frequencyValues[2][i] = 0;
587 // frequencyValues[3][i] = 0;
588 //
589 // frequencyValues[4][i] = 0;
590 // frequencyValues[5][i] = 0;
591 // frequencyValues[6][i] = 0;
592 // frequencyValues[7][i] = 0;
593 // }
594
595 // for(int k = 0 ; k <= bins ; k++){
596 // binborder[k] = pow10( (double)((logLumMax - logLumMin) / (double)bins * (double)k + logLumMin));
597 // }
598 }
599
600
601
602 // int lastbin = -1 ;
603 #pragma omp parallel for
604 for( int i = 0; i < size; i=i+1 ) {
605 if(abort_update == 1) continue ;
606
607
608 float val = (*image)(i);
609 if( val <= 0 || val > lumMax) {
610 //fprintf( stderr, "WARNING: pixel luminance out of range (Histogram::computeFrequency())\n");
611 continue;
612 }
613
614
615 val = log10(val);
616
617 // Calculate frequency value index in table: <0, with>
618 int index = (int)round((val - logLumMin) / (logLumMax - logLumMin) * (float)bins);
619
620
621 // int index = -1 ;
622 //
623 // if(lastbin != -1){
624 //// printf("lb: %d\n", lastbin) ;
625 // int lastbin_b = lastbin -4 ;
626 // int lastbin_e = lastbin +4 ;
627 // if(lastbin_b < 0) lastbin_b = 0 ;
628 // if(lastbin_e > bins) lastbin_e = bins ;
629 //
630 // index = findBin(val, lastbin_b, lastbin_e) ;
631 // }
632 // if(index == -1)
633 // index = findBin(val, 0, bins) ;
634 //
635 // if(index != -1) lastbin = index ;
636
637
638
639 if( index > bins || index < 0 )
640 continue;
641 if( index == bins )
642 index = bins - 1;
643
644 // Increase the counter of this value
645 frequencyValues[ch+4][index] += 1;
646 frequencyValues[ch][index] += 1;
647
648 if(i % 10 == 0) {
649 CB() ;
650 }
651
652
653
654 }
655
656
657
658
659
660 float his_width = (float)(width-BORDER_SIDE*2) ;
661 float fbins = (float)bins ;
662
663 for(int k = 0 ; k < bins ; k++){
664 if(abort_update == 1) continue ;
665 float rel = 0 ;
666 float g_weight = 0 ;
667 float g_sigma = gauss_data ;
668 float g_width = ceil(g_sigma * 3) ;
669 for(int j = -g_width ; j <= g_width ; j++){
670 if(k +j < 0 || k +j >= bins) continue ;
671 float gaussian = 1.0/(g_sigma*sqrt(2.0*M_PI)) * exp(-0.5*pow((float)j/g_sigma,2.0)) ;
672 g_weight += gaussian ;
673 rel += (float)frequencyValues[ch+4][k+j] * gaussian;
674 }
675 // printf("weight: %f\n", g_weight) ;
676 rel /= g_weight ;
677 frequencyValues[ch][k] = rel ;
678 if(k % 10 == 0){
679 CB() ;
680 }
681 }
682
683
684 dbe("Histogram::computeFrequency") ;
685 }
686
687
findBin(float val,int start,int stop)688 int M_Histogram::findBin(float val, int start, int stop){
689
690 // fprintf(stderr, "d1 %d %d\n", start, stop) ;
691 // exit(0) ;
692
693 if(val < binborder[start] && val > binborder[stop]) {
694 // fprintf(stderr, "d1") ;
695 return -1 ;
696 }
697 if(start == stop || start == stop-1){
698 if(val >= binborder[start] && val < binborder[start+1] ) {
699 // fprintf(stderr, "d2") ;
700 return start;
701 }else{
702 // fprintf(stderr, "d3") ;
703 return -1 ;
704 }
705 }
706
707 int left = findBin(val, start, stop - (stop - start)/2) ;
708 int right = findBin(val, start + (stop - start)/2, stop) ;
709
710 // fprintf(stderr, "d4") ;
711 if(left >= 0 ) return left ;
712 // fprintf(stderr, "d5") ;
713 if(right >= 0 ) return right ;
714 // fprintf(stderr, "d6") ;
715 return -1 ;
716 }
717
718
719
720 /** Computes the maximum frequency in an image based on histogram data.
721 */
getMaxFrequency()722 float M_Histogram::getMaxFrequency() {
723 if(frequencyValues == NULL)
724 return -1;
725
726
727 int maxFreq = -1;
728 for( int i = 0; i < bins; i++ ) {
729 if( frequencyValues[0][i] > maxFreq )
730 maxFreq = frequencyValues[0][i];
731 if( frequencyValues[1][i] > maxFreq )
732 maxFreq = frequencyValues[1][i];
733 if( frequencyValues[2][i] > maxFreq )
734 maxFreq = frequencyValues[2][i];
735 if( frequencyValues[3][i] > maxFreq )
736 maxFreq = frequencyValues[3][i];
737 }
738
739 if(maxFreq == 0){
740 maxFreq = -1;
741 for( int i = 0; i < bins; i++ ) {
742 if( frequencyValues[4][i] > maxFreq )
743 maxFreq = frequencyValues[4][i];
744 if( frequencyValues[5][i] > maxFreq )
745 maxFreq = frequencyValues[5][i];
746 if( frequencyValues[6][i] > maxFreq )
747 maxFreq = frequencyValues[6][i];
748 if( frequencyValues[7][i] > maxFreq )
749 maxFreq = frequencyValues[7][i];
750 }
751 }
752
753 return maxFreq;
754 }
755
756
757 /** Returns frequence of the bin = max_bin - PERCENTIL * number_of_bins. Very light and very dark bins
758 * are not taken into consideration in this computations. It allows to skip very dark (black) and/or
759 * very light (white) pixels which can cover large areas of an image and lower the height of histogram for remaining
760 * pixels (undesirable situation: flat histogram with one large pick for very light bin).
761 */
getHighFrequency()762 float M_Histogram::getHighFrequency() {
763 if(frequencyValues == NULL)
764 return -1;
765
766 std::vector<float> vec;
767 for( int i = 0; i < bins; i++ ) {
768 vec.push_back((float)frequencyValues[0][i]);
769 vec.push_back((float)frequencyValues[1][i]);
770 vec.push_back((float)frequencyValues[2][i]);
771 vec.push_back((float)frequencyValues[3][i]);
772 }
773 std::sort(vec.begin(), vec.end());
774
775 #define PERCENTIL 0.99
776
777 float highFreq = vec[(int)((float)vec.size() * PERCENTIL)];
778
779 // returns high frequency only if max frequency is 3 or more times higher
780 float maxFreq = getMaxFrequency();
781
782 if( (3*highFreq) > maxFreq)
783 return maxFreq;
784 else
785 return highFreq;
786
787 }
788
789
790 /** Converts horizontal position in the histogram into luminance value. The position must be in range <0,1>.
791 */
pos2lum(float pos)792 float M_Histogram::pos2lum( float pos) {
793
794 if( pos < 0)
795 pos = 0;
796 if( pos > 1)
797 pos = 1;
798
799 return pow( 10, pos * (logLumMax - logLumMin) + logLumMin);
800 }
801
802 /** Converts luminance value into position in range <0,1>.
803 */
lum2pos(float lum)804 float M_Histogram::lum2pos( float lum) {
805
806 if( lum < lumMin)
807 lum = lumMin;
808 if( lum > lumMax)
809 lum = lumMax;
810
811 return (log10(lum) - logLumMin) / (logLumMax - logLumMin);
812 }
813
814
815 /** Computes initial position of the slider. The calculation are based on the shape of histogram.
816 */
817 #define FREQUENCY_EDGE 0.05
computeLumRange(float & min,float & max)818 void M_Histogram::computeLumRange( float& min, float& max) {
819 if(frequencyValues == NULL)
820 return;
821
822 float maxFreq = getMaxFrequency();
823
824 float freq;
825 for( int i = 0; i < bins; i++) {
826
827 freq = frequencyValues[0][i] / maxFreq;
828
829 if( freq > FREQUENCY_EDGE && freq < 1.0){
830 min = pos2lum((float)i / (float)bins);
831 break;
832 }
833 }
834
835 for( int i = (bins-1); i >=0; i--) {
836
837 freq = frequencyValues[0][i] / maxFreq;
838
839 if( freq > FREQUENCY_EDGE && freq < 1.0){
840 max = pos2lum((float)i / (float)bins);
841 break;
842 }
843 }
844 }
845
846
getPeak()847 float M_Histogram::getPeak() {
848 if(frequencyValues == NULL)
849 return -1;
850
851 float maxFreq = getMaxFrequency();
852
853 float freq = 0 ;
854 float j = -1 ;
855 for( int i = 0; i < bins; i++) {
856
857 if(freq < frequencyValues[0][i]){
858 freq = frequencyValues[0][i] ;
859 j = i ;
860 }
861 }
862 return pos2lum((float)j / (float)bins);
863 }
864
865
866
867
getSidebarWidth(void)868 int M_Histogram::getSidebarWidth(void) {
869 return BORDER_SIDE ;
870 }
871
872
873 /** Returns width of the histogram in pixels
874 */
getInnerWidth(void)875 int M_Histogram::getInnerWidth(void) {
876 return width - BORDER_SIDE * 2;
877 }
getInnerHeight(void)878 int M_Histogram::getInnerHeight(void) {
879 return height - BORDER_BOTTOM - BORDER_TOP;
880 }
881
getBackgroundWidth(void)882 int M_Histogram::getBackgroundWidth(void) {
883 return (width);
884 }
getBackgroundHeight(void)885 int M_Histogram::getBackgroundHeight(void) {
886 return (height);
887 }
888
getLumMin(void)889 float M_Histogram::getLumMin(void) {
890 return lumMin;
891 }
getLumMax(void)892 float M_Histogram::getLumMax(void) {
893 return lumMax;
894 }
895
896
897
setSliderPosMin(float pos)898 void M_Histogram::setSliderPosMin( float pos) {
899 if( pos > sliderPosMax)
900 pos = sliderPosMax;
901 if( pos < 0)
902 pos = 0;
903 sliderPosMin = pos;
904 }
905
getSliderPosMin(void)906 float M_Histogram::getSliderPosMin(void) {
907 return sliderPosMin;
908 }
909
setSliderPosMax(float pos)910 void M_Histogram::setSliderPosMax( float pos) {
911 if( pos < sliderPosMin)
912 pos = sliderPosMin;
913 if( pos > 1.0)
914 pos = 1.0;
915 sliderPosMax = pos;
916 }
917
getSliderPosMax(void)918 float M_Histogram::getSliderPosMax(void) {
919 return sliderPosMax;
920 }
921
setSliderPosMinMax(float min,float max)922 void M_Histogram::setSliderPosMinMax( float min, float max) {
923
924 if( min < 0)
925 min = 0;
926 if( max < 0)
927 max = 0;
928 if( min > 1.0)
929 min = 0;
930 if( max > 1.0)
931 max = 1.0;
932
933 if( min > max)
934 min = max;
935
936 sliderPosMin = min;
937 sliderPosMax = max;
938
939 }
940
941
942 /** Checks what part of slider was touched.
943 */
processPointerPosition(int xCoord,int yCoord,int pan)944 void M_Histogram::processPointerPosition(int xCoord, int yCoord, int pan) {
945 if(frequencyValues == NULL)
946 return;
947
948 redrawStart();
949
950 // Hits counter and viewport martix
951 GLint hits, viewp[4];
952 // Get actual viewport
953 glGetIntegerv(GL_VIEWPORT, viewp);
954
955 #define BUFFER_SIZE 64
956 // Table for selection buffer data
957 GLuint selectionBuffer[BUFFER_SIZE];
958 // Prepare selection buffer
959 glSelectBuffer(BUFFER_SIZE, selectionBuffer);
960
961 // Change rendering mode
962 glRenderMode(GL_SELECT);
963 // Initializes the Name Stack
964 glInitNames();
965 // Push 0 (at least one entry) Onto the Stack
966 glPushName(NONE);
967 // Set new projection matrix as a box around xPos, yPos
968 glLoadIdentity();
969
970 int hh = glutGet(GLUT_WINDOW_HEIGHT);
971 // Picking matrix at position xCoord, windowSize - yCoord (fliped window Y axis)
972 // and size of 4 units in depth
973 gluPickMatrix(xCoord, hh - yCoord, 1, 1, viewp);
974 //gluPickMatrix(xCoord, hh - yCoord, 1, 1, viewp);
975
976 glOrtho(0.0f, viewp[2], 0.0f, viewp[3], -10.0f, 10.0f); // last 1.0 -1.0 it's enough
977 drawSlider(); // draw only picked parts
978
979 hits = glRenderMode(GL_RENDER);
980
981 // printf("\n\nHITS: %d %d\n", hits, BUFFER_SIZE) ;
982
983 if(hits > 0) {
984 for(int i=3; i < hits*4; i+=4) {
985 // printf("HIT: %d - %u \n", i-3, selectionBuffer[i-3] ) ;
986 // printf("HIT: %d - %u \n", i-2, selectionBuffer[i-2] ) ;
987 // printf("HIT: %d - %u \n", i-1, selectionBuffer[i-1] ) ;
988 // printf("HIT: %d - %u \n", i, selectionBuffer[i-0] ) ;
989 switch(selectionBuffer[i]) {
990 case 1 :hoverState = LEFT_BAR; glutSetCursor(GLUT_CURSOR_LEFT_SIDE); break;
991 case 2 :hoverState = RIGHT_BAR; glutSetCursor(GLUT_CURSOR_RIGHT_SIDE); break;
992 case 3 :hoverState = WHOLE_SLIDER; !pan?glutSetCursor(GLUT_CURSOR_LEFT_RIGHT):(virtualWidth>1?glutSetCursor(GLUT_CURSOR_INFO):glutSetCursor(GLUT_CURSOR_INHERIT));break;
993 case 4 :hoverState = BOTTOM; glutSetCursor(GLUT_CURSOR_BOTTOM_SIDE);break;
994 case 5 :hoverState = BACK; !pan?glutSetCursor(GLUT_CURSOR_LEFT_RIGHT):(virtualWidth>1?glutSetCursor(GLUT_CURSOR_INFO):glutSetCursor(GLUT_CURSOR_BOTTOM_SIDE));break;
995 default:hoverState = NONE; glutSetCursor(GLUT_CURSOR_INHERIT); break;
996 }
997 if(hoverState != NONE)
998 break;
999 }
1000 } else {
1001 hoverState = NONE; //glutSetCursor(GLUT_CURSOR_INHERIT); glutSetCursor(GLUT_CURSOR_CROSSHAIR);
1002 }
1003 redrawEnd();
1004
1005 }
1006
1007
setSubComponentHoverState(SubComponent newState)1008 int M_Histogram::setSubComponentHoverState(SubComponent newState)
1009 {
1010 if(newState == LEFT_BAR || newState == RIGHT_BAR || newState == WHOLE_SLIDER || newState == NONE)
1011 {
1012 hoverState = newState;
1013 return (int)hoverState;
1014 }
1015 else
1016 return -1;
1017 }
1018
1019
setVisible(bool _isVisible)1020 void M_Histogram::setVisible(bool _isVisible) {
1021 isVisible = _isVisible;
1022 if(!getVisible()) setSubComponentHoverState(NONE);
1023 }
1024
1025
getSubComponentHoverState()1026 M_Histogram::SubComponent M_Histogram::getSubComponentHoverState()
1027 {
1028 return hoverState;
1029 }
1030
resetFrequencyMax(void)1031 void M_Histogram::resetFrequencyMax(void) {
1032 frequencyMax = -1;
1033 }
1034
1035
setVirtualWidth(float width)1036 void M_Histogram::setVirtualWidth(float width) {
1037 virtualWidth = width ;
1038 // printf("VW: %f\n",virtualWidth) ;
1039 }
1040
1041
getVirtualWidth()1042 float M_Histogram::getVirtualWidth() {
1043 return virtualWidth ;
1044 }
1045
setVirtualOffset(float offset)1046 void M_Histogram::setVirtualOffset(float offset) {
1047 virtualOffset = offset ;
1048 // printf("VW: %f\n",virtualOffset) ;
1049 }
1050
1051
getVirtualOffset()1052 float M_Histogram::getVirtualOffset() {
1053 return virtualOffset ;
1054 }
1055
1056
1057
getChannelAsInt()1058 int M_Histogram::getChannelAsInt(){
1059
1060
1061 if(strcmp(channel, "XYZ") == 0){
1062 return 0 ;
1063 } else {
1064 switch(channel[0]) {
1065 case 'X':
1066 return 1 ;
1067 case 'Y':
1068 return 2 ;
1069 default:
1070 case 'Z':
1071 return 3 ;
1072 }
1073 }
1074 }
1075
1076
1077
get_is_scale_gaussed() const1078 int M_Histogram::get_is_scale_gaussed() const
1079 {
1080 return is_scale_gaussed;
1081 }
1082
set_is_scale_gaussed(int is_scale_gaussed)1083 void M_Histogram::set_is_scale_gaussed(int is_scale_gaussed)
1084 {
1085 this->is_scale_gaussed = is_scale_gaussed;
1086 }
1087
get_is_scale_show_max_hue() const1088 int M_Histogram::get_is_scale_show_max_hue() const
1089 {
1090 return is_scale_show_max_hue;
1091 }
1092
set_is_scale_show_max_hue(int is_scale_show_max_hue)1093 void M_Histogram::set_is_scale_show_max_hue(int is_scale_show_max_hue)
1094 {
1095 this->is_scale_show_max_hue = is_scale_show_max_hue;
1096 }
1097
1098
setRawData(int x,int y,float X,float Y,float Z)1099 void M_Histogram::setRawData( int x, int y, float X, float Y, float Z) {
1100
1101 rawPosX = x;
1102 rawPosY = y;
1103 rawX = X;
1104 rawY = Y;
1105 rawZ = Z;
1106 }
1107