Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/tmoFattal02.cpp view on Meta::CPAN
dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x];
dst_pixel[x] /= 16;
}
// boundary mirroring
dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16;
dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16;
dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16;
dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16;
// next line
src_pixel += pitch;
dst_pixel += pitch;
}
// vertical convolution h_dib -> v_dib
src_pixel = (float*)FreeImage_GetBits(h_dib);
dst_pixel = (float*)FreeImage_GetBits(v_dib);
for(unsigned x = 0; x < width; x++) {
// work on column x
for(unsigned y = 2; y < height - 2; y++) {
const unsigned index = y*pitch + x;
dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index];
dst_pixel[index] /= 16;
}
// boundary mirroring
dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16;
dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16;
dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16;
dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16;
}
FreeImage_Unload(h_dib); h_dib = NULL;
// perform downsampling
dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR);
FreeImage_Unload(v_dib);
return dst;
} catch(int) {
if(h_dib) FreeImage_Unload(h_dib);
if(v_dib) FreeImage_Unload(v_dib);
if(dst) FreeImage_Unload(dst);
return NULL;
}
}
/**
Compute a Gaussian pyramid using the specified number of levels.
@param H Original bitmap
@param pyramid Resulting pyramid array
@param nlevels Number of resolution levels
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL GaussianPyramid(FIBITMAP *H, FIBITMAP **pyramid, int nlevels) {
try {
// first level is the original image
pyramid[0] = FreeImage_Clone(H);
if(pyramid[0] == NULL) throw(1);
// compute next levels
for(int k = 1; k < nlevels; k++) {
pyramid[k] = GaussianLevel5x5(pyramid[k-1]);
if(pyramid[k] == NULL) throw(1);
}
return TRUE;
} catch(int) {
for(int k = 0; k < nlevels; k++) {
if(pyramid[k] != NULL) {
FreeImage_Unload(pyramid[k]);
pyramid[k] = NULL;
}
}
return FALSE;
}
}
/**
Compute the gradient magnitude of an input image H using central differences,
and returns the average gradient.
@param H Input image
@param avgGrad [out] Average gradient
@param k Level number
@return Returns the gradient magnitude if successful, returns NULL otherwise
@see GradientPyramid
*/
static FIBITMAP* GradientLevel(FIBITMAP *H, float *avgGrad, int k) {
FIBITMAP *G = NULL;
try {
const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H);
if(image_type != FIT_FLOAT) throw(1);
const unsigned width = FreeImage_GetWidth(H);
const unsigned height = FreeImage_GetHeight(H);
G = FreeImage_AllocateT(image_type, width, height);
if(!G) throw(1);
const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float);
const float divider = (float)(1 << (k + 1));
float average = 0;
float *src_pixel = (float*)FreeImage_GetBits(H);
float *dst_pixel = (float*)FreeImage_GetBits(G);
for(unsigned y = 0; y < height; y++) {
const unsigned n = (y == 0 ? 0 : y-1);
const unsigned s = (y+1 == height ? y : y+1);
for(unsigned x = 0; x < width; x++) {
const unsigned w = (x == 0 ? 0 : x-1);
const unsigned e = (x+1 == width ? x : x+1);
// central difference
const float gx = (src_pixel[y*pitch+e] - src_pixel[y*pitch+w]) / divider; // [Hk(x+1, y) - Hk(x-1, y)] / 2**(k+1)
const float gy = (src_pixel[s*pitch+x] - src_pixel[n*pitch+x]) / divider; // [Hk(x, y+1) - Hk(x, y-1)] / 2**(k+1)
// gradient
dst_pixel[x] = sqrt(gx*gx + gy*gy);
src/Source/FreeImage/tmoFattal02.cpp view on Meta::CPAN
}
}
/**
Calculate gradient magnitude and its average value on each pyramid level
@param pyramid Gaussian pyramid (nlevels levels)
@param nlevels Number of levels
@param gradients [out] Gradient pyramid (nlevels levels)
@param avgGrad [out] Average gradient on each level (array of size nlevels)
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL GradientPyramid(FIBITMAP **pyramid, int nlevels, FIBITMAP **gradients, float *avgGrad) {
try {
for(int k = 0; k < nlevels; k++) {
FIBITMAP *Hk = pyramid[k];
gradients[k] = GradientLevel(Hk, &avgGrad[k], k);
if(gradients[k] == NULL) throw(1);
}
return TRUE;
} catch(int) {
for(int k = 0; k < nlevels; k++) {
if(gradients[k] != NULL) {
FreeImage_Unload(gradients[k]);
gradients[k] = NULL;
}
}
return FALSE;
}
}
/**
Compute the gradient attenuation function PHI(x, y)
@param gradients Gradient pyramid (nlevels levels)
@param avgGrad Average gradient on each level (array of size nlevels)
@param nlevels Number of levels
@param alpha Parameter alpha in the paper
@param beta Parameter beta in the paper
@return Returns the attenuation matrix Phi if successful, returns NULL otherwise
*/
static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) {
float *src_pixel, *dst_pixel;
FIBITMAP **phi = NULL;
try {
phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*));
if(!phi) throw(1);
memset(phi, 0, nlevels * sizeof(FIBITMAP*));
for(int k = nlevels-1; k >= 0; k--) {
// compute phi(k)
FIBITMAP *Gk = gradients[k];
const unsigned width = FreeImage_GetWidth(Gk);
const unsigned height = FreeImage_GetHeight(Gk);
const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float);
// parameter alpha is 0.1 times the average gradient magnitude
// also, note the factor of 2**k in the denominator;
// that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels
// in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk.
float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k);
if(ALPHA == 0) ALPHA = EPSILON;
phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height);
if(!phi[k]) throw(1);
src_pixel = (float*)FreeImage_GetBits(Gk);
dst_pixel = (float*)FreeImage_GetBits(phi[k]);
for(unsigned y = 0; y < height; y++) {
for(unsigned x = 0; x < width; x++) {
// compute (alpha / grad) * (grad / alpha) ** beta
const float v = src_pixel[x] / ALPHA;
const float value = (float)pow((float)v, (float)(beta-1));
dst_pixel[x] = (value > 1) ? 1 : value;
}
// next line
src_pixel += pitch;
dst_pixel += pitch;
}
if(k < nlevels-1) {
// compute PHI(k) = L( PHI(k+1) ) * phi(k)
FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR);
if(!L) throw(1);
src_pixel = (float*)FreeImage_GetBits(L);
dst_pixel = (float*)FreeImage_GetBits(phi[k]);
for(unsigned y = 0; y < height; y++) {
for(unsigned x = 0; x < width; x++) {
dst_pixel[x] *= src_pixel[x];
}
// next line
src_pixel += pitch;
dst_pixel += pitch;
}
FreeImage_Unload(L);
// PHI(k+1) is no longer needed
FreeImage_Unload(phi[k+1]);
phi[k+1] = NULL;
}
// next level
}
// get the final result and return
FIBITMAP *dst = phi[0];
free(phi);
return dst;
} catch(int) {
if(phi) {
for(int k = nlevels-1; k >= 0; k--) {
if(phi[k]) FreeImage_Unload(phi[k]);
}
free(phi);
}
( run in 1.452 second using v1.01-cache-2.11-cpan-5623c5533a1 )