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