-// xImaHist.cpp : histogram functions\r
-/* 28/01/2004 v1.00 - www.xdp.it\r
- * CxImage version 6.0.0 02/Feb/2008\r
- */\r
-\r
-#include "ximage.h"\r
-\r
-#if CXIMAGE_SUPPORT_DSP\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace)\r
-{\r
- if (!pDib) return 0;\r
- RGBQUAD color;\r
-\r
- if (red) memset(red,0,256*sizeof(long));\r
- if (green) memset(green,0,256*sizeof(long));\r
- if (blue) memset(blue,0,256*sizeof(long));\r
- if (gray) memset(gray,0,256*sizeof(long));\r
-\r
- long xmin,xmax,ymin,ymax;\r
- if (pSelection){\r
- xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;\r
- ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;\r
- } else {\r
- xmin = ymin = 0;\r
- xmax = head.biWidth; ymax=head.biHeight;\r
- }\r
-\r
- for(long y=ymin; y<ymax; y++){\r
- for(long x=xmin; x<xmax; x++){\r
-#if CXIMAGE_SUPPORT_SELECTION\r
- if (BlindSelectionIsInside(x,y))\r
-#endif //CXIMAGE_SUPPORT_SELECTION\r
- {\r
- switch (colorspace){\r
- case 1:\r
- color = HSLtoRGB(BlindGetPixelColor(x,y));\r
- break;\r
- case 2:\r
- color = YUVtoRGB(BlindGetPixelColor(x,y));\r
- break;\r
- case 3:\r
- color = YIQtoRGB(BlindGetPixelColor(x,y));\r
- break;\r
- case 4:\r
- color = XYZtoRGB(BlindGetPixelColor(x,y));\r
- break;\r
- default:\r
- color = BlindGetPixelColor(x,y);\r
- }\r
-\r
- if (red) red[color.rgbRed]++;\r
- if (green) green[color.rgbGreen]++;\r
- if (blue) blue[color.rgbBlue]++;\r
- if (gray) gray[(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++;\r
- }\r
- }\r
- }\r
-\r
- long n=0;\r
- for (int i=0; i<256; i++){\r
- if (red && red[i]>n) n=red[i];\r
- if (green && green[i]>n) n=green[i];\r
- if (blue && blue[i]>n) n=blue[i];\r
- if (gray && gray[i]>n) n=gray[i];\r
- }\r
-\r
- return n;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-/**\r
- * HistogramStretch\r
- * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels.\r
- * \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%);\r
- * \return true if everything is ok\r
- * \author [dave] and [nipper]; changes [DP]\r
- */\r
-bool CxImage::HistogramStretch(long method, double threshold)\r
-{\r
- if (!pDib) return false;\r
-\r
- double dbScaler = 50.0/head.biHeight;\r
- long x,y;\r
-\r
- if ((head.biBitCount==8) && IsGrayScale()){\r
-\r
- double p[256];\r
- memset(p, 0, 256*sizeof(double));\r
- for (y=0; y<head.biHeight; y++)\r
- {\r
- info.nProgress = (long)(y*dbScaler);\r
- if (info.nEscape) break;\r
- for (x=0; x<head.biWidth; x++) {\r
- p[BlindGetPixelIndex(x, y)]++;\r
- }\r
- }\r
-\r
- double maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
- threshold *= maxh;\r
- int minc = 0;\r
- while (minc<255 && p[minc]<=threshold) minc++;\r
- int maxc = 255;\r
- while (maxc>0 && p[maxc]<=threshold) maxc--;\r
-\r
- if (minc == 0 && maxc == 255) return true;\r
- if (minc >= maxc) return true;\r
-\r
- // calculate LUT\r
- BYTE lut[256];\r
- for (x = 0; x <256; x++){\r
- lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
- }\r
-\r
- for (y=0; y<head.biHeight; y++) {\r
- if (info.nEscape) break;\r
- info.nProgress = (long)(50.0+y*dbScaler);\r
- for (x=0; x<head.biWidth; x++)\r
- {\r
- BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);\r
- }\r
- }\r
- } else {\r
- switch(method){\r
- case 1:\r
- { // <nipper>\r
- double p[256];\r
- memset(p, 0, 256*sizeof(double));\r
- for (y=0; y<head.biHeight; y++)\r
- {\r
- info.nProgress = (long)(y*dbScaler);\r
- if (info.nEscape) break;\r
- for (x=0; x<head.biWidth; x++) {\r
- RGBQUAD color = BlindGetPixelColor(x, y);\r
- p[color.rgbRed]++;\r
- p[color.rgbBlue]++;\r
- p[color.rgbGreen]++;\r
- }\r
- }\r
- double maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
- threshold *= maxh;\r
- int minc = 0;\r
- while (minc<255 && p[minc]<=threshold) minc++;\r
- int maxc = 255;\r
- while (maxc>0 && p[maxc]<=threshold) maxc--;\r
-\r
- if (minc == 0 && maxc == 255) return true;\r
- if (minc >= maxc) return true;\r
-\r
- // calculate LUT\r
- BYTE lut[256];\r
- for (x = 0; x <256; x++){\r
- lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
- }\r
-\r
- // normalize image\r
- for (y=0; y<head.biHeight; y++) {\r
- if (info.nEscape) break;\r
- info.nProgress = (long)(50.0+y*dbScaler);\r
-\r
- for (x=0; x<head.biWidth; x++)\r
- {\r
- RGBQUAD color = BlindGetPixelColor(x, y);\r
-\r
- color.rgbRed = lut[color.rgbRed];\r
- color.rgbBlue = lut[color.rgbBlue];\r
- color.rgbGreen = lut[color.rgbGreen];\r
-\r
- BlindSetPixelColor(x, y, color);\r
- }\r
- }\r
- }\r
- break;\r
- case 2:\r
- { // <nipper>\r
- double pR[256];\r
- memset(pR, 0, 256*sizeof(double));\r
- double pG[256];\r
- memset(pG, 0, 256*sizeof(double));\r
- double pB[256];\r
- memset(pB, 0, 256*sizeof(double));\r
- for (y=0; y<head.biHeight; y++)\r
- {\r
- info.nProgress = (long)(y*dbScaler);\r
- if (info.nEscape) break;\r
- for (long x=0; x<head.biWidth; x++) {\r
- RGBQUAD color = BlindGetPixelColor(x, y);\r
- pR[color.rgbRed]++;\r
- pB[color.rgbBlue]++;\r
- pG[color.rgbGreen]++;\r
- }\r
- }\r
-\r
- double maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];\r
- double threshold2 = threshold*maxh;\r
- int minR = 0;\r
- while (minR<255 && pR[minR]<=threshold2) minR++;\r
- int maxR = 255;\r
- while (maxR>0 && pR[maxR]<=threshold2) maxR--;\r
-\r
- maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];\r
- threshold2 = threshold*maxh;\r
- int minG = 0;\r
- while (minG<255 && pG[minG]<=threshold2) minG++;\r
- int maxG = 255;\r
- while (maxG>0 && pG[maxG]<=threshold2) maxG--;\r
-\r
- maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];\r
- threshold2 = threshold*maxh;\r
- int minB = 0;\r
- while (minB<255 && pB[minB]<=threshold2) minB++;\r
- int maxB = 255;\r
- while (maxB>0 && pB[maxB]<=threshold2) maxB--;\r
-\r
- if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)\r
- return true;\r
-\r
- // calculate LUT\r
- BYTE lutR[256];\r
- BYTE range = maxR - minR;\r
- if (range != 0) {\r
- for (x = 0; x <256; x++){\r
- lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range)));\r
- }\r
- } else lutR[minR] = minR;\r
-\r
- BYTE lutG[256];\r
- range = maxG - minG;\r
- if (range != 0) {\r
- for (x = 0; x <256; x++){\r
- lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range)));\r
- }\r
- } else lutG[minG] = minG;\r
- \r
- BYTE lutB[256];\r
- range = maxB - minB;\r
- if (range != 0) {\r
- for (x = 0; x <256; x++){\r
- lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range)));\r
- }\r
- } else lutB[minB] = minB;\r
-\r
- // normalize image\r
- for (y=0; y<head.biHeight; y++)\r
- {\r
- info.nProgress = (long)(50.0+y*dbScaler);\r
- if (info.nEscape) break;\r
-\r
- for (x=0; x<head.biWidth; x++)\r
- {\r
- RGBQUAD color = BlindGetPixelColor(x, y);\r
-\r
- color.rgbRed = lutR[color.rgbRed];\r
- color.rgbBlue = lutB[color.rgbBlue];\r
- color.rgbGreen = lutG[color.rgbGreen];\r
-\r
- BlindSetPixelColor(x, y, color);\r
- }\r
- }\r
- }\r
- break;\r
- default:\r
- { // <dave>\r
- double p[256];\r
- memset(p, 0, 256*sizeof(double));\r
- for (y=0; y<head.biHeight; y++)\r
- {\r
- info.nProgress = (long)(y*dbScaler);\r
- if (info.nEscape) break;\r
- for (x=0; x<head.biWidth; x++) {\r
- RGBQUAD color = BlindGetPixelColor(x, y);\r
- p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++;\r
- }\r
- }\r
-\r
- double maxh = 0;\r
- for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];\r
- threshold *= maxh;\r
- int minc = 0;\r
- while (minc<255 && p[minc]<=threshold) minc++;\r
- int maxc = 255;\r
- while (maxc>0 && p[maxc]<=threshold) maxc--;\r
-\r
- if (minc == 0 && maxc == 255) return true;\r
- if (minc >= maxc) return true;\r
-\r
- // calculate LUT\r
- BYTE lut[256];\r
- for (x = 0; x <256; x++){\r
- lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));\r
- }\r
-\r
- for(y=0; y<head.biHeight; y++){\r
- info.nProgress = (long)(50.0+y*dbScaler);\r
- if (info.nEscape) break;\r
- for(x=0; x<head.biWidth; x++){\r
-\r
- RGBQUAD color = BlindGetPixelColor( x, y );\r
- RGBQUAD yuvClr = RGBtoYUV(color);\r
- yuvClr.rgbRed = lut[yuvClr.rgbRed];\r
- color = YUVtoRGB(yuvClr);\r
- BlindSetPixelColor( x, y, color );\r
- }\r
- }\r
- }\r
- }\r
- }\r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-// HistogramEqualize function by <dave> : dave(at)posortho(dot)com\r
-bool CxImage::HistogramEqualize()\r
-{\r
- if (!pDib) return false;\r
-\r
- int histogram[256];\r
- int map[256];\r
- int equalize_map[256];\r
- int x, y, i, j;\r
- RGBQUAD color;\r
- RGBQUAD yuvClr;\r
- unsigned int YVal, high, low;\r
-\r
- memset( &histogram, 0, sizeof(int) * 256 );\r
- memset( &map, 0, sizeof(int) * 256 );\r
- memset( &equalize_map, 0, sizeof(int) * 256 );\r
- \r
- // form histogram\r
- for(y=0; y < head.biHeight; y++){\r
- info.nProgress = (long)(50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for(x=0; x < head.biWidth; x++){\r
- color = BlindGetPixelColor( x, y );\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- histogram[YVal]++;\r
- }\r
- }\r
-\r
- // integrate the histogram to get the equalization map.\r
- j = 0;\r
- for(i=0; i <= 255; i++){\r
- j += histogram[i];\r
- map[i] = j; \r
- }\r
-\r
- // equalize\r
- low = map[0];\r
- high = map[255];\r
- if (low == high) return false;\r
- for( i = 0; i <= 255; i++ ){\r
- equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) );\r
- }\r
-\r
- // stretch the histogram\r
- if(head.biClrUsed == 0){ // No Palette\r
- for( y = 0; y < head.biHeight; y++ ){\r
- info.nProgress = (long)(50+50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for( x = 0; x < head.biWidth; x++ ){\r
-\r
- color = BlindGetPixelColor( x, y );\r
- yuvClr = RGBtoYUV(color);\r
-\r
- yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];\r
-\r
- color = YUVtoRGB(yuvClr);\r
- BlindSetPixelColor( x, y, color );\r
- }\r
- }\r
- } else { // Palette\r
- for( i = 0; i < (int)head.biClrUsed; i++ ){\r
-\r
- color = GetPaletteColor((BYTE)i);\r
- yuvClr = RGBtoYUV(color);\r
-\r
- yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];\r
-\r
- color = YUVtoRGB(yuvClr);\r
- SetPaletteColor( (BYTE)i, color );\r
- }\r
- }\r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-// HistogramNormalize function by <dave> : dave(at)posortho(dot)com\r
-bool CxImage::HistogramNormalize()\r
-{\r
- if (!pDib) return false;\r
-\r
- int histogram[256];\r
- int threshold_intensity, intense;\r
- int x, y, i;\r
- unsigned int normalize_map[256];\r
- unsigned int high, low, YVal;\r
-\r
- RGBQUAD color;\r
- RGBQUAD yuvClr;\r
-\r
- memset( &histogram, 0, sizeof( int ) * 256 );\r
- memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );\r
- \r
- // form histogram\r
- for(y=0; y < head.biHeight; y++){\r
- info.nProgress = (long)(50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for(x=0; x < head.biWidth; x++){\r
- color = BlindGetPixelColor( x, y );\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- histogram[YVal]++;\r
- }\r
- }\r
-\r
- // find histogram boundaries by locating the 1 percent levels\r
- threshold_intensity = ( head.biWidth * head.biHeight) / 100;\r
-\r
- intense = 0;\r
- for( low = 0; low < 255; low++ ){\r
- intense += histogram[low];\r
- if( intense > threshold_intensity ) break;\r
- }\r
-\r
- intense = 0;\r
- for( high = 255; high != 0; high--){\r
- intense += histogram[ high ];\r
- if( intense > threshold_intensity ) break;\r
- }\r
-\r
- if ( low == high ){\r
- // Unreasonable contrast; use zero threshold to determine boundaries.\r
- threshold_intensity = 0;\r
- intense = 0;\r
- for( low = 0; low < 255; low++){\r
- intense += histogram[low];\r
- if( intense > threshold_intensity ) break;\r
- }\r
- intense = 0;\r
- for( high = 255; high != 0; high-- ){\r
- intense += histogram [high ];\r
- if( intense > threshold_intensity ) break;\r
- }\r
- }\r
- if( low == high ) return false; // zero span bound\r
-\r
- // Stretch the histogram to create the normalized image mapping.\r
- for(i = 0; i <= 255; i++){\r
- if ( i < (int) low ){\r
- normalize_map[i] = 0;\r
- } else {\r
- if(i > (int) high)\r
- normalize_map[i] = 255;\r
- else\r
- normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );\r
- }\r
- }\r
-\r
- // Normalize\r
- if( head.biClrUsed == 0 ){\r
- for( y = 0; y < head.biHeight; y++ ){\r
- info.nProgress = (long)(50+50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for( x = 0; x < head.biWidth; x++ ){\r
-\r
- color = BlindGetPixelColor( x, y );\r
- yuvClr = RGBtoYUV( color );\r
-\r
- yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];\r
-\r
- color = YUVtoRGB( yuvClr );\r
- BlindSetPixelColor( x, y, color );\r
- }\r
- }\r
- } else {\r
- for(i = 0; i < (int)head.biClrUsed; i++){\r
-\r
- color = GetPaletteColor( (BYTE)i );\r
- yuvClr = RGBtoYUV( color );\r
-\r
- yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];\r
-\r
- color = YUVtoRGB( yuvClr );\r
- SetPaletteColor( (BYTE)i, color );\r
- }\r
- }\r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-// HistogramLog function by <dave> : dave(at)posortho(dot)com\r
-bool CxImage::HistogramLog()\r
-{\r
- if (!pDib) return false;\r
-\r
- //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);\r
- int x, y, i;\r
- RGBQUAD color;\r
- RGBQUAD yuvClr;\r
-\r
- unsigned int YVal, high = 1;\r
-\r
- // Find Highest Luminance Value in the Image\r
- if( head.biClrUsed == 0 ){ // No Palette\r
- for(y=0; y < head.biHeight; y++){\r
- info.nProgress = (long)(50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for(x=0; x < head.biWidth; x++){\r
- color = BlindGetPixelColor( x, y );\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- if (YVal > high ) high = YVal;\r
- }\r
- }\r
- } else { // Palette\r
- for(i = 0; i < (int)head.biClrUsed; i++){\r
- color = GetPaletteColor((BYTE)i);\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- if (YVal > high ) high = YVal;\r
- }\r
- }\r
-\r
- // Logarithm Operator\r
- double k = 255.0 / ::log( 1.0 + (double)high );\r
- if( head.biClrUsed == 0 ){\r
- for( y = 0; y < head.biHeight; y++ ){\r
- info.nProgress = (long)(50+50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for( x = 0; x < head.biWidth; x++ ){\r
-\r
- color = BlindGetPixelColor( x, y );\r
- yuvClr = RGBtoYUV( color );\r
- \r
- yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );\r
-\r
- color = YUVtoRGB( yuvClr );\r
- BlindSetPixelColor( x, y, color );\r
- }\r
- }\r
- } else {\r
- for(i = 0; i < (int)head.biClrUsed; i++){\r
-\r
- color = GetPaletteColor( (BYTE)i );\r
- yuvClr = RGBtoYUV( color );\r
-\r
- yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );\r
- \r
- color = YUVtoRGB( yuvClr );\r
- SetPaletteColor( (BYTE)i, color );\r
- }\r
- }\r
- \r
- return true;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// HistogramRoot function by <dave> : dave(at)posortho(dot)com\r
-bool CxImage::HistogramRoot()\r
-{\r
- if (!pDib) return false;\r
- //q(i,j) = sqrt(|p(i,j)|);\r
-\r
- int x, y, i;\r
- RGBQUAD color;\r
- RGBQUAD yuvClr;\r
- double dtmp;\r
- unsigned int YVal, high = 1;\r
-\r
- // Find Highest Luminance Value in the Image\r
- if( head.biClrUsed == 0 ){ // No Palette\r
- for(y=0; y < head.biHeight; y++){\r
- info.nProgress = (long)(50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for(x=0; x < head.biWidth; x++){\r
- color = BlindGetPixelColor( x, y );\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- if (YVal > high ) high = YVal;\r
- }\r
- }\r
- } else { // Palette\r
- for(i = 0; i < (int)head.biClrUsed; i++){\r
- color = GetPaletteColor((BYTE)i);\r
- YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);\r
- if (YVal > high ) high = YVal;\r
- }\r
- }\r
-\r
- // Root Operator\r
- double k = 128.0 / ::log( 1.0 + (double)high );\r
- if( head.biClrUsed == 0 ){\r
- for( y = 0; y < head.biHeight; y++ ){\r
- info.nProgress = (long)(50+50*y/head.biHeight);\r
- if (info.nEscape) break;\r
- for( x = 0; x < head.biWidth; x++ ){\r
-\r
- color = BlindGetPixelColor( x, y );\r
- yuvClr = RGBtoYUV( color );\r
-\r
- dtmp = k * ::sqrt( (double)yuvClr.rgbRed );\r
- if ( dtmp > 255.0 ) dtmp = 255.0;\r
- if ( dtmp < 0 ) dtmp = 0;\r
- yuvClr.rgbRed = (BYTE)dtmp;\r
-\r
- color = YUVtoRGB( yuvClr );\r
- BlindSetPixelColor( x, y, color );\r
- }\r
- }\r
- } else {\r
- for(i = 0; i < (int)head.biClrUsed; i++){\r
-\r
- color = GetPaletteColor( (BYTE)i );\r
- yuvClr = RGBtoYUV( color );\r
-\r
- dtmp = k * ::sqrt( (double)yuvClr.rgbRed );\r
- if ( dtmp > 255.0 ) dtmp = 255.0;\r
- if ( dtmp < 0 ) dtmp = 0;\r
- yuvClr.rgbRed = (BYTE)dtmp;\r
-\r
- color = YUVtoRGB( yuvClr );\r
- SetPaletteColor( (BYTE)i, color );\r
- }\r
- }\r
- \r
- return true;\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+// xImaHist.cpp : histogram functions
+/* 28/01/2004 v1.00 - www.xdp.it
+ * CxImage version 6.0.0 02/Feb/2008
+ */
+
+#include "ximage.h"
+
+#if CXIMAGE_SUPPORT_DSP
+
+////////////////////////////////////////////////////////////////////////////////
+long CxImage::Histogram(long* red, long* green, long* blue, long* gray, long colorspace)
+{
+ if (!pDib) return 0;
+ RGBQUAD color;
+
+ if (red) memset(red,0,256*sizeof(long));
+ if (green) memset(green,0,256*sizeof(long));
+ if (blue) memset(blue,0,256*sizeof(long));
+ if (gray) memset(gray,0,256*sizeof(long));
+
+ long xmin,xmax,ymin,ymax;
+ if (pSelection){
+ xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
+ ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
+ } else {
+ xmin = ymin = 0;
+ xmax = head.biWidth; ymax=head.biHeight;
+ }
+
+ for(long y=ymin; y<ymax; y++){
+ for(long x=xmin; x<xmax; x++){
+#if CXIMAGE_SUPPORT_SELECTION
+ if (BlindSelectionIsInside(x,y))
+#endif //CXIMAGE_SUPPORT_SELECTION
+ {
+ switch (colorspace){
+ case 1:
+ color = HSLtoRGB(BlindGetPixelColor(x,y));
+ break;
+ case 2:
+ color = YUVtoRGB(BlindGetPixelColor(x,y));
+ break;
+ case 3:
+ color = YIQtoRGB(BlindGetPixelColor(x,y));
+ break;
+ case 4:
+ color = XYZtoRGB(BlindGetPixelColor(x,y));
+ break;
+ default:
+ color = BlindGetPixelColor(x,y);
+ }
+
+ if (red) red[color.rgbRed]++;
+ if (green) green[color.rgbGreen]++;
+ if (blue) blue[color.rgbBlue]++;
+ if (gray) gray[(BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue)]++;
+ }
+ }
+ }
+
+ long n=0;
+ for (int i=0; i<256; i++){
+ if (red && red[i]>n) n=red[i];
+ if (green && green[i]>n) n=green[i];
+ if (blue && blue[i]>n) n=blue[i];
+ if (gray && gray[i]>n) n=gray[i];
+ }
+
+ return n;
+}
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * HistogramStretch
+ * \param method: 0 = luminance (default), 1 = linked channels , 2 = independent channels.
+ * \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%);
+ * \return true if everything is ok
+ * \author [dave] and [nipper]; changes [DP]
+ */
+bool CxImage::HistogramStretch(long method, double threshold)
+{
+ if (!pDib) return false;
+
+ double dbScaler = 50.0/head.biHeight;
+ long x,y;
+
+ if ((head.biBitCount==8) && IsGrayScale()){
+
+ double p[256];
+ memset(p, 0, 256*sizeof(double));
+ for (y=0; y<head.biHeight; y++)
+ {
+ info.nProgress = (long)(y*dbScaler);
+ if (info.nEscape) break;
+ for (x=0; x<head.biWidth; x++) {
+ p[BlindGetPixelIndex(x, y)]++;
+ }
+ }
+
+ double maxh = 0;
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
+ threshold *= maxh;
+ int minc = 0;
+ while (minc<255 && p[minc]<=threshold) minc++;
+ int maxc = 255;
+ while (maxc>0 && p[maxc]<=threshold) maxc--;
+
+ if (minc == 0 && maxc == 255) return true;
+ if (minc >= maxc) return true;
+
+ // calculate LUT
+ BYTE lut[256];
+ for (x = 0; x <256; x++){
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
+ }
+
+ for (y=0; y<head.biHeight; y++) {
+ if (info.nEscape) break;
+ info.nProgress = (long)(50.0+y*dbScaler);
+ for (x=0; x<head.biWidth; x++)
+ {
+ BlindSetPixelIndex(x, y, lut[BlindGetPixelIndex(x, y)]);
+ }
+ }
+ } else {
+ switch(method){
+ case 1:
+ { // <nipper>
+ double p[256];
+ memset(p, 0, 256*sizeof(double));
+ for (y=0; y<head.biHeight; y++)
+ {
+ info.nProgress = (long)(y*dbScaler);
+ if (info.nEscape) break;
+ for (x=0; x<head.biWidth; x++) {
+ RGBQUAD color = BlindGetPixelColor(x, y);
+ p[color.rgbRed]++;
+ p[color.rgbBlue]++;
+ p[color.rgbGreen]++;
+ }
+ }
+ double maxh = 0;
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
+ threshold *= maxh;
+ int minc = 0;
+ while (minc<255 && p[minc]<=threshold) minc++;
+ int maxc = 255;
+ while (maxc>0 && p[maxc]<=threshold) maxc--;
+
+ if (minc == 0 && maxc == 255) return true;
+ if (minc >= maxc) return true;
+
+ // calculate LUT
+ BYTE lut[256];
+ for (x = 0; x <256; x++){
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
+ }
+
+ // normalize image
+ for (y=0; y<head.biHeight; y++) {
+ if (info.nEscape) break;
+ info.nProgress = (long)(50.0+y*dbScaler);
+
+ for (x=0; x<head.biWidth; x++)
+ {
+ RGBQUAD color = BlindGetPixelColor(x, y);
+
+ color.rgbRed = lut[color.rgbRed];
+ color.rgbBlue = lut[color.rgbBlue];
+ color.rgbGreen = lut[color.rgbGreen];
+
+ BlindSetPixelColor(x, y, color);
+ }
+ }
+ }
+ break;
+ case 2:
+ { // <nipper>
+ double pR[256];
+ memset(pR, 0, 256*sizeof(double));
+ double pG[256];
+ memset(pG, 0, 256*sizeof(double));
+ double pB[256];
+ memset(pB, 0, 256*sizeof(double));
+ for (y=0; y<head.biHeight; y++)
+ {
+ info.nProgress = (long)(y*dbScaler);
+ if (info.nEscape) break;
+ for (long x=0; x<head.biWidth; x++) {
+ RGBQUAD color = BlindGetPixelColor(x, y);
+ pR[color.rgbRed]++;
+ pB[color.rgbBlue]++;
+ pG[color.rgbGreen]++;
+ }
+ }
+
+ double maxh = 0;
+ for (y=0; y<255; y++) if (maxh < pR[y]) maxh = pR[y];
+ double threshold2 = threshold*maxh;
+ int minR = 0;
+ while (minR<255 && pR[minR]<=threshold2) minR++;
+ int maxR = 255;
+ while (maxR>0 && pR[maxR]<=threshold2) maxR--;
+
+ maxh = 0;
+ for (y=0; y<255; y++) if (maxh < pG[y]) maxh = pG[y];
+ threshold2 = threshold*maxh;
+ int minG = 0;
+ while (minG<255 && pG[minG]<=threshold2) minG++;
+ int maxG = 255;
+ while (maxG>0 && pG[maxG]<=threshold2) maxG--;
+
+ maxh = 0;
+ for (y=0; y<255; y++) if (maxh < pB[y]) maxh = pB[y];
+ threshold2 = threshold*maxh;
+ int minB = 0;
+ while (minB<255 && pB[minB]<=threshold2) minB++;
+ int maxB = 255;
+ while (maxB>0 && pB[maxB]<=threshold2) maxB--;
+
+ if (minR == 0 && maxR == 255 && minG == 0 && maxG == 255 && minB == 0 && maxB == 255)
+ return true;
+
+ // calculate LUT
+ BYTE lutR[256];
+ BYTE range = maxR - minR;
+ if (range != 0) {
+ for (x = 0; x <256; x++){
+ lutR[x] = (BYTE)max(0,min(255,(255 * (x - minR) / range)));
+ }
+ } else lutR[minR] = minR;
+
+ BYTE lutG[256];
+ range = maxG - minG;
+ if (range != 0) {
+ for (x = 0; x <256; x++){
+ lutG[x] = (BYTE)max(0,min(255,(255 * (x - minG) / range)));
+ }
+ } else lutG[minG] = minG;
+
+ BYTE lutB[256];
+ range = maxB - minB;
+ if (range != 0) {
+ for (x = 0; x <256; x++){
+ lutB[x] = (BYTE)max(0,min(255,(255 * (x - minB) / range)));
+ }
+ } else lutB[minB] = minB;
+
+ // normalize image
+ for (y=0; y<head.biHeight; y++)
+ {
+ info.nProgress = (long)(50.0+y*dbScaler);
+ if (info.nEscape) break;
+
+ for (x=0; x<head.biWidth; x++)
+ {
+ RGBQUAD color = BlindGetPixelColor(x, y);
+
+ color.rgbRed = lutR[color.rgbRed];
+ color.rgbBlue = lutB[color.rgbBlue];
+ color.rgbGreen = lutG[color.rgbGreen];
+
+ BlindSetPixelColor(x, y, color);
+ }
+ }
+ }
+ break;
+ default:
+ { // <dave>
+ double p[256];
+ memset(p, 0, 256*sizeof(double));
+ for (y=0; y<head.biHeight; y++)
+ {
+ info.nProgress = (long)(y*dbScaler);
+ if (info.nEscape) break;
+ for (x=0; x<head.biWidth; x++) {
+ RGBQUAD color = BlindGetPixelColor(x, y);
+ p[RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue)]++;
+ }
+ }
+
+ double maxh = 0;
+ for (y=0; y<255; y++) if (maxh < p[y]) maxh = p[y];
+ threshold *= maxh;
+ int minc = 0;
+ while (minc<255 && p[minc]<=threshold) minc++;
+ int maxc = 255;
+ while (maxc>0 && p[maxc]<=threshold) maxc--;
+
+ if (minc == 0 && maxc == 255) return true;
+ if (minc >= maxc) return true;
+
+ // calculate LUT
+ BYTE lut[256];
+ for (x = 0; x <256; x++){
+ lut[x] = (BYTE)max(0,min(255,(255 * (x - minc) / (maxc - minc))));
+ }
+
+ for(y=0; y<head.biHeight; y++){
+ info.nProgress = (long)(50.0+y*dbScaler);
+ if (info.nEscape) break;
+ for(x=0; x<head.biWidth; x++){
+
+ RGBQUAD color = BlindGetPixelColor( x, y );
+ RGBQUAD yuvClr = RGBtoYUV(color);
+ yuvClr.rgbRed = lut[yuvClr.rgbRed];
+ color = YUVtoRGB(yuvClr);
+ BlindSetPixelColor( x, y, color );
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+// HistogramEqualize function by <dave> : dave(at)posortho(dot)com
+bool CxImage::HistogramEqualize()
+{
+ if (!pDib) return false;
+
+ int histogram[256];
+ int map[256];
+ int equalize_map[256];
+ int x, y, i, j;
+ RGBQUAD color;
+ RGBQUAD yuvClr;
+ unsigned int YVal, high, low;
+
+ memset( &histogram, 0, sizeof(int) * 256 );
+ memset( &map, 0, sizeof(int) * 256 );
+ memset( &equalize_map, 0, sizeof(int) * 256 );
+
+ // form histogram
+ for(y=0; y < head.biHeight; y++){
+ info.nProgress = (long)(50*y/head.biHeight);
+ if (info.nEscape) break;
+ for(x=0; x < head.biWidth; x++){
+ color = BlindGetPixelColor( x, y );
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ histogram[YVal]++;
+ }
+ }
+
+ // integrate the histogram to get the equalization map.
+ j = 0;
+ for(i=0; i <= 255; i++){
+ j += histogram[i];
+ map[i] = j;
+ }
+
+ // equalize
+ low = map[0];
+ high = map[255];
+ if (low == high) return false;
+ for( i = 0; i <= 255; i++ ){
+ equalize_map[i] = (unsigned int)((((double)( map[i] - low ) ) * 255) / ( high - low ) );
+ }
+
+ // stretch the histogram
+ if(head.biClrUsed == 0){ // No Palette
+ for( y = 0; y < head.biHeight; y++ ){
+ info.nProgress = (long)(50+50*y/head.biHeight);
+ if (info.nEscape) break;
+ for( x = 0; x < head.biWidth; x++ ){
+
+ color = BlindGetPixelColor( x, y );
+ yuvClr = RGBtoYUV(color);
+
+ yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
+
+ color = YUVtoRGB(yuvClr);
+ BlindSetPixelColor( x, y, color );
+ }
+ }
+ } else { // Palette
+ for( i = 0; i < (int)head.biClrUsed; i++ ){
+
+ color = GetPaletteColor((BYTE)i);
+ yuvClr = RGBtoYUV(color);
+
+ yuvClr.rgbRed = (BYTE)equalize_map[yuvClr.rgbRed];
+
+ color = YUVtoRGB(yuvClr);
+ SetPaletteColor( (BYTE)i, color );
+ }
+ }
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+// HistogramNormalize function by <dave> : dave(at)posortho(dot)com
+bool CxImage::HistogramNormalize()
+{
+ if (!pDib) return false;
+
+ int histogram[256];
+ int threshold_intensity, intense;
+ int x, y, i;
+ unsigned int normalize_map[256];
+ unsigned int high, low, YVal;
+
+ RGBQUAD color;
+ RGBQUAD yuvClr;
+
+ memset( &histogram, 0, sizeof( int ) * 256 );
+ memset( &normalize_map, 0, sizeof( unsigned int ) * 256 );
+
+ // form histogram
+ for(y=0; y < head.biHeight; y++){
+ info.nProgress = (long)(50*y/head.biHeight);
+ if (info.nEscape) break;
+ for(x=0; x < head.biWidth; x++){
+ color = BlindGetPixelColor( x, y );
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ histogram[YVal]++;
+ }
+ }
+
+ // find histogram boundaries by locating the 1 percent levels
+ threshold_intensity = ( head.biWidth * head.biHeight) / 100;
+
+ intense = 0;
+ for( low = 0; low < 255; low++ ){
+ intense += histogram[low];
+ if( intense > threshold_intensity ) break;
+ }
+
+ intense = 0;
+ for( high = 255; high != 0; high--){
+ intense += histogram[ high ];
+ if( intense > threshold_intensity ) break;
+ }
+
+ if ( low == high ){
+ // Unreasonable contrast; use zero threshold to determine boundaries.
+ threshold_intensity = 0;
+ intense = 0;
+ for( low = 0; low < 255; low++){
+ intense += histogram[low];
+ if( intense > threshold_intensity ) break;
+ }
+ intense = 0;
+ for( high = 255; high != 0; high-- ){
+ intense += histogram [high ];
+ if( intense > threshold_intensity ) break;
+ }
+ }
+ if( low == high ) return false; // zero span bound
+
+ // Stretch the histogram to create the normalized image mapping.
+ for(i = 0; i <= 255; i++){
+ if ( i < (int) low ){
+ normalize_map[i] = 0;
+ } else {
+ if(i > (int) high)
+ normalize_map[i] = 255;
+ else
+ normalize_map[i] = ( 255 - 1) * ( i - low) / ( high - low );
+ }
+ }
+
+ // Normalize
+ if( head.biClrUsed == 0 ){
+ for( y = 0; y < head.biHeight; y++ ){
+ info.nProgress = (long)(50+50*y/head.biHeight);
+ if (info.nEscape) break;
+ for( x = 0; x < head.biWidth; x++ ){
+
+ color = BlindGetPixelColor( x, y );
+ yuvClr = RGBtoYUV( color );
+
+ yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
+
+ color = YUVtoRGB( yuvClr );
+ BlindSetPixelColor( x, y, color );
+ }
+ }
+ } else {
+ for(i = 0; i < (int)head.biClrUsed; i++){
+
+ color = GetPaletteColor( (BYTE)i );
+ yuvClr = RGBtoYUV( color );
+
+ yuvClr.rgbRed = (BYTE)normalize_map[yuvClr.rgbRed];
+
+ color = YUVtoRGB( yuvClr );
+ SetPaletteColor( (BYTE)i, color );
+ }
+ }
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+// HistogramLog function by <dave> : dave(at)posortho(dot)com
+bool CxImage::HistogramLog()
+{
+ if (!pDib) return false;
+
+ //q(i,j) = 255/log(1 + |high|) * log(1 + |p(i,j)|);
+ int x, y, i;
+ RGBQUAD color;
+ RGBQUAD yuvClr;
+
+ unsigned int YVal, high = 1;
+
+ // Find Highest Luminance Value in the Image
+ if( head.biClrUsed == 0 ){ // No Palette
+ for(y=0; y < head.biHeight; y++){
+ info.nProgress = (long)(50*y/head.biHeight);
+ if (info.nEscape) break;
+ for(x=0; x < head.biWidth; x++){
+ color = BlindGetPixelColor( x, y );
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ if (YVal > high ) high = YVal;
+ }
+ }
+ } else { // Palette
+ for(i = 0; i < (int)head.biClrUsed; i++){
+ color = GetPaletteColor((BYTE)i);
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ if (YVal > high ) high = YVal;
+ }
+ }
+
+ // Logarithm Operator
+ double k = 255.0 / ::log( 1.0 + (double)high );
+ if( head.biClrUsed == 0 ){
+ for( y = 0; y < head.biHeight; y++ ){
+ info.nProgress = (long)(50+50*y/head.biHeight);
+ if (info.nEscape) break;
+ for( x = 0; x < head.biWidth; x++ ){
+
+ color = BlindGetPixelColor( x, y );
+ yuvClr = RGBtoYUV( color );
+
+ yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
+
+ color = YUVtoRGB( yuvClr );
+ BlindSetPixelColor( x, y, color );
+ }
+ }
+ } else {
+ for(i = 0; i < (int)head.biClrUsed; i++){
+
+ color = GetPaletteColor( (BYTE)i );
+ yuvClr = RGBtoYUV( color );
+
+ yuvClr.rgbRed = (BYTE)(k * ::log( 1.0 + (double)yuvClr.rgbRed ) );
+
+ color = YUVtoRGB( yuvClr );
+ SetPaletteColor( (BYTE)i, color );
+ }
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HistogramRoot function by <dave> : dave(at)posortho(dot)com
+bool CxImage::HistogramRoot()
+{
+ if (!pDib) return false;
+ //q(i,j) = sqrt(|p(i,j)|);
+
+ int x, y, i;
+ RGBQUAD color;
+ RGBQUAD yuvClr;
+ double dtmp;
+ unsigned int YVal, high = 1;
+
+ // Find Highest Luminance Value in the Image
+ if( head.biClrUsed == 0 ){ // No Palette
+ for(y=0; y < head.biHeight; y++){
+ info.nProgress = (long)(50*y/head.biHeight);
+ if (info.nEscape) break;
+ for(x=0; x < head.biWidth; x++){
+ color = BlindGetPixelColor( x, y );
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ if (YVal > high ) high = YVal;
+ }
+ }
+ } else { // Palette
+ for(i = 0; i < (int)head.biClrUsed; i++){
+ color = GetPaletteColor((BYTE)i);
+ YVal = (unsigned int)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
+ if (YVal > high ) high = YVal;
+ }
+ }
+
+ // Root Operator
+ double k = 128.0 / ::log( 1.0 + (double)high );
+ if( head.biClrUsed == 0 ){
+ for( y = 0; y < head.biHeight; y++ ){
+ info.nProgress = (long)(50+50*y/head.biHeight);
+ if (info.nEscape) break;
+ for( x = 0; x < head.biWidth; x++ ){
+
+ color = BlindGetPixelColor( x, y );
+ yuvClr = RGBtoYUV( color );
+
+ dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
+ if ( dtmp > 255.0 ) dtmp = 255.0;
+ if ( dtmp < 0 ) dtmp = 0;
+ yuvClr.rgbRed = (BYTE)dtmp;
+
+ color = YUVtoRGB( yuvClr );
+ BlindSetPixelColor( x, y, color );
+ }
+ }
+ } else {
+ for(i = 0; i < (int)head.biClrUsed; i++){
+
+ color = GetPaletteColor( (BYTE)i );
+ yuvClr = RGBtoYUV( color );
+
+ dtmp = k * ::sqrt( (double)yuvClr.rgbRed );
+ if ( dtmp > 255.0 ) dtmp = 255.0;
+ if ( dtmp < 0 ) dtmp = 0;
+ yuvClr.rgbRed = (BYTE)dtmp;
+
+ color = YUVtoRGB( yuvClr );
+ SetPaletteColor( (BYTE)i, color );
+ }
+ }
+
+ return true;
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif