Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

soconne

Bicubic Interpolation for Image Resizing

This topic is 5208 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Does anybody have any good urls showing code for resizing image s using Bicubic Interpolation? Or at least a site that explains it well?

Share this post


Link to post
Share on other sites
Advertisement
Well I found an explanation for bicubic interpolation here http://astronomy.swin.edu.au/~pbourke/colour/bicubic/

and I''ve implemented it, but it does not seem to be working. I tried it on a single 2x2 image, with the 4 pixel values of Red,Blue,Yellow, and Green, and after enlarging the 2x2 image to an 8x8 image, it simply had a faded dark red in the upper left and then diagnolly down to the right was a darker red, then every other pixel was black.

Can anybody help me with my code?

code

Share this post


Link to post
Share on other sites


uint Interpolate_Value(uint v0, uint v1, uint v2, uint v3, float t)
{
int p = (v3 - v2) - (v0 - v1);
int q = (v0 - v1) - p;
int r = v2 - v0;
int s = v1;
float tSqrd = t * t;
//
return (p * (tSqrd * t)) + (q * tSqrd) + (r * t) + s;
//return (p * (tSqrd * t) + 0.5f) + (q * tSqrd + 0.5f) + (r * t + 0.5f) + s; // Use this one for nicer interpolation, it rounds instead of truncates.
}
//
// To interpolate a pixel we need to interpolate each color component seperately
//
ARGB Interpolate_Pixel(ARGB p0, ARGB p1, ARGB p2, ARGB p3, float t)
{
return InterpolateValue(p0.a, p1.a, p2.a, p3.a, t) << 24 |
InterpolateValue(p0.r, p1.r, p2.r, p3.r, t) << 16 |
InterpolateValue(p0.g, p1.g, p2.g, p3.g, t) << 08 |
InterpolateValue(p0.b, p1.b, p2.b, p3.b, t);
}
//
//
//
Resize_Image(ARGB *Image, uint Width, uint Height, uint NewWidth, uint NewWidth, ARGB *NewImage)
{
uint OldImageX, OldImageY;
float dx = Width / NewWidth, dy = Height / NewHeight;
ARGB Temp[4];
//
//
for (y = 0; y < NewHeight; ++y)
{
OldImageY = dy * y;
ty = dy * y - OldImageY;
//
for (x = 0; x < NewWidth; ++x)
{
OldImageX = dx * x;
tx = dx * x - OldImageX;
//
// I don't know how image scaling works with regards to edges
// e.g. when OldImageX is 0 and you need pixels from behind (OldImageX - 1) you can either wrap around and get pixels to sample from the other side of the image (OldImageX = Width - 1)
// or you can just clamp to the edge (if (OldImageX - 1 < 0) OldImageX = 0), your choice, see what looks best.
// Likewise for when OldImageX == Width - 1 and you need to get OldImageX + 1
//
// To interpolate 2D data correctly we first interpolate 4 pixels horizontally for each of 4 scanlines, which leaves us with 4 new pixels
//
Temp[0] = Interpolate_Pixel(Image[(OldImageY - 1) * Width + OldImageX - 1],
Image[(OldImageY - 1) * Width + OldImageX],
Image[(OldImageY - 1) * Width + OldImageX + 1],
Image[(OldImageY - 1) * Width + OldImageX + 2],
tx);
Temp[1] = Interpolate_Pixel(Image[OldImageY * Width + OldImageX - 1],
Image[OldImageY * Width + OldImageX],
Image[OldImageY * Width + OldImageX + 1],
Image[OldImageY * Width + OldImageX + 2],
tx);
Temp[2] = Interpolate_Pixel(Image[(OldImageY + 1) * Width + OldImageX - 1],
Image[(OldImageY + 1) * Width + OldImageX],
Image[(OldImageY + 1) * Width + OldImageX + 1],
Image[(OldImageY + 1) * Width + OldImageX + 2],
tx);
Temp[3] = Interpolate_Pixel(Image[(OldImageY + 2) * Width + OldImageX - 1],
Image[(OldImageY + 2) * Width + OldImageX],
Image[(OldImageY + 2) * Width + OldImageX + 1],
Image[(OldImageY + 2) * Width + OldImageX + 2],
tx);
//
// Then we interpolate those 4 pixels to get a single pixel that is a composite of 4 * 4 pixels, 16 pixels
NewImage[y * NewWidth + x] = Interpolate_Pixel(Temp[0], Temp[1], Temp[2], Temp[3], ty);
}
}
}



Note that it contains a bit of pseudo-code, but I hope you understand. Note the caveats. You can do a lot of optimization, but for clarity I skipped most of it, you can obviously reuse some of the values instead of recalculating them. I haven't tested it, but if anyone spots something amiss feel free to jump in and correct it.

Arghhh.. better code parsing plz. x_x

------------
- outRider -

[edited by - outRider on June 5, 2004 4:26:54 PM]

Share this post


Link to post
Share on other sites
Bicubic. Bilinear would sample the nearest 4 pixels, bicubic samples the nearest 16.

------------
- outRider -

[edited by - outRider on June 5, 2004 4:28:05 PM]

Share this post


Link to post
Share on other sites
I tried implementing your code, but I still got very odd results. Here's the 8x8 image I was enlarging to a 32x32, and the result of what happened after enlarging.

8x8 image


32x32 image



I pretty much tried to copy your code piece by piece, although I had to convert it over to using char instead of int for the pixel data. But other than that, it is identical.

CODE

Any ideas ?

[edited by - oconnellseanm on June 5, 2004 5:55:49 PM]

Share this post


Link to post
Share on other sites
Yeah, I just tested it myself and noticed I forgot to clamp the values in the 0-255 range in InterpolateValue(). Cubic interpolation can overflow or underflow, so you have to either clamp or rescale all your values.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!