/// <summary> /// processes incoming image /// </summary> /// <returns>error code, refer to AL_XXX codes</returns> /// <remarks> /// working parallel code with single loop, using Win32 events to protect data dependecies across vertical blocks /// [Filter processing of full resolution image] in [1.131 seconds] /// </remarks> int CParallelEventAltaLuxFilter::Run() { if (ClipLimit == 1.0) return AL_OK; //< is OK, immediately returns original image PixelType *pImage = (PixelType *)ImageBuffer; /// pulMapArray is pointer to mappings unsigned int *pulMapArray = new unsigned int[NumHorRegions * NumVertRegions * NUM_GRAY_LEVELS]; if (pulMapArray == 0) return AL_OUT_OF_MEMORY; //< not enough memory /// region pixel count unsigned int NumPixels = (unsigned int)RegionWidth * (unsigned int)RegionHeight; //< region pixel count unsigned int ulClipLimit; //< clip limit if (ClipLimit > 0.0) { /// calculate actual cliplimit ulClipLimit = (unsigned int) (ClipLimit * (RegionWidth * RegionHeight) / NUM_GRAY_LEVELS); ulClipLimit = (ulClipLimit < 1UL) ? 1UL : ulClipLimit; } else ulClipLimit = 1UL<<14; //< large value, do not clip (AHE) /// Interpolate greylevel mappings to get CLAHE image // create events for signaling that the first phase is completed HANDLE FirstPhaseCompleted[MAX_VERT_REGIONS]; for (int i = 0; i < NumVertRegions; i++) FirstPhaseCompleted[i] = CreateEvent( NULL, // default security attributes TRUE, // manual-reset event FALSE, // initial state is nonsignaled NULL // object name ); concurrency::parallel_for((int)0, (int)(NumVertRegions + 1), [&](int uiY) { // first half PixelType* pImPointer = pImage; if (uiY > 0) pImPointer += ((RegionHeight >> 1) + ((uiY - 1) * RegionHeight)) * OriginalImageWidth; if (uiY < NumVertRegions) { /// calculate greylevel mappings for each contextual region for (unsigned int uiX = 0; uiX < NumHorRegions; uiX++, pImPointer += RegionWidth) { unsigned int *pHistogram = &pulMapArray[NUM_GRAY_LEVELS * (uiY * NumHorRegions + uiX)]; MakeHistogram(pImPointer, pHistogram); ClipHistogram(pHistogram, ulClipLimit); MapHistogram(pHistogram, NumPixels); } } // signal that the first phase is completed for this horizontal block if (uiY < NumVertRegions) SetEvent(FirstPhaseCompleted[uiY]); // wait for completion of first phase of the previous horizontal block if (uiY > 0) DWORD dwWaitResult = WaitForSingleObject(FirstPhaseCompleted[uiY-1], INFINITE); // second half unsigned int uiSubX, uiSubY; //< size of subimages unsigned int uiXL, uiXR, uiYU, uiYB; //< auxiliary variables interpolation routine pImPointer = pImage; if (uiY > 0) pImPointer += ((RegionHeight >> 1) + ((uiY - 1) * RegionHeight)) * OriginalImageWidth; if (uiY == 0) { /// special case: top row uiSubY = RegionHeight >> 1; uiYU = 0; uiYB = 0; } else { if (uiY == NumVertRegions)
/************************** main function CLAHE ******************/ static int CLAHE (kz_pixel_t* pImage, unsigned int uiXRes, unsigned int uiYRes, kz_pixel_t Min, kz_pixel_t Max, unsigned int uiNrX, unsigned int uiNrY, unsigned int uiNrBins, float fCliplimit) /* pImage - Pointer to the input/output image * uiXRes - Image resolution in the X direction * uiYRes - Image resolution in the Y direction * Min - Minimum greyvalue of input image (also becomes minimum of output image) * Max - Maximum greyvalue of input image (also becomes maximum of output image) * uiNrX - Number of contextial regions in the X direction (min 2, max uiMAX_REG_X) * uiNrY - Number of contextial regions in the Y direction (min 2, max uiMAX_REG_Y) * uiNrBins - Number of greybins for histogram ("dynamic range") * float fCliplimit - Normalized cliplimit (higher values give more contrast) * The number of "effective" greylevels in the output image is set by uiNrBins; selecting * a small value (eg. 128) speeds up processing and still produce an output image of * good quality. The output image will have the same minimum and maximum value as the input * image. A clip limit smaller than 1 results in standard (non-contrast limited) AHE. */ { unsigned int uiX, uiY; /* counters */ unsigned int uiXSize, uiYSize, uiSubX, uiSubY; /* size of context. reg. and subimages */ unsigned int uiXL, uiXR, uiYU, uiYB; /* auxiliary variables interpolation routine */ unsigned long ulClipLimit, ulNrPixels;/* clip limit and region pixel count */ kz_pixel_t* pImPointer; /* pointer to image */ kz_pixel_t aLUT[uiNR_OF_GREY]; /* lookup table used for scaling of input image */ unsigned long* pulHist, *pulMapArray; /* pointer to histogram and mappings*/ unsigned long* pulLU, *pulLB, *pulRU, *pulRB; /* auxiliary pointers interpolation */ if (uiNrX > uiMAX_REG_X) return -1; /* # of regions x-direction too large */ if (uiNrY > uiMAX_REG_Y) return -2; /* # of regions y-direction too large */ if (uiXRes % uiNrX) return -3; /* x-resolution no multiple of uiNrX */ if (uiYRes % uiNrY) return -4; /* y-resolution no multiple of uiNrY #TPB FIX */ #ifndef BYTE_IMAGE /* #TPB FIX */ if (Max >= uiNR_OF_GREY) return -5; /* maximum too large */ #endif if (Min >= Max) return -6; /* minimum equal or larger than maximum */ if (uiNrX < 2 || uiNrY < 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 */ pulMapArray=(unsigned long *)malloc(sizeof(unsigned long)*uiNrX*uiNrY*uiNrBins); if (pulMapArray == 0) return -8; /* Not enough memory! (try reducing uiNrBins) */ uiXSize = uiXRes/uiNrX; uiYSize = uiYRes/uiNrY; /* Actual size of contextual regions */ ulNrPixels = (unsigned long)uiXSize * (unsigned long)uiYSize; if(fCliplimit > 0.0) { /* Calculate actual cliplimit */ ulClipLimit = (unsigned long) (fCliplimit * (uiXSize * uiYSize) / uiNrBins); ulClipLimit = (ulClipLimit < 1UL) ? 1UL : ulClipLimit; } else ulClipLimit = 1UL<<14; /* Large value, do not clip (AHE) */ MakeLut(aLUT, Min, Max, uiNrBins); /* Make lookup table for mapping of greyvalues */ /* Calculate greylevel mappings for each contextual region */ for (uiY = 0, pImPointer = pImage; uiY < uiNrY; uiY++) { for (uiX = 0; uiX < uiNrX; uiX++, pImPointer += uiXSize) { pulHist = &pulMapArray[uiNrBins * (uiY * uiNrX + uiX)]; MakeHistogram(pImPointer,uiXRes,uiXSize,uiYSize,pulHist,uiNrBins,aLUT); ClipHistogram(pulHist, uiNrBins, ulClipLimit); MapHistogram(pulHist, Min, Max, uiNrBins, ulNrPixels); } pImPointer += (uiYSize - 1) * uiXRes; /* skip lines, set pointer */ } /* Interpolate greylevel mappings to get CLAHE image */ for (pImPointer = pImage, uiY = 0; uiY <= uiNrY; uiY++) { if (uiY == 0) { /* special case: top row */ uiSubY = uiYSize >> 1; uiYU = 0; uiYB = 0; } else { if (uiY == uiNrY) { /* special case: bottom row */
/// <summary> /// processes incoming image /// </summary> /// <returns>error code, refer to AL_XXX codes</returns> /// <remarks> /// working parallel code with single loop, using active waits to protect data dependencies /// [Filter processing of full resolution image] in [1.131 seconds] /// </remarks> int CParallelActiveWaitAltaLuxFilter::Run() { if (ClipLimit == 1.0) return AL_OK; //< is OK, immediately returns original image PixelType *pImage = (PixelType *)ImageBuffer; /// pulMapArray is pointer to mappings unsigned int *pulMapArray = new unsigned int[NumHorRegions * NumVertRegions * NUM_GRAY_LEVELS]; if (pulMapArray == 0) return AL_OUT_OF_MEMORY; //< not enough memory /// region pixel count unsigned int NumPixels = (unsigned int)RegionWidth * (unsigned int)RegionHeight; //< region pixel count unsigned int ulClipLimit; //< clip limit if (ClipLimit > 0.0) { /// calculate actual cliplimit ulClipLimit = (unsigned int) (ClipLimit * (RegionWidth * RegionHeight) / NUM_GRAY_LEVELS); ulClipLimit = (ulClipLimit < 1UL) ? 1UL : ulClipLimit; } else ulClipLimit = 1UL<<14; //< large value, do not clip (AHE) /// Interpolate greylevel mappings to get CLAHE image // create events for signaling that the first phase is completed __declspec(align(32)) volatile LONG FirstPhaseCompleted[MAX_VERT_REGIONS+1]; for (int i = 0; i <= NumVertRegions; i++) InterlockedExchange((volatile LONG*)&FirstPhaseCompleted[i], -1); concurrency::parallel_for((LONG)0, (LONG)(NumVertRegions + 1), [&](LONG uiY) { // first half PixelType* pImPointer = pImage; if (uiY > 0) pImPointer += ((RegionHeight >> 1) + ((uiY - 1) * RegionHeight)) * OriginalImageWidth; if (uiY < NumVertRegions) { /// calculate greylevel mappings for each contextual region for (LONG uiX = 0; uiX < NumHorRegions; uiX++, pImPointer += RegionWidth) { unsigned int *pHistogram = &pulMapArray[NUM_GRAY_LEVELS * (uiY * NumHorRegions + uiX)]; MakeHistogram(pImPointer, pHistogram); ClipHistogram(pHistogram, ulClipLimit); MapHistogram(pHistogram, NumPixels); InterlockedExchange((volatile LONG*) &FirstPhaseCompleted[uiY], uiX); } } // second half unsigned int uiSubX, uiSubY; //< size of subimages unsigned int uiXL, uiXR, uiYU, uiYB; //< auxiliary variables interpolation routine pImPointer = pImage; if (uiY > 0) pImPointer += ((RegionHeight >> 1) + ((uiY - 1) * RegionHeight)) * OriginalImageWidth; if (uiY == 0) { /// special case: top row uiSubY = RegionHeight >> 1; uiYU = 0; uiYB = 0; } else {