void cvCLAdaptEqualize(const CvArr* srcarr, CvArr* dstarr, unsigned int xdivs, unsigned int ydivs, unsigned int bins, float limit, int range) { double min_val, max_val; unsigned char min, max; int type; IplImage sstub, *src = cvGetImage(srcarr, &sstub); IplImage dstub, *dst = cvGetImage(dstarr, &dstub); if ((src == NULL) || (dst == NULL)) CV_ERROR( CV_StsUnsupportedFormat, "NULL value passed as image to function" ); CV_CALL( type = cvGetElemType( src )); if( type != CV_8UC1 ) CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" ); CV_CALL( type = cvGetElemType( src )); if( type != CV_8UC1 ) CV_ERROR( CV_StsUnsupportedFormat, "Only 8uC1 images are supported" ); //if( !CV_ARE_SIZES_EQ( src, dst )) // Modified by Shervin Emami, 17Nov2010. if (src->width != dst->width || src->height != dst->height) CV_ERROR( CV_StsUnmatchedSizes, "src and dst images must be equal sizes" ); if (((xdivs < 2) || (xdivs > 16)) || ((ydivs < 2) || (ydivs > 16))) CV_ERROR( CV_StsBadFlag, "xdivs and ydivs must in range (MIN=2 MAX = 16)" ); if ((bins < 2) || (bins > 256)) CV_ERROR( CV_StsBadFlag, "bins must in range (MIN=2 MAX = 256)" ); // copy src to dst for in-place CLAHE. cvCopy(src, dst); // 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. // Also make sure the image is aligned to 8 pixels width, so that OpenCV won't add extra padding to the image. // Added by Shervin Emami, 17Nov2010. int enlarged = 0; int origW = dst->width; int origH = dst->height; IplImage *tmpDst = 0; if ((dst->width & (8-1)) || (dst->height & (8-1)) || (dst->width % xdivs) || (dst->height % ydivs)) { int newW = ((dst->width + 8-1) & -8); // Align to 8 pixels, so that widthStep hopefully equals width. newW = ((newW + xdivs-1) & -xdivs); // Also align for CLAHE. int newH = ((dst->height + ydivs-1) & -ydivs); //std::cout << "w=" << dst->width << ", h=" << dst->height << ". new w = " << newW << ", h = " << newH << std::endl; IplImage *enlargedDst = cvCreateImage(cvSize(newW, newH), dst->depth, dst->nChannels); cvResize(dst, enlargedDst, CV_INTER_CUBIC); //cvReleaseImage(&dst); tmpDst = dst; dst = enlargedDst; // Use the enlarged image instead of the original dst image. enlarged = 1; // signal that we need to shrink later! } // Check if OpenCV adds padding bytes on each row. Added by Shervin Emami, 17Nov2010. if (dst->width != dst->widthStep) CV_ERROR( CV_StsBadFlag, "dst->widthStep should be the same as dst->width. The IplImage has padding, so use a larger image." ); // check number of xdivs and ydivs is a multiple of image dimensions if (dst->width % xdivs) CV_ERROR( CV_StsBadFlag, "xdiv must be an integer multiple of image width " ); if (dst->height % ydivs) CV_ERROR( CV_StsBadFlag, "ydiv must be an integer multiple of image height " ); // get the min and max values of the image if (range == CV_CLAHE_RANGE_INPUT) { cvMinMaxLoc(dst, &min_val, &max_val); min = (unsigned char) min_val; max = (unsigned char) max_val; } else { min = 0; max = 255; } // call CLHAHE for in-place CLAHE //int rcode = CLAHE((kz_pixel_t*) (dst->imageData), (unsigned int) dst->width, (unsigned int) dst->height, (kz_pixel_t) min, (kz_pixel_t) max, (unsigned int) xdivs, (unsigned int) ydivs, (unsigned int) bins, (float) limit); //printf("RCODE %i\n", rcode); // If the dst image was enlarged to fit the alignment, then shrink it back now. // Added by Shervin Emami, 17Nov2010. if (enlarged) { //std::cout << "w=" << dst->width << ", h=" << dst->height << ". orig w=" << origW << ", h=" << origH << std::endl; cvResize(dst, tmpDst, CV_INTER_CUBIC); // Shrink the enlarged image back into the original dst image. cvReleaseImage(&dst); // Free the enlarged image. } }
void convert(uint8_t img[], int* nrows, int* ncols, int ldim) { int h, w, chrh, chrw; // h = *nrows; w = *ncols; // CLAHE(img, img, h, w, ldim, 8, 8, 2); // chrh = 16; chrw = 8; decimate(img, img, h, w, ldim, chrh, chrw); h = h/chrh; w = w/chrw; // CLAHE(img, img, h, w, w, 4, 8, 3); // pixel intensity quantization quantize(img, img, h, w, w); // *nrows = h; *ncols = w; }
SEXP clahe (SEXP x, SEXP _uiNrX, SEXP _uiNrY, SEXP _uiNrBins, SEXP _fCliplimit, SEXP _keepRange) { int nx, ny, nz, i, j; unsigned int uiNrX, uiNrY, uiNrBins; float fCliplimit; int keepRange; double *src, *tgt; SEXP res; kz_pixel_t min = 0, max = uiNR_OF_GREY-1; kz_pixel_t *img; double maxPixelValue = uiNR_OF_GREY-1; PROTECT( res = allocVector(REALSXP, XLENGTH(x)) ); DUPLICATE_ATTRIB(res, x); nx = INTEGER(GET_DIM(x))[0]; ny = INTEGER(GET_DIM(x))[1]; nz = getNumberOfFrames(x, 0); uiNrX = INTEGER(_uiNrX)[0]; uiNrY = INTEGER(_uiNrY)[0]; uiNrBins = INTEGER(_uiNrBins)[0]; fCliplimit = REAL(_fCliplimit)[0]; keepRange = LOGICAL(_keepRange)[0]; img = R_Calloc(nx*ny, kz_pixel_t); // process channels separately for(j = 0; j < nz; j++) { src = &(REAL(x)[j*nx*ny]); tgt = &(REAL(res)[j*nx*ny]); if (keepRange) { min = uiNR_OF_GREY-1; max = 0; } // convert frame to CLAHE-compatible format for (i = 0; i < nx*ny; i++) { double el = src[i]; // clip if (el < 0.0) el = 0; else if (el > 1.0) el = 1.0; // convert to int kz_pixel_t nel = (kz_pixel_t) round(el * maxPixelValue); if (keepRange) { if (nel < min) min = nel; if (nel > max) max = nel; } img[i] = nel; } int val = CLAHE (img, (unsigned int) nx, (unsigned int) ny, min, max, uiNrX, uiNrY, uiNrBins, fCliplimit); // translate internal error codes switch (val) { case -1: error("# of regions x-direction too large"); break; case -2: error("# of regions y-direction too large"); break; case -3: error("x-resolution no multiple of 'nx'"); break; case -4: error("y-resolution no multiple of 'ny'"); break; case -5: error("maximum too large"); break; case -6: error("minimum equal or larger than maximum"); break; case -7: error("at least 4 contextual regions required"); break; case -8: error("not enough memory! (try reducing 'bins')"); break; } // convert back to [0:1] range for (i = 0; i < nx*ny; i++) { tgt[i] = (double) img[i] / maxPixelValue; } } R_Free(img); UNPROTECT(1); return res; }