1
// xImaHist.cpp : histogram functions
2
/* 28/01/2004 v1.00 - www.xdp.it
3
* CxImage version 5.99c 17/Oct/2004
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 (SelectionIsInside(x,y))
34
#endif //CXIMAGE_SUPPORT_SELECTION
38
color = HSLtoRGB(GetPixelColor(x,y));
41
color = YUVtoRGB(GetPixelColor(x,y));
44
color = YIQtoRGB(GetPixelColor(x,y));
47
color = XYZtoRGB(GetPixelColor(x,y));
50
color = GetPixelColor(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
* \return true if everything is ok
76
* \author [dave] and [nipper]
78
bool CxImage::HistogramStretch(long method)
80
if (!pDib) return false;
82
if ((head.biBitCount==8) && IsGrayScale()){
84
BYTE minc = 255, maxc = 0;
88
double dbScaler = 50.0/head.biHeight;
90
for (y=0; y<head.biHeight; y++)
92
info.nProgress = (long)(y*dbScaler);
93
if (info.nEscape) break;
94
for (long x=0; x<head.biWidth; x++) {
95
gray = GetPixelIndex(x, y);
96
if (gray < minc) minc = gray;
97
if (gray > maxc) maxc = gray;
101
if (minc == 0 && maxc == 255) return true;
105
BYTE range = maxc - minc;
107
for (long x = minc; x <= maxc; x++){
108
lut[x] = (BYTE)(255 * (x - minc) / range);
110
} else lut[minc] = minc;
112
for (y=0; y<head.biHeight; y++) {
113
if (info.nEscape) break;
114
info.nProgress = (long)(50.0+y*dbScaler);
115
for (long x=0; x<head.biWidth; x++)
117
SetPixelIndex(x, y, lut[GetPixelIndex(x, y)]);
125
BYTE minc = 255, maxc = 0;
129
for (y=0; y<head.biHeight; y++)
131
if (info.nEscape) break;
133
for (long x=0; x<head.biWidth; x++)
135
color = GetPixelColor(x, y);
137
if (color.rgbRed < minc) minc = color.rgbRed;
138
if (color.rgbBlue < minc) minc = color.rgbBlue;
139
if (color.rgbGreen < minc) minc = color.rgbGreen;
141
if (color.rgbRed > maxc) maxc = color.rgbRed;
142
if (color.rgbBlue > maxc) maxc = color.rgbBlue;
143
if (color.rgbGreen > maxc) maxc = color.rgbGreen;
147
if (minc == 0 && maxc == 255)
152
BYTE range = maxc - minc;
155
for (long x = minc; x <= maxc; x++){
156
lut[x] = (BYTE)(255 * (x - minc) / range);
158
} else lut[minc] = minc;
161
double dbScaler = 100.0/head.biHeight;
163
for (y=0; y<head.biHeight; y++) {
164
if (info.nEscape) break;
165
info.nProgress = (long)(y*dbScaler);
167
for (long x=0; x<head.biWidth; x++)
169
color = GetPixelColor(x, y);
171
color.rgbRed = lut[color.rgbRed];
172
color.rgbBlue = lut[color.rgbBlue];
173
color.rgbGreen = lut[color.rgbGreen];
175
SetPixelColor(x, y, color);
183
BYTE minR = 255, maxR = 0;
184
BYTE minG = 255, maxG = 0;
185
BYTE minB = 255, maxB = 0;
189
for (y=0; y<head.biHeight; y++)
191
if (info.nEscape) break;
193
for (long x=0; x<head.biWidth; x++)
195
color = GetPixelColor(x, y);
197
if (color.rgbRed < minR) minR = color.rgbRed;
198
if (color.rgbBlue < minB) minB = color.rgbBlue;
199
if (color.rgbGreen < minG) minG = color.rgbGreen;
201
if (color.rgbRed > maxR) maxR = color.rgbRed;
202
if (color.rgbBlue > maxB) maxB = color.rgbBlue;
203
if (color.rgbGreen > maxG) maxG = color.rgbGreen;
207
if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)
212
BYTE range = maxR - minR;
214
for (long x = minR; x <= maxR; x++){
215
lutR[x] = (BYTE)(255 * (x - minR) / range);
217
} else lutR[minR] = minR;
222
for (long x = minG; x <= maxG; x++){
223
lutG[x] = (BYTE)(255 * (x - minG) / range);
225
} else lutG[minG] = minG;
230
for (long x = minB; x <= maxB; x++){
231
lutB[x] = (BYTE)(255 * (x - minB) / range);
233
} else lutB[minB] = minB;
236
double dbScaler = 100.0/head.biHeight;
238
for (y=0; y<head.biHeight; y++)
240
info.nProgress = (long)(y*dbScaler);
241
if (info.nEscape) break;
243
for (long x=0; x<head.biWidth; x++)
245
color = GetPixelColor(x, y);
247
color.rgbRed = lutR[color.rgbRed];
248
color.rgbBlue = lutB[color.rgbBlue];
249
color.rgbGreen = lutG[color.rgbGreen];
251
SetPixelColor(x, y, color);
258
// S = ( R - C ) ( B - A / D - C )
260
double blimit = 255.0;
261
double lowerc = 255.0;
269
if ( head.biClrUsed == 0 ){
270
long x, y, xmin, xmax, ymin, ymax;
273
ymax = head.biHeight;
275
for( y = ymin; y < ymax; y++ ){
276
info.nProgress = (long)(50*y/ymax);
277
if (info.nEscape) break;
278
for( x = xmin; x < xmax; x++ ){
279
color = GetPixelColor( x, y );
280
tmpGray = RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
281
if ( tmpGray < lowerc ) lowerc = tmpGray;
282
if ( tmpGray > upperd ) upperd = tmpGray;
285
if (upperd==lowerc) return false;
287
for( y = ymin; y < ymax; y++ ){
288
info.nProgress = (long)(50+50*y/ymax);
289
if (info.nEscape) break;
290
for( x = xmin; x < xmax; x++ ){
292
color = GetPixelColor( x, y );
293
yuvClr = RGBtoYUV(color);
296
tmpGray = (double)yuvClr.rgbRed;
297
stretcheds = (double)(tmpGray - lowerc) * ( (blimit - alimit) / (upperd - lowerc) ); // + alimit;
298
if ( stretcheds < 0.0 ) stretcheds = 0.0;
299
else if ( stretcheds > 255.0 ) stretcheds = 255.0;
300
yuvClr.rgbRed = (BYTE)stretcheds;
302
color = YUVtoRGB(yuvClr);
303
SetPixelColor( x, y, color );
308
for( j = 0; j < head.biClrUsed; j++ ){
309
color = GetPaletteColor( (BYTE)j );
310
tmpGray = RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
311
if ( tmpGray < lowerc ) lowerc = tmpGray;
312
if ( tmpGray > upperd ) upperd = tmpGray;
314
if (upperd==lowerc) return false;
316
for( j = 0; j < head.biClrUsed; j++ ){
318
color = GetPaletteColor( (BYTE)j );
319
yuvClr = RGBtoYUV( color );
322
tmpGray = (double)yuvClr.rgbRed;
323
stretcheds = (double)(tmpGray - lowerc) * ( (blimit - alimit) / (upperd - lowerc) ); // + alimit;
324
if ( stretcheds < 0.0 ) stretcheds = 0.0;
325
else if ( stretcheds > 255.0 ) stretcheds = 255.0;
326
yuvClr.rgbRed = (BYTE)stretcheds;
328
color = YUVtoRGB(yuvClr);
329
SetPaletteColor( (BYTE)j, color );
337
////////////////////////////////////////////////////////////////////////////////
338
// HistogramEqualize function by <dave> : dave(at)posortho(dot)com
339
bool CxImage::HistogramEqualize()
341
if (!pDib) return false;
345
int equalize_map[256];
349
unsigned int YVal, high, low;
351
memset( &histogram, 0, sizeof(int) * 256 );
352
memset( &map, 0, sizeof(int) * 256 );
353
memset( &equalize_map, 0, sizeof(int) * 256 );
356
for(y=0; y < head.biHeight; y++){
357
info.nProgress = (long)(50*y/head.biHeight);
358
if (info.nEscape) break;
359
for(x=0; x < head.biWidth; x++){
360
color = GetPixelColor( x, y );
361
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
366
// integrate the histogram to get the equalization map.
368
for(i=0; i <= 255; i++){
376
if (low == high) return false;
377
for( i = 0; i <= 255; i++ ){
378
equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) );
381
// stretch the histogram
382
if(head.biClrUsed == 0){ // No Palette
383
for( y = 0; y < head.biHeight; y++ ){
384
info.nProgress = (long)(50+50*y/head.biHeight);
385
if (info.nEscape) break;
386
for( x = 0; x < head.biWidth; x++ ){
388
color = GetPixelColor( x, y );
389
yuvClr = RGBtoYUV(color);
391
yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
393
color = YUVtoRGB(yuvClr);
394
SetPixelColor( x, y, color );
398
for( i = 0; i < (int)head.biClrUsed; i++ ){
400
color = GetPaletteColor((BYTE)i);
401
yuvClr = RGBtoYUV(color);
403
yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
405
color = YUVtoRGB(yuvClr);
406
SetPaletteColor( (BYTE)i, color );
411
////////////////////////////////////////////////////////////////////////////////
412
// HistogramNormalize function by <dave> : dave(at)posortho(dot)com
413
bool CxImage::HistogramNormalize()
415
if (!pDib) return false;
418
int threshold_intensity, intense;
420
unsigned int normalize_map[256];
421
unsigned int high, low, YVal;
426
memset( &histogram, 0, sizeof( int ) * 256 );
427
memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );
430
for(y=0; y < head.biHeight; y++){
431
info.nProgress = (long)(50*y/head.biHeight);
432
if (info.nEscape) break;
433
for(x=0; x < head.biWidth; x++){
434
color = GetPixelColor( x, y );
435
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
440
// find histogram boundaries by locating the 1 percent levels
441
threshold_intensity = ( head.biWidth * head.biHeight) / 100;
444
for( low = 0; low < 255; low++ ){
445
intense += histogram[low];
446
if( intense > threshold_intensity ) break;
450
for( high = 255; high != 0; high--){
451
intense += histogram[ high ];
452
if( intense > threshold_intensity ) break;
456
// Unreasonable contrast; use zero threshold to determine boundaries.
457
threshold_intensity = 0;
459
for( low = 0; low < 255; low++){
460
intense += histogram[low];
461
if( intense > threshold_intensity ) break;
464
for( high = 255; high != 0; high-- ){
465
intense += histogram [high ];
466
if( intense > threshold_intensity ) break;
469
if( low == high ) return false; // zero span bound
471
// Stretch the histogram to create the normalized image mapping.
472
for(i = 0; i <= 255; i++){
473
if ( i < (int) low ){
474
normalize_map[i] = 0;
477
normalize_map[i] = 255;
479
normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );
484
if( head.biClrUsed == 0 ){
485
for( y = 0; y < head.biHeight; y++ ){
486
info.nProgress = (long)(50+50*y/head.biHeight);
487
if (info.nEscape) break;
488
for( x = 0; x < head.biWidth; x++ ){
490
color = GetPixelColor( x, y );
491
yuvClr = RGBtoYUV( color );
493
yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
495
color = YUVtoRGB( yuvClr );
496
SetPixelColor( x, y, color );
500
for(i = 0; i < (int)head.biClrUsed; i++){
502
color = GetPaletteColor( (BYTE)i );
503
yuvClr = RGBtoYUV( color );
505
yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
507
color = YUVtoRGB( yuvClr );
508
SetPaletteColor( (BYTE)i, color );
513
////////////////////////////////////////////////////////////////////////////////
514
// HistogramLog function by <dave> : dave(at)posortho(dot)com
515
bool CxImage::HistogramLog()
517
if (!pDib) return false;
519
//q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);
524
unsigned int YVal, high = 1;
526
// Find Highest Luminance Value in the Image
527
if( head.biClrUsed == 0 ){ // No Palette
528
for(y=0; y < head.biHeight; y++){
529
info.nProgress = (long)(50*y/head.biHeight);
530
if (info.nEscape) break;
531
for(x=0; x < head.biWidth; x++){
532
color = GetPixelColor( x, y );
533
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
534
if (YVal > high ) high = YVal;
538
for(i = 0; i < (int)head.biClrUsed; i++){
539
color = GetPaletteColor((BYTE)i);
540
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
541
if (YVal > high ) high = YVal;
545
// Logarithm Operator
546
double k = 255.0 / ::log( 1.0 + (double)high );
547
if( head.biClrUsed == 0 ){
548
for( y = 0; y < head.biHeight; y++ ){
549
info.nProgress = (long)(50+50*y/head.biHeight);
550
if (info.nEscape) break;
551
for( x = 0; x < head.biWidth; x++ ){
553
color = GetPixelColor( x, y );
554
yuvClr = RGBtoYUV( color );
556
yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
558
color = YUVtoRGB( yuvClr );
559
SetPixelColor( x, y, color );
563
for(i = 0; i < (int)head.biClrUsed; i++){
565
color = GetPaletteColor( (BYTE)i );
566
yuvClr = RGBtoYUV( color );
568
yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
570
color = YUVtoRGB( yuvClr );
571
SetPaletteColor( (BYTE)i, color );
578
////////////////////////////////////////////////////////////////////////////////
579
// HistogramRoot function by <dave> : dave(at)posortho(dot)com
580
bool CxImage::HistogramRoot()
582
if (!pDib) return false;
583
//q(i,j) = sqrt(|p(i,j)|);
589
unsigned int YVal, high = 1;
591
// Find Highest Luminance Value in the Image
592
if( head.biClrUsed == 0 ){ // No Palette
593
for(y=0; y < head.biHeight; y++){
594
info.nProgress = (long)(50*y/head.biHeight);
595
if (info.nEscape) break;
596
for(x=0; x < head.biWidth; x++){
597
color = GetPixelColor( x, y );
598
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
599
if (YVal > high ) high = YVal;
603
for(i = 0; i < (int)head.biClrUsed; i++){
604
color = GetPaletteColor((BYTE)i);
605
YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
606
if (YVal > high ) high = YVal;
611
double k = 128.0 / ::log( 1.0 + (double)high );
612
if( head.biClrUsed == 0 ){
613
for( y = 0; y < head.biHeight; y++ ){
614
info.nProgress = (long)(50+50*y/head.biHeight);
615
if (info.nEscape) break;
616
for( x = 0; x < head.biWidth; x++ ){
618
color = GetPixelColor( x, y );
619
yuvClr = RGBtoYUV( color );
621
dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
622
if ( dtmp > 255.0 ) dtmp = 255.0;
623
if ( dtmp < 0 ) dtmp = 0;
624
yuvClr.rgbRed = (BYTE)dtmp;
626
color = YUVtoRGB( yuvClr );
627
SetPixelColor( x, y, color );
631
for(i = 0; i < (int)head.biClrUsed; i++){
633
color = GetPaletteColor( (BYTE)i );
634
yuvClr = RGBtoYUV( color );
636
dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
637
if ( dtmp > 255.0 ) dtmp = 255.0;
638
if ( dtmp < 0 ) dtmp = 0;
639
yuvClr.rgbRed = (BYTE)dtmp;
641
color = YUVtoRGB( yuvClr );
642
SetPaletteColor( (BYTE)i, color );
648
////////////////////////////////////////////////////////////////////////////////