为了提高运行速度,把CLAHE的代码进行了修改,方便运行。
CLAHE.h
class CLAHE { public: CLAHE(void); ~CLAHE(void); int m_nGridX; /* CLAHE 宽网格的个数 */ int m_nGridY; /* CLAHE 高网格的个数 */ unsigned char m_aLUT[256]; /* CLAHE lookup table used for scaling of input image */ int Initial(int nMaxPixel, int nMinPixel, int uiNrBins, int nX, int nY, int nWidth, int nHeight,float fCliplimit); int m_nWidth; int m_nHeight; int m_nCliplimit; int m_nHistBins; int m_nGridSize_X; int m_nGridSize_Y; int *m_pMapArray; int m_nGridSize; /* Actual size of contextual regions */ int ProcessCLAHE(unsigned char* pImage); void MakeHistogram(unsigned char* pImage,int* pulHistogram); void ClipHistogram(int* pulHistogram); void MapHistogram(int* pulHistogram); void Interpolate (unsigned char * pImage); int m_nMaxPixel; int m_nMinPixel; void ShiftInterpolate(unsigned char* pImage, int nSizeX, int nSizeY, int* pulMapLU, int* pulMapRU, int *pulMapLB, int *pulMapRB); int LineInterpolate(unsigned char* pImage, int nSizeX, int nSizeY, int* pLU, int* pRU, int* pLB, int* pRB); };
CLAH.CPP
<pre name="code" class="cpp">const unsigned int uiMAX_REG_X = 16; /* max. # contextual regions in x-direction */ const unsigned int uiMAX_REG_Y = 16; /* max. # contextual regions in y-direction */ #define uiNR_OF_GREY (256) #define uiNR_OF_GREY (4096) CLAHE::CLAHE(void) : m_nGridX(0) , m_nGridY(0) , m_nWidth(0) , m_nHeight(0) , m_nCliplimit(0) , m_nHistBins(0) , m_nGridSize_X(0) , m_nGridSize_Y(0) , m_pMapArray(0) , m_nGridSize(0) , m_nMaxPixel(0) , m_nMinPixel(0) { } CLAHE::~CLAHE(void) { } int CLAHE::Initial(int nMaxPixel, int nMinPixel, int uiNrBins, int nX, int nY, int nWidth, int nHeight, float fCliplimit) { if (nX > uiMAX_REG_X) return -1; /* # of regions x-direction too large */ if (nY > uiMAX_REG_Y) return -2; /* # of regions y-direction too large */ if (nWidth % nX) return -3; /* x-resolution no multiple of uiNrX */ if (nHeight % nY) return -4; /* y-resolution no multiple of uiNrY */ if (nMaxPixel >= uiNR_OF_GREY) return -5; /* maximum too large */ if (nMinPixel >= nMaxPixel) return -6; /* minimum equal or larger than maximum */ if (nX < 2 || nY < 2) return -7; /* at least 4 contextual regions required */ if (fCliplimit == 1.0) return 0; /* is OK, immediately returns original image. */ if (uiNrBins == 0) uiNrBins = 128; /* default value when not specified */ /* Make lookup table for mapping of greyvalues */ int i; const unsigned char BinSize = (unsigned char)(1 + (nMaxPixel-nMinPixel)/uiNrBins); for (i=nMinPixel; i<=nMaxPixel; i++) m_aLUT[i] = (i-nMinPixel) / BinSize; m_nMinPixel = nMinPixel; m_nMaxPixel = nMaxPixel; m_nGridX = nX; m_nGridY = nY; m_nWidth = nWidth; m_nHeight = nHeight; m_nHistBins = uiNrBins; m_nGridSize_X = m_nWidth / m_nGridX; m_nGridSize_Y = m_nHeight / m_nGridY; m_nGridSize = m_nGridSize_X * m_nGridSize_Y; if(fCliplimit > 0.0) { /* Calculate actual cliplimit */ m_nCliplimit = fCliplimit * m_nGridSize / uiNrBins; m_nCliplimit = (m_nCliplimit < 1) ? 1: m_nCliplimit; } m_pMapArray=(int *)malloc(sizeof(int)*m_nGridX*m_nGridY*m_nHistBins); if (m_pMapArray == 0) return -8; /* Not enough memory! (try reducing uiNrBins) */ return 1; } int CLAHE::ProcessCLAHE(unsigned char* pImage) { int x,y; unsigned char* pImPointer; int *pulHist; int uiSubX, uiSubY; int uiXL, uiXR, uiYU, uiYB; /* auxiliary variables interpolation routine */ int * pulLU, *pulLB, *pulRU, *pulRB; /* auxiliary pointers interpolation */ /* Calculate greylevel mappings for each contextual region */ for (y=0,pImPointer=pImage; y<m_nGridY; y++) { for (x=0; x<m_nGridX; x++,pImPointer+=m_nGridSize_X) { pulHist = &m_pMapArray[m_nHistBins * (y * m_nGridX + x)]; MakeHistogram(pImPointer,pulHist); ClipHistogram(pulHist); MapHistogram(pulHist); } pImPointer += (m_nGridSize_Y-1) * m_nWidth; /* skip lines, set pointer */ } /* Interpolate greylevel mappings to get CLAHE image */ Interpolate (pImage); return 0; } void CLAHE::MakeHistogram(unsigned char* pImage,int* pulHistogram) { unsigned char* pImagePointer; int i; memset(pulHistogram, 0, sizeof(int) * m_nHistBins); /* clear histogram */ for (i=0; i<m_nGridSize_Y; i++) { pImagePointer = &pImage[m_nGridSize_X]; while (pImage < pImagePointer) pulHistogram[m_aLUT[*pImage++]]++; pImagePointer += m_nWidth; pImage = &pImagePointer[-m_nGridSize_X]; } } /* This function performs clipping of the histogram and redistribution of bins. * The histogram is clipped and the number of excess pixels is counted. Afterwards * the excess pixels are equally redistributed across the whole histogram (providing * the bin count is smaller than the cliplimit). */ void CLAHE::ClipHistogram(int* pulHistogram) { int* pulBinPointer, *pulEndPointer, *pulHisto; int ulNrExcess, ulUpper, ulBinIncr, ulStepSize, i; int lBinExcess; ulNrExcess = 0; pulBinPointer = pulHistogram; for (i = 0; i < m_nHistBins; i++) { /* calculate total number of excess pixels */ lBinExcess = pulBinPointer[i] - m_nCliplimit; if (lBinExcess > 0) ulNrExcess += lBinExcess; /* excess in current bin */ } /* Second part: clip histogram and redistribute excess pixels in each bin */ ulBinIncr = ulNrExcess / m_nHistBins; /* average binincrement */ ulUpper = m_nCliplimit - ulBinIncr; /* Bins larger than ulUpper set to cliplimit */ for (i=0; i<m_nHistBins; i++) { if (pulHistogram[i] > m_nCliplimit) pulHistogram[i] = m_nCliplimit; /* clip bin */ else { if (pulHistogram[i] > ulUpper) { /* high bin count */ ulNrExcess -= (pulHistogram[i] - ulUpper); pulHistogram[i]= m_nCliplimit; } else { /* low bin count */ ulNrExcess -= ulBinIncr; pulHistogram[i] += ulBinIncr; } } } while (ulNrExcess) { /* Redistribute remaining excess */ pulEndPointer = &pulHistogram[m_nHistBins]; pulHisto = pulHistogram; while (ulNrExcess && (pulHisto<pulEndPointer)) { ulStepSize = m_nHistBins / ulNrExcess; if (ulStepSize < 1) ulStepSize = 1; /* stepsize at least 1 */ for (pulBinPointer=pulHisto; pulBinPointer<pulEndPointer&&ulNrExcess; pulBinPointer += ulStepSize) { if (*pulBinPointer < m_nCliplimit) { (*pulBinPointer)++; ulNrExcess--; /* reduce excess */ } } pulHisto++; /* restart redistributing on other bin location */ } } } /* This function calculates the equalized lookup table (mapping) by * cumulating the input histogram. Note: lookup table is rescaled in range [Min..Max]. */ void CLAHE::MapHistogram(int* pulHistogram) { int i; long ulSum = 0; const float fScale = ((float)(m_nMaxPixel - m_nMinPixel)) / m_nGridSize; const long ulMin = (long)m_nMinPixel; for (i=0; i<m_nHistBins; i++) { ulSum += pulHistogram[i]; pulHistogram[i] = (long)(ulMin+ulSum*fScale); if (pulHistogram[i] > m_nMaxPixel) pulHistogram[i] = m_nMaxPixel; } } /* pImage - pointer to input/output image * This function calculates the new greylevel assignments of pixels within a submatrix * of the image with size uiXSize and uiYSize. This is done by a bilinear interpolation * between four different mappings in order to eliminate boundary artifacts. * It uses a division; since division is often an expensive operation, I added code to * perform a logical shift instead when feasible. */ void CLAHE:: Interpolate (unsigned char * pImage) { int x,y; int uiSubY,uiSubX,uiYU,uiYB,uiXL,uiXR; int *pulLU,*pulRU,*pulLB,*pulRB; unsigned char *pImPointer; //x,y都为0 pImPointer = pImage; uiSubY = m_nGridSize_Y>>1; uiSubX = m_nGridSize_X>>1; pulLU = &m_pMapArray[0]; pulRU = &m_pMapArray[0]; pulLB = &m_pMapArray[0]; pulRB = &m_pMapArray[0]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ //y为0 uiYU = 0; uiYB = 0; for (x=1; x<m_nGridX; x++) { uiSubX = m_nGridSize_X; uiXL = x - 1; uiXR = uiXL + 1; pulLU = &m_pMapArray[m_nHistBins * uiXL]; pulRU = &m_pMapArray[m_nHistBins * uiXR]; pulLB = &m_pMapArray[m_nHistBins * uiXL]; pulRB = &m_pMapArray[m_nHistBins * uiXR]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ } //y为0,x为m_nGridX uiSubX = m_nGridSize_X>>1; uiXL = m_nGridX - 1; uiXR = uiXL; pulLU = &m_pMapArray[m_nHistBins * uiXL]; pulRU = &m_pMapArray[m_nHistBins * uiXR]; pulLB = &m_pMapArray[m_nHistBins * uiXL]; pulRB = &m_pMapArray[m_nHistBins * uiXR]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ pImPointer += (uiSubY - 1) * m_nWidth; for (y=1; y<m_nGridY; y++) { uiSubY = m_nGridSize_Y; uiYU = y - 1; uiYB = uiYU + 1; //x为0 uiSubX = m_nGridSize_X >> 1; pulLU = &m_pMapArray[m_nHistBins * uiYU * m_nGridX]; pulRU = &m_pMapArray[m_nHistBins * uiYU * m_nGridX]; pulLB = &m_pMapArray[m_nHistBins * uiYB * m_nGridX]; pulRB = &m_pMapArray[m_nHistBins * uiYB * m_nGridX]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ for (x=1; x<m_nGridX; x++) { uiSubX = m_nGridSize_X; uiXL = x - 1; uiXR = uiXL + 1; pulLU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXL)]; pulRU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXR)]; pulLB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXL)]; pulRB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXR)]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ } uiSubX = m_nGridSize_X >> 1; uiXL = x - 1; uiXR = uiXL; pulLU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXL)]; pulRU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXR)]; pulLB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXL)]; pulRB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXR)]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ pImPointer += (uiSubY - 1) * m_nWidth; } //y为m_nGridY uiSubY = m_nGridSize_Y >> 1; uiYU = m_nGridY-1; uiYB = uiYU; //x为0 uiSubX = m_nGridSize_X >> 1; pulLU = &m_pMapArray[m_nHistBins * uiYU * m_nGridX]; pulRU = &m_pMapArray[m_nHistBins * uiYU * m_nGridX]; pulLB = &m_pMapArray[m_nHistBins * uiYB * m_nGridX]; pulRB = &m_pMapArray[m_nHistBins * uiYB * m_nGridX]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ for (x=1; x<m_nGridX; x++) { uiSubX = m_nGridSize_X; uiXL = x - 1; uiXR = uiXL + 1; pulLU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXL)]; pulRU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXR)]; pulLB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXL)]; pulRB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXR)]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ } uiSubX = m_nGridSize_X >> 1; uiXL = x - 1; uiXR = uiXL; pulLU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXL)]; pulRU = &m_pMapArray[m_nHistBins * (uiYU * m_nGridX + uiXR)]; pulLB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXL)]; pulRB = &m_pMapArray[m_nHistBins * (uiYB * m_nGridX + uiXR)]; LineInterpolate(pImPointer,uiSubX,uiSubY,pulLU,pulRU,pulLB,pulRB); pImPointer += uiSubX; /* set pointer on next matrix */ pImPointer += (uiSubY - 1) * m_nWidth; } void CLAHE::ShiftInterpolate(unsigned char* pImage, int nSizeX, int nSizeY, int* pulMapLU,int* pulMapRU, int *pulMapLB, int *pulMapRB) { const int uiIncr = m_nWidth-nSizeX; /* Pointer increment after processing row */ unsigned char GreyValue; int uiNum = nSizeX*nSizeY; int x, y, nInvX, nInvY, uiShift = 0; while (uiNum >>= 1) uiShift++; /* Calculate 2log of uiNum */ for (y=0,nInvY=nSizeY; y<nSizeY; y++,nInvY--,pImage+=uiIncr) { for (x=0, nInvX=nSizeX; x<nSizeX; x++,nInvX--) { GreyValue = m_aLUT[*pImage]; /* get histogram bin value */ *pImage++ = (unsigned char)((nInvY*(nInvX*pulMapLU[GreyValue] + x*pulMapRU[GreyValue]) + y*(nInvX*pulMapLB[GreyValue] + x*pulMapRB[GreyValue])) >> uiShift); } } } int CLAHE::LineInterpolate(unsigned char* pImage, int nSizeX, int nSizeY, int* pulMapLU,int* pulMapRU, int* pulMapLB, int* pulMapRB) { const int uiIncr = m_nWidth-nSizeX; /* Pointer increment after processing row */ unsigned char GreyValue; int uiNum = nSizeX*nSizeY; int x, y, nInvX, nInvY, uiShift = 0; for (y=0, nInvY=nSizeY; y<nSizeY; y++, nInvY--,pImage+=uiIncr) { for (x=0,nInvX=nSizeX; x<nSizeX; x++, nInvX--) { GreyValue = m_aLUT[*pImage]; /* get histogram bin value */ *pImage++ = (unsigned char) (( nInvY*(nInvX*pulMapLU[GreyValue] + x*pulMapRU[GreyValue]) + y * (nInvX*pulMapLB[GreyValue] + x*pulMapRB[GreyValue])) / uiNum); } } return 0; }