uint32_t *resize_image(rgb32_t *in, int32_t old_w, int32_t old_h, int32_t new_w, int32_t new_h)
{
int32_t i, iy, ix, jy, jx; // iterators
int32_t jy_start, jy_stop, jx_start, jx_stop; // bounds for the iteration of pixels from the original image
rgb32_t *out; // new image
float pos_in_x, pos_in_y; // position of the new image pixel in the old image
float ratio_x, ratio_y; // downsampling ratio (< 1.0 means enlargement)
float radius_x, radius_y; // radius of the triangle from the projected point in original units
float weight; // global weight to apply to all weights, globally
float p_weight, p_weight_y; // local pixel weight
int32_t *p_weight_p = (int32_t *) &p_weight; // integer pointer to the float p_weight
int32_t *p_weight_yp = (int32_t *) &p_weight_y; // integer pointer to the float p_weight_y
float r, g, b;
ratio_x = (float) (old_w-1) / (float) (new_w-1); // resizing ratio
ratio_y = (float) (old_h-1) / (float) (new_h-1);
radius_x = ratio_x; // how far from the new pixel should we look for old pixels to weight and add
radius_y = ratio_y;
if (radius_x<1.f)
radius_x = 1.f; // if we upsample
if (radius_y<1.f) // keep the radius to 1 so that we catch all the 4 neighbouring original pixels
radius_y = 1.f;
weight = 1.f / (radius_x * radius_y); // product by which to weight to final sum for a pixel
out = calloc (new_w * new_h, sizeof(rgb32_t));
for (iy=0; iy<new_h; iy++)
{
pos_in_y = (float) iy * ratio_y; // position of the new pixel (iy) in the old array
jy_start = (int32_t) ceilf(pos_in_y - radius_y); // only start at the first pixel that comes after the new pixel minus its radius
if (jy_start < 0) // bounds checking
jy_start = 0;
jy_stop = (int32_t) ceilf(pos_in_y + radius_y); // stop at the last pixel before the new pixel + its radius
if (jy_stop >= old_h) // bounds checking
jy_stop = old_h - 1;
for (ix=0; ix<new_w; ix++)
{
pos_in_x = (float) ix * ratio_x; // position of the new pixel (ix) in the old array
jx_start = (int32_t) ceilf(pos_in_x - radius_x);
if (jx_start < 0)
jx_start = 0;
jx_stop = (int32_t) ceilf(pos_in_x + radius_x);
if (jx_stop >= old_w)
jx_stop = old_w - 1;
r = 0; // reset the values of the new interpolated pixels for each colour channel
g = 0;
b = 0;
weight = 0;
for (jy=jy_start; jy<jy_stop; jy++) // iteration through all the neighbouring pixels from the new interpolated pixel
{
p_weight_y = ((float) jy - pos_in_y) * (1.f/radius_y); // normalised distance of the original neighbouring pixel from the new pixel
*p_weight_yp &= 0x7FFFFFFF; // absolute value by binary masking (sets the sign to 0)
p_weight_y = 1.f - p_weight_y; // f(x) = 1 - x; <-- the formula for linear interpolation
for (jx=jx_start; jx<jx_stop; jx++)
{
p_weight = ((float) jx - pos_in_x) * (1.f/radius_x); // same thing as above in the X axis
*p_weight_p &= 0x7FFFFFFF; // absolute value by binary masking (sets the sign to 0)
p_weight = 1.f - p_weight;
p_weight *= p_weight_y; // we multiply the weights of each axis to obtain the 2D weight
weight += p_weight;
r += (float) in[jy*old_w + jx].r * p_weight; // we multiply each original pixel value by its weight
g += (float) in[jy*old_w + jx].g * p_weight; // and add it to the new value,
b += (float) in[jy*old_w + jx].b * p_weight; // for each channel
}
}
weight = 1.f/weight; // we do that to avoid having to do 3 divisions (1 div + 3 muls is faster than 3 divs, right?)
out[iy*new_w + ix].r = r * weight; // finally we weight the final sum and put it in the new image array
out[iy*new_w + ix].g = g * weight;
out[iy*new_w + ix].b = b * weight;
}
}
return (uint32_t *) out;
}
[Edited by - A_SN on October 13, 2008 9:06:42 PM]
Bilinear resizing - I fail at it
I wrote a function which purpose is to resize an using bilinear filtering/interpolation given its old dimensions and the new dimensions, regardless of the aspect ratio. I decided to try and get to same code working for both regular linear interpolation (upsizing) and linear filtering (when downsizing) for that reason, because while an axis can be upsized the other one can be simultaneously downsized.
It works well for downsizing, looks great and all right, and for upsizing it works OK until you realise it really looks like a bit of pre-smoothing + nearest neighbour interpolation. That puzzles me, I have no idea how it can make it look like it does a tad bit of blurring on the original image and then upsamples it with nearest neighbour interpolation. I would blame it on the way that I calculate the 'weight' variable, which works by adding the sum of each weight used for each of the 4 original neighbouring pixels for the calculation of each new interpolated pixel, however when I used a fixed 'weight' variable things are 'way wronger' than when I do it like this.
I'm kind of stumped that I would fail at doing something as simple as bilinear interpolation, but I just cannot see what's wrong with what I do, despite spending a whole day on trying to fix it, so I need help..
Thanks a lot in advance.
EDIT : Also, my code is a tad slow. Any thoughts on that? I could move to fixed point airthmetic when things work I guess, but I'm going to reuse the code anything for some float image resizing..
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement