$search
00001 00005 //***************************************************************************** 00006 // Contrast Limited Adaptive Histogram Equalization (CLAHE) for OpenCV 00007 //----------------------------------------------------------------------------- 00008 // Original CLAHE implementation by Karel Zuiderveld, karel@cv.ruu.nl 00009 // in "Graphics Gems IV", Academic Press, 1994. 00010 //----------------------------------------------------------------------------- 00011 // Converted to OpenCV format by Toby Breckon, toby.breckon@cranfield.ac.uk 00012 // Copyright (c) 2009 School of Engineering, Cranfield University 00013 // License : LGPL - http://www.gnu.org/licenses/lgpl.html 00014 //----------------------------------------------------------------------------- 00015 // Improved by Shervin Emami on 17th Nov 2010, shervin.emami@gmail.com 00016 // http://www.shervinemami.co.cc/ 00017 //***************************************************************************** 00018 00019 00020 #include <cv.h> // open cv general include file 00021 00022 #include "clahe.h" // opencv CLAHE include file 00023 00024 #include <stdio.h> 00025 #include <stdlib.h> 00026 00027 // ***************************************************************************** 00028 00029 // type defs. for Graphic Gemms Code - see later 00030 00031 #define BYTE_IMAGE 00032 00033 #ifdef BYTE_IMAGE 00034 typedef unsigned char kz_pixel_t; /* for 8 bit-per-pixel images */ 00035 #define uiNR_OF_GREY (256) 00036 #else 00037 typedef unsigned short kz_pixel_t; /* for 12 bit-per-pixel images (default) */ 00038 # define uiNR_OF_GREY (4096) 00039 #endif 00040 00041 /************* Prototype of Graphic Gemms CLAHE function. *********************/ 00042 00043 static int CLAHE(kz_pixel_t* pImage, unsigned int uiXRes, 00044 unsigned int uiYRes, kz_pixel_t Min, 00045 kz_pixel_t Max, unsigned int uiNrX, unsigned int uiNrY, 00046 unsigned int uiNrBins, float fCliplimit); 00047 00048 // ***************************************************************************** 00049 00050 // General Notes: 00051 // 00052 // The number of "effective" greylevels in the output image is set by bins; selecting 00053 // a small value (eg. 128) speeds up processing and still produce an output image of 00054 // good quality. The output image will have the same minimum and maximum value as the input 00055 // image. A clip limit smaller than 1 (?? is this correct ) results in 00056 // standard (non-contrast limited) AHE. 00057 00058 00059 // cvAdaptEqualize(src, dst, xdivs, ydivs, bins) 00060 // 00061 // perform adaptive histogram equalization (AHE) 00062 // 00063 // src - pointer to source image (must be single channel 8-bit) 00064 // dst - pointer to destination image (must be single channel 8-bit) 00065 // xdivs - number of cell divisions to use in vertical (x) direction (MIN=2 MAX = 16) 00066 // ydivs - number of cell divisions to use in vertical (y) direction (MIN=2 MAX = 16) 00067 // bins - number of histogram bins to use per division 00068 // range - either of CV_CLAHE_RANGE_INPUT or CV_CLAHE_RANGE_FULL to limit the output 00069 // pixel range to the min/max range of the input image or the full range of the 00070 // pixel depth (8-bit in this case) 00071 00072 void cvAdaptEqualize(IplImage *src, IplImage *dst, 00073 unsigned int xdivs, unsigned int ydivs, unsigned int bins, int range) 00074 { 00075 00076 // call CLAHE with negative limit (as flag value) to perform AHE (no limits) 00077 00078 cvCLAdaptEqualize(src, dst, xdivs, ydivs, bins, -1.0, range); 00079 } 00080 00081 // cvCLAdaptEqualize(src, dst, xdivs, ydivs, bins, limit) 00082 // 00083 // perform contrast limited adaptive histogram equalization (CLAHE) 00084 // 00085 // src - pointer to source image (must be single channel 8-bit) 00086 // dst - pointer to destination image (must be single channel 8-bit) 00087 // xdivs - number of cell divisions to use in vertical (x) direction (MIN=2 MAX = 16) 00088 // ydivs - number of cell divisions to use in vertical (y) direction (MIN=2 MAX = 16) 00089 // bins - number of histogram bins to use per division (MIN=2 MAX = 256) 00090 // limit - contrast limit for localised changes in contrast 00091 // (limit >= 0 gives standard AHE without contrast limiting) 00092 // range - either of CV_CLAHE_RANGE_INPUT or CV_CLAHE_RANGE_FULL to limit the output 00093 // pixel range to the min/max range of the input image or the full range of the 00094 // pixel depth (8-bit in this case) 00095 00096 00097 void cvCLAdaptEqualize(IplImage *src, IplImage *dst, 00098 unsigned int xdivs, unsigned int ydivs, unsigned int bins, 00099 float limit, int range) 00100 { 00101 00102 double min_val, max_val; 00103 unsigned char min, max; 00104 00105 // CV_FUNCNAME( "cvCLAdaptEquualize" ); 00106 // __BEGIN__; 00107 00108 // check the inputs to the function 00109 00110 int type; 00111 00112 if ((src == NULL) || (dst == NULL)) 00113 CV_ERROR( CV_StsUnsupportedFormat, "NULL value passed as image to function" ); 00114 00115 CV_CALL( type = cvGetElemType( src )); 00116 if( type != CV_8UC1 ) 00117 CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" ); 00118 CV_CALL( type = cvGetElemType( src )); 00119 if( type != CV_8UC1 ) 00120 CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" ); 00121 00122 //if( !CV_ARE_SIZES_EQ( src, dst )) // Modified by Shervin Emami, 17Nov2010. 00123 if (src->width != dst->width || src->height != dst->height) 00124 CV_ERROR( CV_StsUnmatchedSizes, "src and dst images must be equal sizes" ); 00125 00126 if (((xdivs < 2) || (xdivs > 16)) || ((ydivs < 2) || (ydivs > 16))) 00127 CV_ERROR( CV_StsBadFlag, "xdivs and ydivs must in range (MIN=2 MAX = 16)" ); 00128 00129 if ((bins < 2) || (bins > 256)) 00130 CV_ERROR( CV_StsBadFlag, "bins must in range (MIN=2 MAX = 256)" ); 00131 00132 // copy src to dst for in-place CLAHE. 00133 cvCopy(src, dst); 00134 00135 00136 // If the dimensions of the image are not a multiple of the xdivs and ydivs, then enlarge the image to be a correct size and then shrink the image. 00137 // Also make sure the image is aligned to 8 pixels width, so that OpenCV won't add extra padding to the image. 00138 // Added by Shervin Emami, 17Nov2010. 00139 int enlarged = 0; 00140 int origW = dst->width; 00141 int origH = dst->height; 00142 IplImage *tmpDst = 0; 00143 if ((dst->width & (8-1)) || (dst->height & (8-1)) || (dst->width % xdivs) || (dst->height % ydivs)) { 00144 int newW = ((dst->width + 8-1) & -8); // Align to 8 pixels, so that widthStep hopefully equals width. 00145 newW = ((newW + xdivs-1) & -xdivs); // Also align for CLAHE. 00146 int newH = ((dst->height + ydivs-1) & -ydivs); 00147 //std::cout << "w=" << dst->width << ", h=" << dst->height << ". new w = " << newW << ", h = " << newH << std::endl; 00148 IplImage *enlargedDst = cvCreateImage(cvSize(newW, newH), dst->depth, dst->nChannels); 00149 cvResize(dst, enlargedDst, CV_INTER_CUBIC); 00150 //cvReleaseImage(&dst); 00151 tmpDst = dst; 00152 dst = enlargedDst; // Use the enlarged image instead of the original dst image. 00153 enlarged = 1; // signal that we need to shrink later! 00154 } 00155 // Check if OpenCV adds padding bytes on each row. Added by Shervin Emami, 17Nov2010. 00156 if (dst->width != dst->widthStep) 00157 CV_ERROR( CV_StsBadFlag, "dst->widthStep should be the same as dst->width. The IplImage has padding, so use a larger image." ); 00158 00159 00160 // check number of xdivs and ydivs is a multiple of image dimensions 00161 if (dst->width % xdivs) 00162 CV_ERROR( CV_StsBadFlag, "xdiv must be an integer multiple of image width " ); 00163 if (dst->height % ydivs) 00164 CV_ERROR( CV_StsBadFlag, "ydiv must be an integer multiple of image height " ); 00165 00166 // get the min and max values of the image 00167 00168 if (range == CV_CLAHE_RANGE_INPUT) { 00169 cvMinMaxLoc(dst, &min_val, &max_val); 00170 min = (unsigned char) min_val; 00171 max = (unsigned char) max_val; 00172 } else { 00173 min = 0; 00174 max = 255; 00175 } 00176 // call CLHAHE for in-place CLAHE 00177 00178 //int rcode = 00179 CLAHE((kz_pixel_t*) (dst->imageData), (unsigned int) dst->width, (unsigned int) 00180 dst->height, (kz_pixel_t) min, (kz_pixel_t) max, (unsigned int) xdivs, (unsigned int) ydivs, 00181 (unsigned int) bins, (float) limit); 00182 00183 //printf("RCODE %i\n", rcode); 00184 00185 // If the dst image was enlarged to fit the alignment, then shrink it back now. 00186 // Added by Shervin Emami, 17Nov2010. 00187 if (enlarged) { 00188 //std::cout << "w=" << dst->width << ", h=" << dst->height << ". orig w=" << origW << ", h=" << origH << std::endl; 00189 cvResize(dst, tmpDst, CV_INTER_CUBIC); // Shrink the enlarged image back into the original dst image. 00190 cvReleaseImage(&dst); // Free the enlarged image. 00191 } 00192 } 00193 00194 // ***************************************************************************** 00195 /* 00196 * ANSI C code from the article 00197 * "Contrast Limited Adaptive Histogram Equalization" 00198 * by Karel Zuiderveld, karel@cv.ruu.nl 00199 * in "Graphics Gems IV", Academic Press, 1994 00200 * 00201 * 00202 * These functions implement Contrast Limited Adaptive Histogram Equalization. 00203 * The main routine (CLAHE) expects an input image that is stored contiguously in 00204 * memory; the CLAHE output image overwrites the original input image and has the 00205 * same minimum and maximum values (which must be provided by the user). 00206 * This implementation assumes that the X- and Y image resolutions are an integer 00207 * multiple of the X- and Y sizes of the contextual regions. A check on various other 00208 * error conditions is performed. 00209 * 00210 * #define the symbol BYTE_IMAGE to make this implementation suitable for 00211 * 8-bit images. The maximum number of contextual regions can be redefined 00212 * by changing uiMAX_REG_X and/or uiMAX_REG_Y; the use of more than 256 00213 * contextual regions is not recommended. 00214 * 00215 * The code is ANSI-C and is also C++ compliant. 00216 * 00217 * Author: Karel Zuiderveld, Computer Vision Research Group, 00218 * Utrecht, The Netherlands (karel@cv.ruu.nl) 00219 */ 00220 00221 /* 00222 00223 EULA: The Graphics Gems code is copyright-protected. In other words, you cannot 00224 claim the text of the code as your own and resell it. Using the code is permitted 00225 in any program, product, or library, non-commercial or commercial. Giving credit 00226 is not required, though is a nice gesture. The code comes as-is, and if there are 00227 any flaws or problems with any Gems code, nobody involved with Gems - authors, 00228 editors, publishers, or webmasters - are to be held responsible. Basically, 00229 don't be a jerk, and remember that anything free comes with no guarantee. 00230 00231 - http://tog.acm.org/resources/GraphicsGems/ (August 2009) 00232 00233 */ 00234 00235 /*********************** Local prototypes ************************/ 00236 static void ClipHistogram (unsigned long*, unsigned int, unsigned long); 00237 static void MakeHistogram (kz_pixel_t*, unsigned int, unsigned int, unsigned int, 00238 unsigned long*, unsigned int, kz_pixel_t*); 00239 static void MapHistogram (unsigned long*, kz_pixel_t, kz_pixel_t, 00240 unsigned int, unsigned long); 00241 static void MakeLut (kz_pixel_t*, kz_pixel_t, kz_pixel_t, unsigned int); 00242 static void Interpolate (kz_pixel_t*, int, unsigned long*, unsigned long*, 00243 unsigned long*, unsigned long*, unsigned int, unsigned int, kz_pixel_t*); 00244 00245 // ***************************************************************************** 00246 00247 /************** Start of actual code **************/ 00248 #include <stdlib.h> /* To get prototypes of malloc() and free() */ 00249 00250 const static unsigned int uiMAX_REG_X = 16; /* max. # contextual regions in x-direction */ 00251 const static unsigned int uiMAX_REG_Y = 16; /* max. # contextual regions in y-direction */ 00252 00253 /************************** main function CLAHE ******************/ 00254 static int CLAHE (kz_pixel_t* pImage, unsigned int uiXRes, unsigned int uiYRes, 00255 kz_pixel_t Min, kz_pixel_t Max, unsigned int uiNrX, unsigned int uiNrY, 00256 unsigned int uiNrBins, float fCliplimit) 00257 /* pImage - Pointer to the input/output image 00258 * uiXRes - Image resolution in the X direction 00259 * uiYRes - Image resolution in the Y direction 00260 * Min - Minimum greyvalue of input image (also becomes minimum of output image) 00261 * Max - Maximum greyvalue of input image (also becomes maximum of output image) 00262 * uiNrX - Number of contextial regions in the X direction (min 2, max uiMAX_REG_X) 00263 * uiNrY - Number of contextial regions in the Y direction (min 2, max uiMAX_REG_Y) 00264 * uiNrBins - Number of greybins for histogram ("dynamic range") 00265 * float fCliplimit - Normalized cliplimit (higher values give more contrast) 00266 * The number of "effective" greylevels in the output image is set by uiNrBins; selecting 00267 * a small value (eg. 128) speeds up processing and still produce an output image of 00268 * good quality. The output image will have the same minimum and maximum value as the input 00269 * image. A clip limit smaller than 1 results in standard (non-contrast limited) AHE. 00270 */ 00271 { 00272 unsigned int uiX, uiY; /* counters */ 00273 unsigned int uiXSize, uiYSize, uiSubX, uiSubY; /* size of context. reg. and subimages */ 00274 unsigned int uiXL, uiXR, uiYU, uiYB; /* auxiliary variables interpolation routine */ 00275 unsigned long ulClipLimit, ulNrPixels;/* clip limit and region pixel count */ 00276 kz_pixel_t* pImPointer; /* pointer to image */ 00277 kz_pixel_t aLUT[uiNR_OF_GREY]; /* lookup table used for scaling of input image */ 00278 unsigned long* pulHist, *pulMapArray; /* pointer to histogram and mappings*/ 00279 unsigned long* pulLU, *pulLB, *pulRU, *pulRB; /* auxiliary pointers interpolation */ 00280 00281 if (uiNrX > uiMAX_REG_X) return -1; /* # of regions x-direction too large */ 00282 if (uiNrY > uiMAX_REG_Y) return -2; /* # of regions y-direction too large */ 00283 if (uiXRes % uiNrX) return -3; /* x-resolution no multiple of uiNrX */ 00284 if (uiYRes % uiNrY) return -4; /* y-resolution no multiple of uiNrY #TPB FIX */ 00285 #ifndef BYTE_IMAGE /* #TPB FIX */ 00286 if (Max >= uiNR_OF_GREY) return -5; /* maximum too large */ 00287 #endif 00288 if (Min >= Max) return -6; /* minimum equal or larger than maximum */ 00289 if (uiNrX < 2 || uiNrY < 2) return -7;/* at least 4 contextual regions required */ 00290 if (fCliplimit == 1.0) return 0; /* is OK, immediately returns original image. */ 00291 if (uiNrBins == 0) uiNrBins = 128; /* default value when not specified */ 00292 00293 pulMapArray=(unsigned long *)malloc(sizeof(unsigned long)*uiNrX*uiNrY*uiNrBins); 00294 if (pulMapArray == 0) return -8; /* Not enough memory! (try reducing uiNrBins) */ 00295 00296 uiXSize = uiXRes/uiNrX; uiYSize = uiYRes/uiNrY; /* Actual size of contextual regions */ 00297 ulNrPixels = (unsigned long)uiXSize * (unsigned long)uiYSize; 00298 00299 if(fCliplimit > 0.0) { /* Calculate actual cliplimit */ 00300 ulClipLimit = (unsigned long) (fCliplimit * (uiXSize * uiYSize) / uiNrBins); 00301 ulClipLimit = (ulClipLimit < 1UL) ? 1UL : ulClipLimit; 00302 } 00303 else ulClipLimit = 1UL<<14; /* Large value, do not clip (AHE) */ 00304 MakeLut(aLUT, Min, Max, uiNrBins); /* Make lookup table for mapping of greyvalues */ 00305 /* Calculate greylevel mappings for each contextual region */ 00306 for (uiY = 0, pImPointer = pImage; uiY < uiNrY; uiY++) { 00307 for (uiX = 0; uiX < uiNrX; uiX++, pImPointer += uiXSize) { 00308 pulHist = &pulMapArray[uiNrBins * (uiY * uiNrX + uiX)]; 00309 MakeHistogram(pImPointer,uiXRes,uiXSize,uiYSize,pulHist,uiNrBins,aLUT); 00310 ClipHistogram(pulHist, uiNrBins, ulClipLimit); 00311 MapHistogram(pulHist, Min, Max, uiNrBins, ulNrPixels); 00312 } 00313 pImPointer += (uiYSize - 1) * uiXRes; /* skip lines, set pointer */ 00314 } 00315 00316 /* Interpolate greylevel mappings to get CLAHE image */ 00317 for (pImPointer = pImage, uiY = 0; uiY <= uiNrY; uiY++) { 00318 if (uiY == 0) { /* special case: top row */ 00319 uiSubY = uiYSize >> 1; uiYU = 0; uiYB = 0; 00320 } 00321 else { 00322 if (uiY == uiNrY) { /* special case: bottom row */ 00323 uiSubY = uiYSize >> 1; uiYU = uiNrY-1; uiYB = uiYU; 00324 } 00325 else { /* default values */ 00326 uiSubY = uiYSize; uiYU = uiY - 1; uiYB = uiYU + 1; 00327 } 00328 } 00329 for (uiX = 0; uiX <= uiNrX; uiX++) { 00330 if (uiX == 0) { /* special case: left column */ 00331 uiSubX = uiXSize >> 1; uiXL = 0; uiXR = 0; 00332 } 00333 else { 00334 if (uiX == uiNrX) { /* special case: right column */ 00335 uiSubX = uiXSize >> 1; uiXL = uiNrX - 1; uiXR = uiXL; 00336 } 00337 else { /* default values */ 00338 uiSubX = uiXSize; uiXL = uiX - 1; uiXR = uiXL + 1; 00339 } 00340 } 00341 00342 pulLU = &pulMapArray[uiNrBins * (uiYU * uiNrX + uiXL)]; 00343 pulRU = &pulMapArray[uiNrBins * (uiYU * uiNrX + uiXR)]; 00344 pulLB = &pulMapArray[uiNrBins * (uiYB * uiNrX + uiXL)]; 00345 pulRB = &pulMapArray[uiNrBins * (uiYB * uiNrX + uiXR)]; 00346 Interpolate(pImPointer,uiXRes,pulLU,pulRU,pulLB,pulRB,uiSubX,uiSubY,aLUT); 00347 pImPointer += uiSubX; /* set pointer on next matrix */ 00348 } 00349 pImPointer += (uiSubY - 1) * uiXRes; 00350 } 00351 free(pulMapArray); /* free space for histograms */ 00352 return 0; /* return status OK */ 00353 } 00354 void ClipHistogram (unsigned long* pulHistogram, unsigned int 00355 uiNrGreylevels, unsigned long ulClipLimit) 00356 /* This function performs clipping of the histogram and redistribution of bins. 00357 * The histogram is clipped and the number of excess pixels is counted. Afterwards 00358 * the excess pixels are equally redistributed across the whole histogram (providing 00359 * the bin count is smaller than the cliplimit). 00360 */ 00361 { 00362 unsigned long* pulBinPointer, *pulEndPointer, *pulHisto; 00363 unsigned long ulNrExcess, ulUpper, ulBinIncr, ulStepSize, i; 00364 unsigned long ulOldNrExcess; // #IAC Modification 00365 00366 long lBinExcess; 00367 00368 ulNrExcess = 0; pulBinPointer = pulHistogram; 00369 for (i = 0; i < uiNrGreylevels; i++) { /* calculate total number of excess pixels */ 00370 lBinExcess = (long) pulBinPointer[i] - (long) ulClipLimit; 00371 if (lBinExcess > 0) ulNrExcess += lBinExcess; /* excess in current bin */ 00372 }; 00373 00374 /* Second part: clip histogram and redistribute excess pixels in each bin */ 00375 ulBinIncr = ulNrExcess / uiNrGreylevels; /* average binincrement */ 00376 ulUpper = ulClipLimit - ulBinIncr; /* Bins larger than ulUpper set to cliplimit */ 00377 00378 for (i = 0; i < uiNrGreylevels; i++) { 00379 if (pulHistogram[i] > ulClipLimit) pulHistogram[i] = ulClipLimit; /* clip bin */ 00380 else { 00381 if (pulHistogram[i] > ulUpper) { /* high bin count */ 00382 ulNrExcess -= pulHistogram[i] - ulUpper; pulHistogram[i]=ulClipLimit; 00383 } 00384 else { /* low bin count */ 00385 ulNrExcess -= ulBinIncr; pulHistogram[i] += ulBinIncr; 00386 } 00387 } 00388 } 00389 00390 // while (ulNrExcess) { /* Redistribute remaining excess */ 00391 // pulEndPointer = &pulHistogram[uiNrGreylevels]; pulHisto = pulHistogram; 00392 // 00393 // while (ulNrExcess && pulHisto < pulEndPointer) { 00394 // ulStepSize = uiNrGreylevels / ulNrExcess; 00395 // if (ulStepSize < 1) ulStepSize = 1; /* stepsize at least 1 */ 00396 // for (pulBinPointer=pulHisto; pulBinPointer < pulEndPointer && ulNrExcess; 00397 // pulBinPointer += ulStepSize) { 00398 // if (*pulBinPointer < ulClipLimit) { 00399 // (*pulBinPointer)++; ulNrExcess--; /* reduce excess */ 00400 // } 00401 // } 00402 // pulHisto++; /* restart redistributing on other bin location */ 00403 // } 00404 //} 00405 00406 /* #### 00407 00408 IAC Modification: 00409 In the original version of the loop below (commented out above) it was possible for an infinite loop to get 00410 created. If there was more pixels to be redistributed than available space then the 00411 while loop would never end. This problem has been fixed by stopping the loop when all 00412 pixels have been redistributed OR when no pixels where redistributed in the previous iteration. 00413 This change allows very low clipping levels to be used. 00414 00415 */ 00416 00417 do { /* Redistribute remaining excess */ 00418 pulEndPointer = &pulHistogram[uiNrGreylevels]; pulHisto = pulHistogram; 00419 00420 ulOldNrExcess = ulNrExcess; /* Store number of excess pixels for test later. */ 00421 00422 while (ulNrExcess && pulHisto < pulEndPointer) 00423 { 00424 ulStepSize = uiNrGreylevels / ulNrExcess; 00425 if (ulStepSize < 1) 00426 ulStepSize = 1; /* stepsize at least 1 */ 00427 for (pulBinPointer=pulHisto; pulBinPointer < pulEndPointer && ulNrExcess; 00428 pulBinPointer += ulStepSize) 00429 { 00430 if (*pulBinPointer < ulClipLimit) 00431 { 00432 (*pulBinPointer)++; ulNrExcess--; /* reduce excess */ 00433 } 00434 } 00435 pulHisto++; /* restart redistributing on other bin location */ 00436 } 00437 } while ((ulNrExcess) && (ulNrExcess < ulOldNrExcess)); 00438 /* Finish loop when we have no more pixels or we can't redistribute any more pixels */ 00439 00440 00441 } 00442 00443 void MakeHistogram (kz_pixel_t* pImage, unsigned int uiXRes, 00444 unsigned int uiSizeX, unsigned int uiSizeY, 00445 unsigned long* pulHistogram, 00446 unsigned int uiNrGreylevels, kz_pixel_t* pLookupTable) 00447 /* This function classifies the greylevels present in the array image into 00448 * a greylevel histogram. The pLookupTable specifies the relationship 00449 * between the greyvalue of the pixel (typically between 0 and 4095) and 00450 * the corresponding bin in the histogram (usually containing only 128 bins). 00451 */ 00452 { 00453 kz_pixel_t* pImagePointer; 00454 unsigned int i; 00455 00456 for (i = 0; i < uiNrGreylevels; i++) pulHistogram[i] = 0L; /* clear histogram */ 00457 00458 for (i = 0; i < uiSizeY; i++) { 00459 pImagePointer = &pImage[uiSizeX]; 00460 while (pImage < pImagePointer) pulHistogram[pLookupTable[*pImage++]]++; 00461 pImagePointer += uiXRes; 00462 pImage = &pImagePointer[-uiSizeX]; 00463 } 00464 } 00465 00466 void MapHistogram (unsigned long* pulHistogram, kz_pixel_t Min, kz_pixel_t Max, 00467 unsigned int uiNrGreylevels, unsigned long ulNrOfPixels) 00468 /* This function calculates the equalized lookup table (mapping) by 00469 * cumulating the input histogram. Note: lookup table is rescaled in range [Min..Max]. 00470 */ 00471 { 00472 unsigned int i; unsigned long ulSum = 0; 00473 const float fScale = ((float)(Max - Min)) / ulNrOfPixels; 00474 const unsigned long ulMin = (unsigned long) Min; 00475 00476 for (i = 0; i < uiNrGreylevels; i++) { 00477 ulSum += pulHistogram[i]; pulHistogram[i]=(unsigned long)(ulMin+ulSum*fScale); 00478 if (pulHistogram[i] > Max) pulHistogram[i] = Max; 00479 } 00480 } 00481 00482 void MakeLut (kz_pixel_t * pLUT, kz_pixel_t Min, kz_pixel_t Max, unsigned int uiNrBins) 00483 /* To speed up histogram clipping, the input image [Min,Max] is scaled down to 00484 * [0,uiNrBins-1]. This function calculates the LUT. 00485 */ 00486 { 00487 int i; 00488 const kz_pixel_t BinSize = (kz_pixel_t) (1 + (Max - Min) / uiNrBins); 00489 00490 for (i = Min; i <= Max; i++) pLUT[i] = (i - Min) / BinSize; 00491 } 00492 00493 void Interpolate (kz_pixel_t * pImage, int uiXRes, unsigned long * pulMapLU, 00494 unsigned long * pulMapRU, unsigned long * pulMapLB, unsigned long * pulMapRB, 00495 unsigned int uiXSize, unsigned int uiYSize, kz_pixel_t * pLUT) 00496 /* pImage - pointer to input/output image 00497 * uiXRes - resolution of image in x-direction 00498 * pulMap* - mappings of greylevels from histograms 00499 * uiXSize - uiXSize of image submatrix 00500 * uiYSize - uiYSize of image submatrix 00501 * pLUT - lookup table containing mapping greyvalues to bins 00502 * This function calculates the new greylevel assignments of pixels within a submatrix 00503 * of the image with size uiXSize and uiYSize. This is done by a bilinear interpolation 00504 * between four different mappings in order to eliminate boundary artifacts. 00505 * It uses a division; since division is often an expensive operation, I added code to 00506 * perform a logical shift instead when feasible. 00507 */ 00508 { 00509 const unsigned int uiIncr = uiXRes-uiXSize; /* Pointer increment after processing row */ 00510 kz_pixel_t GreyValue; unsigned int uiNum = uiXSize*uiYSize; /* Normalization factor */ 00511 00512 unsigned int uiXCoef, uiYCoef, uiXInvCoef, uiYInvCoef, uiShift = 0; 00513 00514 if (uiNum & (uiNum - 1)) /* If uiNum is not a power of two, use division */ 00515 for (uiYCoef = 0, uiYInvCoef = uiYSize; uiYCoef < uiYSize; 00516 uiYCoef++, uiYInvCoef--,pImage+=uiIncr) { 00517 for (uiXCoef = 0, uiXInvCoef = uiXSize; uiXCoef < uiXSize; 00518 uiXCoef++, uiXInvCoef--) { 00519 GreyValue = pLUT[*pImage]; /* get histogram bin value */ 00520 *pImage++ = (kz_pixel_t ) ((uiYInvCoef * (uiXInvCoef*pulMapLU[GreyValue] 00521 + uiXCoef * pulMapRU[GreyValue]) 00522 + uiYCoef * (uiXInvCoef * pulMapLB[GreyValue] 00523 + uiXCoef * pulMapRB[GreyValue])) / uiNum); 00524 } 00525 } 00526 else { /* avoid the division and use a right shift instead */ 00527 while (uiNum >>= 1) uiShift++; /* Calculate 2log of uiNum */ 00528 for (uiYCoef = 0, uiYInvCoef = uiYSize; uiYCoef < uiYSize; 00529 uiYCoef++, uiYInvCoef--,pImage+=uiIncr) { 00530 for (uiXCoef = 0, uiXInvCoef = uiXSize; uiXCoef < uiXSize; 00531 uiXCoef++, uiXInvCoef--) { 00532 GreyValue = pLUT[*pImage]; /* get histogram bin value */ 00533 *pImage++ = (kz_pixel_t)((uiYInvCoef* (uiXInvCoef * pulMapLU[GreyValue] 00534 + uiXCoef * pulMapRU[GreyValue]) 00535 + uiYCoef * (uiXInvCoef * pulMapLB[GreyValue] 00536 + uiXCoef * pulMapRB[GreyValue])) >> uiShift); 00537 } 00538 } 00539 } 00540 } 00541 // *****************************************************************************