1 // xImaHist.cpp : histogram functions
2 /* 28/01/2004 v1.00 - www.xdp.it
3 * CxImage version 6.0.0 02/Feb/2008
8 #if CXIMAGE_SUPPORT_DSP
10 ////////////////////////////////////////////////////////////////////////////////
11 long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace)
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));
21 long xmin,xmax,ymin,ymax;
23 xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
24 ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
27 xmax = head.biWidth; ymax=head.biHeight;
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
38 color = HSLtoRGB(BlindGetPixelColor(x,y));
41 color = YUVtoRGB(BlindGetPixelColor(x,y));
44 color = YIQtoRGB(BlindGetPixelColor(x,y));
47 color = XYZtoRGB(BlindGetPixelColor(x,y));
50 color = BlindGetPixelColor(x,y);
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)]++;
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];
71 ////////////////////////////////////////////////////////////////////////////////
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]
79 bool CxImage::HistogramStretch(long method, double threshold)
81 if (!pDib) return false;
83 double dbScaler = 50.0/head.biHeight;
86 if ((head.biBitCount==8) && IsGrayScale()){
89 memset(p, 0, 256*sizeof(double));
90 for (y=0; y<head.biHeight; y++)
92 info.nProgress = (long)(y*dbScaler);
93 if (info.nEscape) break;
94 for (x=0; x<head.biWidth; x++) {
95 p[BlindGetPixelIndex(x, y)]++;
100 for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
103 while (minc<255 && p[minc]<=threshold) minc++;
105 while (maxc>0 && p[maxc]<=threshold) maxc--;
107 if (minc == 0 && maxc == 255) return true;
108 if (minc >= maxc) return true;
112 for (x = 0; x <256; x++){
113 lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
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++)
121 BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);
129 memset(p, 0, 256*sizeof(double));
130 for (y=0; y<head.biHeight; y++)
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);
142 for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
145 while (minc<255 && p[minc]<=threshold) minc++;
147 while (maxc>0 && p[maxc]<=threshold) maxc--;
149 if (minc == 0 && maxc == 255) return true;
150 if (minc >= maxc) return true;
154 for (x = 0; x <256; x++){
155 lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
159 for (y=0; y<head.biHeight; y++) {
160 if (info.nEscape) break;
161 info.nProgress = (long)(50.0+y*dbScaler);
163 for (x=0; x<head.biWidth; x++)
165 RGBQUAD color = BlindGetPixelColor(x, y);
167 color.rgbRed = lut[color.rgbRed];
168 color.rgbBlue = lut[color.rgbBlue];
169 color.rgbGreen = lut[color.rgbGreen];
171 BlindSetPixelColor(x, y, color);
179 memset(pR, 0, 256*sizeof(double));
181 memset(pG, 0, 256*sizeof(double));
183 memset(pB, 0, 256*sizeof(double));
184 for (y=0; y<head.biHeight; y++)
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);
192 pG[color.rgbGreen]++;
197 for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];
198 double threshold2 = threshold*maxh;
200 while (minR<255 && pR[minR]<=threshold2) minR++;
202 while (maxR>0 && pR[maxR]<=threshold2) maxR--;
205 for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];
206 threshold2 = threshold*maxh;
208 while (minG<255 && pG[minG]<=threshold2) minG++;
210 while (maxG>0 && pG[maxG]<=threshold2) maxG--;
213 for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];
214 threshold2 = threshold*maxh;
216 while (minB<255 && pB[minB]<=threshold2) minB++;
218 while (maxB>0 && pB[maxB]<=threshold2) maxB--;
220 if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)
225 BYTE range = maxR - minR;
227 for (x = 0; x <256; x++){
228 lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range)));
230 } else lutR[minR] = minR;
235 for (x = 0; x <256; x++){
236 lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range)));
238 } else lutG[minG] = minG;
243 for (x = 0; x <256; x++){
244 lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range)));
246 } else lutB[minB] = minB;
249 for (y=0; y<head.biHeight; y++)
251 info.nProgress = (long)(50.0+y*dbScaler);
252 if (info.nEscape) break;
254 for (x=0; x<head.biWidth; x++)
256 RGBQUAD color = BlindGetPixelColor(x, y);
258 color.rgbRed = lutR[color.rgbRed];
259 color.rgbBlue = lutB[color.rgbBlue];
260 color.rgbGreen = lutG[color.rgbGreen];
262 BlindSetPixelColor(x, y, color);
270 memset(p, 0, 256*sizeof(double));
271 for (y=0; y<head.biHeight; y++)
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)]++;
282 for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
285 while (minc<255 && p[minc]<=threshold) minc++;
287 while (maxc>0 && p[maxc]<=threshold) maxc--;
289 if (minc == 0 && maxc == 255) return true;
290 if (minc >= maxc) return true;
294 for (x = 0; x <256; x++){
295 lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
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++){
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 );
315 ////////////////////////////////////////////////////////////////////////////////
316 // HistogramEqualize function by <dave> : dave(at)posortho(dot)com
317 bool CxImage::HistogramEqualize()
319 if (!pDib) return false;
323 int equalize_map[256];
327 unsigned int YVal, high, low;
329 memset( &histogram, 0, sizeof(int) * 256 );
330 memset( &map, 0, sizeof(int) * 256 );
331 memset( &equalize_map, 0, sizeof(int) * 256 );
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);
344 // integrate the histogram to get the equalization map.
346 for(i=0; i <= 255; i++){
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 ) );
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++ ){
366 color = BlindGetPixelColor( x, y );
367 yuvClr = RGBtoYUV(color);
369 yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
371 color = YUVtoRGB(yuvClr);
372 BlindSetPixelColor( x, y, color );
376 for( i = 0; i < (int)head.biClrUsed; i++ ){
378 color = GetPaletteColor((BYTE)i);
379 yuvClr = RGBtoYUV(color);
381 yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
383 color = YUVtoRGB(yuvClr);
384 SetPaletteColor( (BYTE)i, color );
389 ////////////////////////////////////////////////////////////////////////////////
390 // HistogramNormalize function by <dave> : dave(at)posortho(dot)com
391 bool CxImage::HistogramNormalize()
393 if (!pDib) return false;
396 int threshold_intensity, intense;
398 unsigned int normalize_map[256];
399 unsigned int high, low, YVal;
404 memset( &histogram, 0, sizeof( int ) * 256 );
405 memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );
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);
418 // find histogram boundaries by locating the 1 percent levels
419 threshold_intensity = ( head.biWidth * head.biHeight) / 100;
422 for( low = 0; low < 255; low++ ){
423 intense += histogram[low];
424 if( intense > threshold_intensity ) break;
428 for( high = 255; high != 0; high--){
429 intense += histogram[ high ];
430 if( intense > threshold_intensity ) break;
434 // Unreasonable contrast; use zero threshold to determine boundaries.
435 threshold_intensity = 0;
437 for( low = 0; low < 255; low++){
438 intense += histogram[low];
439 if( intense > threshold_intensity ) break;
442 for( high = 255; high != 0; high-- ){
443 intense += histogram [high ];
444 if( intense > threshold_intensity ) break;
447 if( low == high ) return false; // zero span bound
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;
455 normalize_map[i] = 255;
457 normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );
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++ ){
468 color = BlindGetPixelColor( x, y );
469 yuvClr = RGBtoYUV( color );
471 yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
473 color = YUVtoRGB( yuvClr );
474 BlindSetPixelColor( x, y, color );
478 for(i = 0; i < (int)head.biClrUsed; i++){
480 color = GetPaletteColor( (BYTE)i );
481 yuvClr = RGBtoYUV( color );
483 yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
485 color = YUVtoRGB( yuvClr );
486 SetPaletteColor( (BYTE)i, color );
491 ////////////////////////////////////////////////////////////////////////////////
492 // HistogramLog function by <dave> : dave(at)posortho(dot)com
493 bool CxImage::HistogramLog()
495 if (!pDib) return false;
497 //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);
502 unsigned int YVal, high = 1;
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;
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;
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++ ){
531 color = BlindGetPixelColor( x, y );
532 yuvClr = RGBtoYUV( color );
534 yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
536 color = YUVtoRGB( yuvClr );
537 BlindSetPixelColor( x, y, color );
541 for(i = 0; i < (int)head.biClrUsed; i++){
543 color = GetPaletteColor( (BYTE)i );
544 yuvClr = RGBtoYUV( color );
546 yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
548 color = YUVtoRGB( yuvClr );
549 SetPaletteColor( (BYTE)i, color );
556 ////////////////////////////////////////////////////////////////////////////////
557 // HistogramRoot function by <dave> : dave(at)posortho(dot)com
558 bool CxImage::HistogramRoot()
560 if (!pDib) return false;
561 //q(i,j) = sqrt(|p(i,j)|);
567 unsigned int YVal, high = 1;
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;
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;
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++ ){
596 color = BlindGetPixelColor( x, y );
597 yuvClr = RGBtoYUV( color );
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;
604 color = YUVtoRGB( yuvClr );
605 BlindSetPixelColor( x, y, color );
609 for(i = 0; i < (int)head.biClrUsed; i++){
611 color = GetPaletteColor( (BYTE)i );
612 yuvClr = RGBtoYUV( color );
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;
619 color = YUVtoRGB( yuvClr );
620 SetPaletteColor( (BYTE)i, color );
626 ////////////////////////////////////////////////////////////////////////////////