]> Creatis software - clitk.git/blob - utilities/CxImage/ximahist.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximahist.cpp
1 // xImaHist.cpp : histogram functions
2 /* 28/01/2004 v1.00 - www.xdp.it
3  * CxImage version 6.0.0 02/Feb/2008
4  */
5
6 #include "ximage.h"
7
8 #if CXIMAGE_SUPPORT_DSP
9
10 ////////////////////////////////////////////////////////////////////////////////
11 long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace)
12 {
13         if (!pDib) return 0;
14         RGBQUAD color;
15
16         if (red) memset(red,0,256*sizeof(long));
17         if (green) memset(green,0,256*sizeof(long));
18         if (blue) memset(blue,0,256*sizeof(long));
19         if (gray) memset(gray,0,256*sizeof(long));
20
21         long xmin,xmax,ymin,ymax;
22         if (pSelection){
23                 xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
24                 ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
25         } else {
26                 xmin = ymin = 0;
27                 xmax = head.biWidth; ymax=head.biHeight;
28         }
29
30         for(long y=ymin; y<ymax; y++){
31                 for(long x=xmin; x<xmax; x++){
32 #if CXIMAGE_SUPPORT_SELECTION
33                         if (BlindSelectionIsInside(x,y))
34 #endif //CXIMAGE_SUPPORT_SELECTION
35                         {
36                                 switch (colorspace){
37                                 case 1:
38                                         color = HSLtoRGB(BlindGetPixelColor(x,y));
39                                         break;
40                                 case 2:
41                                         color = YUVtoRGB(BlindGetPixelColor(x,y));
42                                         break;
43                                 case 3:
44                                         color = YIQtoRGB(BlindGetPixelColor(x,y));
45                                         break;
46                                 case 4:
47                                         color = XYZtoRGB(BlindGetPixelColor(x,y));
48                                         break;
49                                 default:
50                                         color = BlindGetPixelColor(x,y);
51                                 }
52
53                                 if (red) red[color.rgbRed]++;
54                                 if (green) green[color.rgbGreen]++;
55                                 if (blue) blue[color.rgbBlue]++;
56                                 if (gray) gray[(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++;
57                         }
58                 }
59         }
60
61         long n=0;
62         for (int i=0; i<256; i++){
63                 if (red && red[i]>n) n=red[i];
64                 if (green && green[i]>n) n=green[i];
65                 if (blue && blue[i]>n) n=blue[i];
66                 if (gray && gray[i]>n) n=gray[i];
67         }
68
69         return n;
70 }
71 ////////////////////////////////////////////////////////////////////////////////
72 /**
73  * HistogramStretch
74  * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels.
75  * \param threshold: minimum percentage level in the histogram to recognize it as meaningful. Range: 0.0 to 1.0; default = 0; typical = 0.005 (0.5%);
76  * \return true if everything is ok
77  * \author [dave] and [nipper]; changes [DP]
78  */
79 bool CxImage::HistogramStretch(long method, double threshold)
80 {
81         if (!pDib) return false;
82
83         double dbScaler = 50.0/head.biHeight;
84         long x,y;
85
86   if ((head.biBitCount==8) && IsGrayScale()){
87
88         double p[256];
89         memset(p,  0, 256*sizeof(double));
90         for (y=0; y<head.biHeight; y++)
91         {
92                 info.nProgress = (long)(y*dbScaler);
93                 if (info.nEscape) break;
94                 for (x=0; x<head.biWidth; x++)  {
95                         p[BlindGetPixelIndex(x, y)]++;
96                 }
97         }
98
99         double maxh = 0;
100         for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
101         threshold *= maxh;
102         int minc = 0;
103         while (minc<255 && p[minc]<=threshold) minc++;
104         int maxc = 255;
105         while (maxc>0 && p[maxc]<=threshold) maxc--;
106
107         if (minc == 0 && maxc == 255) return true;
108         if (minc >= maxc) return true;
109
110         // calculate LUT
111         BYTE lut[256];
112         for (x = 0; x <256; x++){
113                 lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
114         }
115
116         for (y=0; y<head.biHeight; y++) {
117                 if (info.nEscape) break;
118                 info.nProgress = (long)(50.0+y*dbScaler);
119                 for (x=0; x<head.biWidth; x++)
120                 {
121                         BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);
122                 }
123         }
124   } else {
125         switch(method){
126         case 1:
127           { // <nipper>
128                 double p[256];
129                 memset(p,  0, 256*sizeof(double));
130                 for (y=0; y<head.biHeight; y++)
131                 {
132                         info.nProgress = (long)(y*dbScaler);
133                         if (info.nEscape) break;
134                         for (x=0; x<head.biWidth; x++)  {
135                                 RGBQUAD color = BlindGetPixelColor(x, y);
136                                 p[color.rgbRed]++;
137                                 p[color.rgbBlue]++;
138                                 p[color.rgbGreen]++;
139                         }
140                 }
141                 double maxh = 0;
142                 for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
143                 threshold *= maxh;
144                 int minc = 0;
145                 while (minc<255 && p[minc]<=threshold) minc++;
146                 int maxc = 255;
147                 while (maxc>0 && p[maxc]<=threshold) maxc--;
148
149                 if (minc == 0 && maxc == 255) return true;
150                 if (minc >= maxc) return true;
151
152                 // calculate LUT
153                 BYTE lut[256];
154                 for (x = 0; x <256; x++){
155                         lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
156                 }
157
158                 // normalize image
159                 for (y=0; y<head.biHeight; y++) {
160                         if (info.nEscape) break;
161                         info.nProgress = (long)(50.0+y*dbScaler);
162
163                         for (x=0; x<head.biWidth; x++)
164                         {
165                                 RGBQUAD color = BlindGetPixelColor(x, y);
166
167                                 color.rgbRed = lut[color.rgbRed];
168                                 color.rgbBlue = lut[color.rgbBlue];
169                                 color.rgbGreen = lut[color.rgbGreen];
170
171                                 BlindSetPixelColor(x, y, color);
172                         }
173                 }
174           }
175                 break;
176         case 2:
177           { // <nipper>
178                 double pR[256];
179                 memset(pR,  0, 256*sizeof(double));
180                 double pG[256];
181                 memset(pG,  0, 256*sizeof(double));
182                 double pB[256];
183                 memset(pB,  0, 256*sizeof(double));
184                 for (y=0; y<head.biHeight; y++)
185                 {
186                         info.nProgress = (long)(y*dbScaler);
187                         if (info.nEscape) break;
188                         for (long x=0; x<head.biWidth; x++)     {
189                                 RGBQUAD color = BlindGetPixelColor(x, y);
190                                 pR[color.rgbRed]++;
191                                 pB[color.rgbBlue]++;
192                                 pG[color.rgbGreen]++;
193                         }
194                 }
195
196                 double maxh = 0;
197                 for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];
198                 double threshold2 = threshold*maxh;
199                 int minR = 0;
200                 while (minR<255 && pR[minR]<=threshold2) minR++;
201                 int maxR = 255;
202                 while (maxR>0 && pR[maxR]<=threshold2) maxR--;
203
204                 maxh = 0;
205                 for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];
206                 threshold2 = threshold*maxh;
207                 int minG = 0;
208                 while (minG<255 && pG[minG]<=threshold2) minG++;
209                 int maxG = 255;
210                 while (maxG>0 && pG[maxG]<=threshold2) maxG--;
211
212                 maxh = 0;
213                 for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];
214                 threshold2 = threshold*maxh;
215                 int minB = 0;
216                 while (minB<255 && pB[minB]<=threshold2) minB++;
217                 int maxB = 255;
218                 while (maxB>0 && pB[maxB]<=threshold2) maxB--;
219
220                 if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)
221                         return true;
222
223                 // calculate LUT
224                 BYTE lutR[256];
225                 BYTE range = maxR - minR;
226                 if (range != 0) {
227                         for (x = 0; x <256; x++){
228                                 lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range)));
229                         }
230                 } else lutR[minR] = minR;
231
232                 BYTE lutG[256];
233                 range = maxG - minG;
234                 if (range != 0) {
235                         for (x = 0; x <256; x++){
236                                 lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range)));
237                         }
238                 } else lutG[minG] = minG;
239                         
240                 BYTE lutB[256];
241                 range = maxB - minB;
242                 if (range != 0) {
243                         for (x = 0; x <256; x++){
244                                 lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range)));
245                         }
246                 } else lutB[minB] = minB;
247
248                 // normalize image
249                 for (y=0; y<head.biHeight; y++)
250                 {
251                         info.nProgress = (long)(50.0+y*dbScaler);
252                         if (info.nEscape) break;
253
254                         for (x=0; x<head.biWidth; x++)
255                         {
256                                 RGBQUAD color = BlindGetPixelColor(x, y);
257
258                                 color.rgbRed = lutR[color.rgbRed];
259                                 color.rgbBlue = lutB[color.rgbBlue];
260                                 color.rgbGreen = lutG[color.rgbGreen];
261
262                                 BlindSetPixelColor(x, y, color);
263                         }
264                 }
265           }
266                 break;
267         default:
268           { // <dave>
269                 double p[256];
270                 memset(p,  0, 256*sizeof(double));
271                 for (y=0; y<head.biHeight; y++)
272                 {
273                         info.nProgress = (long)(y*dbScaler);
274                         if (info.nEscape) break;
275                         for (x=0; x<head.biWidth; x++)  {
276                                 RGBQUAD color = BlindGetPixelColor(x, y);
277                                 p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++;
278                         }
279                 }
280
281                 double maxh = 0;
282                 for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
283                 threshold *= maxh;
284                 int minc = 0;
285                 while (minc<255 && p[minc]<=threshold) minc++;
286                 int maxc = 255;
287                 while (maxc>0 && p[maxc]<=threshold) maxc--;
288
289                 if (minc == 0 && maxc == 255) return true;
290                 if (minc >= maxc) return true;
291
292                 // calculate LUT
293                 BYTE lut[256];
294                 for (x = 0; x <256; x++){
295                         lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
296                 }
297
298                 for(y=0; y<head.biHeight; y++){
299                         info.nProgress = (long)(50.0+y*dbScaler);
300                         if (info.nEscape) break;
301                         for(x=0; x<head.biWidth; x++){
302
303                                 RGBQUAD color = BlindGetPixelColor( x, y );
304                                 RGBQUAD yuvClr = RGBtoYUV(color);
305                                 yuvClr.rgbRed = lut[yuvClr.rgbRed];
306                                 color = YUVtoRGB(yuvClr);
307                                 BlindSetPixelColor( x, y, color );
308                         }
309                 }
310           }
311         }
312   }
313   return true;
314 }
315 ////////////////////////////////////////////////////////////////////////////////
316 // HistogramEqualize function by <dave> : dave(at)posortho(dot)com
317 bool CxImage::HistogramEqualize()
318 {
319         if (!pDib) return false;
320
321     int histogram[256];
322         int map[256];
323         int equalize_map[256];
324     int x, y, i, j;
325         RGBQUAD color;
326         RGBQUAD yuvClr;
327         unsigned int YVal, high, low;
328
329         memset( &histogram, 0, sizeof(int) * 256 );
330         memset( &map, 0, sizeof(int) * 256 );
331         memset( &equalize_map, 0, sizeof(int) * 256 );
332  
333      // form histogram
334         for(y=0; y < head.biHeight; y++){
335                 info.nProgress = (long)(50*y/head.biHeight);
336                 if (info.nEscape) break;
337                 for(x=0; x < head.biWidth; x++){
338                         color = BlindGetPixelColor( x, y );
339                         YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
340                         histogram[YVal]++;
341                 }
342         }
343
344         // integrate the histogram to get the equalization map.
345         j = 0;
346         for(i=0; i <= 255; i++){
347                 j += histogram[i];
348                 map[i] = j; 
349         }
350
351         // equalize
352         low = map[0];
353         high = map[255];
354         if (low == high) return false;
355         for( i = 0; i <= 255; i++ ){
356                 equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) );
357         }
358
359         // stretch the histogram
360         if(head.biClrUsed == 0){ // No Palette
361                 for( y = 0; y < head.biHeight; y++ ){
362                         info.nProgress = (long)(50+50*y/head.biHeight);
363                         if (info.nEscape) break;
364                         for( x = 0; x < head.biWidth; x++ ){
365
366                                 color = BlindGetPixelColor( x, y );
367                                 yuvClr = RGBtoYUV(color);
368
369                 yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
370
371                                 color = YUVtoRGB(yuvClr);
372                                 BlindSetPixelColor( x, y, color );
373                         }
374                 }
375         } else { // Palette
376                 for( i = 0; i < (int)head.biClrUsed; i++ ){
377
378                         color = GetPaletteColor((BYTE)i);
379                         yuvClr = RGBtoYUV(color);
380
381             yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
382
383                         color = YUVtoRGB(yuvClr);
384                         SetPaletteColor( (BYTE)i, color );
385                 }
386         }
387         return true;
388 }
389 ////////////////////////////////////////////////////////////////////////////////
390 // HistogramNormalize function by <dave> : dave(at)posortho(dot)com
391 bool CxImage::HistogramNormalize()
392 {
393         if (!pDib) return false;
394
395         int histogram[256];
396         int threshold_intensity, intense;
397         int x, y, i;
398         unsigned int normalize_map[256];
399         unsigned int high, low, YVal;
400
401         RGBQUAD color;
402         RGBQUAD yuvClr;
403
404         memset( &histogram, 0, sizeof( int ) * 256 );
405         memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );
406  
407      // form histogram
408         for(y=0; y < head.biHeight; y++){
409                 info.nProgress = (long)(50*y/head.biHeight);
410                 if (info.nEscape) break;
411                 for(x=0; x < head.biWidth; x++){
412                         color = BlindGetPixelColor( x, y );
413                         YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
414                         histogram[YVal]++;
415                 }
416         }
417
418         // find histogram boundaries by locating the 1 percent levels
419         threshold_intensity = ( head.biWidth * head.biHeight) / 100;
420
421         intense = 0;
422         for( low = 0; low < 255; low++ ){
423                 intense += histogram[low];
424                 if( intense > threshold_intensity )     break;
425         }
426
427         intense = 0;
428         for( high = 255; high != 0; high--){
429                 intense += histogram[ high ];
430                 if( intense > threshold_intensity ) break;
431         }
432
433         if ( low == high ){
434                 // Unreasonable contrast;  use zero threshold to determine boundaries.
435                 threshold_intensity = 0;
436                 intense = 0;
437                 for( low = 0; low < 255; low++){
438                         intense += histogram[low];
439                         if( intense > threshold_intensity )     break;
440                 }
441                 intense = 0;
442                 for( high = 255; high != 0; high-- ){
443                         intense += histogram [high ];
444                         if( intense > threshold_intensity )     break;
445                 }
446         }
447         if( low == high ) return false;  // zero span bound
448
449         // Stretch the histogram to create the normalized image mapping.
450         for(i = 0; i <= 255; i++){
451                 if ( i < (int) low ){
452                         normalize_map[i] = 0;
453                 } else {
454                         if(i > (int) high)
455                                 normalize_map[i] = 255;
456                         else
457                                 normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );
458                 }
459         }
460
461         // Normalize
462         if( head.biClrUsed == 0 ){
463                 for( y = 0; y < head.biHeight; y++ ){
464                         info.nProgress = (long)(50+50*y/head.biHeight);
465                         if (info.nEscape) break;
466                         for( x = 0; x < head.biWidth; x++ ){
467
468                                 color = BlindGetPixelColor( x, y );
469                                 yuvClr = RGBtoYUV( color );
470
471                 yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
472
473                                 color = YUVtoRGB( yuvClr );
474                                 BlindSetPixelColor( x, y, color );
475                         }
476                 }
477         } else {
478                 for(i = 0; i < (int)head.biClrUsed; i++){
479
480                         color = GetPaletteColor( (BYTE)i );
481                         yuvClr = RGBtoYUV( color );
482
483             yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
484
485                         color = YUVtoRGB( yuvClr );
486                         SetPaletteColor( (BYTE)i, color );
487                 }
488         }
489         return true;
490 }
491 ////////////////////////////////////////////////////////////////////////////////
492 // HistogramLog function by <dave> : dave(at)posortho(dot)com
493 bool CxImage::HistogramLog()
494 {
495         if (!pDib) return false;
496
497         //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);
498     int x, y, i;
499         RGBQUAD color;
500         RGBQUAD yuvClr;
501
502         unsigned int YVal, high = 1;
503
504     // Find Highest Luminance Value in the Image
505         if( head.biClrUsed == 0 ){ // No Palette
506                 for(y=0; y < head.biHeight; y++){
507                         info.nProgress = (long)(50*y/head.biHeight);
508                         if (info.nEscape) break;
509                         for(x=0; x < head.biWidth; x++){
510                                 color = BlindGetPixelColor( x, y );
511                                 YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
512                                 if (YVal > high ) high = YVal;
513                         }
514                 }
515         } else { // Palette
516                 for(i = 0; i < (int)head.biClrUsed; i++){
517                         color = GetPaletteColor((BYTE)i);
518                         YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
519                         if (YVal > high ) high = YVal;
520                 }
521         }
522
523         // Logarithm Operator
524         double k = 255.0 / ::log( 1.0 + (double)high );
525         if( head.biClrUsed == 0 ){
526                 for( y = 0; y < head.biHeight; y++ ){
527                         info.nProgress = (long)(50+50*y/head.biHeight);
528                         if (info.nEscape) break;
529                         for( x = 0; x < head.biWidth; x++ ){
530
531                                 color = BlindGetPixelColor( x, y );
532                                 yuvClr = RGBtoYUV( color );
533                 
534                                 yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
535
536                                 color = YUVtoRGB( yuvClr );
537                                 BlindSetPixelColor( x, y, color );
538                         }
539                 }
540         } else {
541                 for(i = 0; i < (int)head.biClrUsed; i++){
542
543                         color = GetPaletteColor( (BYTE)i );
544                         yuvClr = RGBtoYUV( color );
545
546             yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
547                         
548                         color = YUVtoRGB( yuvClr );
549                         SetPaletteColor( (BYTE)i, color );
550                 }
551         }
552  
553         return true;
554 }
555
556 ////////////////////////////////////////////////////////////////////////////////
557 // HistogramRoot function by <dave> : dave(at)posortho(dot)com
558 bool CxImage::HistogramRoot()
559 {
560         if (!pDib) return false;
561         //q(i,j) = sqrt(|p(i,j)|);
562
563     int x, y, i;
564         RGBQUAD color;
565         RGBQUAD  yuvClr;
566         double  dtmp;
567         unsigned int YVal, high = 1;
568
569      // Find Highest Luminance Value in the Image
570         if( head.biClrUsed == 0 ){ // No Palette
571                 for(y=0; y < head.biHeight; y++){
572                         info.nProgress = (long)(50*y/head.biHeight);
573                         if (info.nEscape) break;
574                         for(x=0; x < head.biWidth; x++){
575                                 color = BlindGetPixelColor( x, y );
576                                 YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
577                                 if (YVal > high ) high = YVal;
578                         }
579                 }
580         } else { // Palette
581                 for(i = 0; i < (int)head.biClrUsed; i++){
582                         color = GetPaletteColor((BYTE)i);
583                         YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
584                         if (YVal > high ) high = YVal;
585                 }
586         }
587
588         // Root Operator
589         double k = 128.0 / ::log( 1.0 + (double)high );
590         if( head.biClrUsed == 0 ){
591                 for( y = 0; y < head.biHeight; y++ ){
592                         info.nProgress = (long)(50+50*y/head.biHeight);
593                         if (info.nEscape) break;
594                         for( x = 0; x < head.biWidth; x++ ){
595
596                                 color = BlindGetPixelColor( x, y );
597                                 yuvClr = RGBtoYUV( color );
598
599                                 dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
600                                 if ( dtmp > 255.0 )     dtmp = 255.0;
601                                 if ( dtmp < 0 ) dtmp = 0;
602                 yuvClr.rgbRed = (BYTE)dtmp;
603
604                                 color = YUVtoRGB( yuvClr );
605                                 BlindSetPixelColor( x, y, color );
606                         }
607                 }
608         } else {
609                 for(i = 0; i < (int)head.biClrUsed; i++){
610
611                         color = GetPaletteColor( (BYTE)i );
612                         yuvClr = RGBtoYUV( color );
613
614                         dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
615                         if ( dtmp > 255.0 )     dtmp = 255.0;
616                         if ( dtmp < 0 ) dtmp = 0;
617             yuvClr.rgbRed = (BYTE)dtmp;
618
619                         color = YUVtoRGB( yuvClr );
620                         SetPaletteColor( (BYTE)i, color );
621                 }
622         }
623  
624         return true;
625 }
626 ////////////////////////////////////////////////////////////////////////////////
627 #endif