Jump to content
  • Advertisement
Sign in to follow this  
Basiror

bicubic interpolation on image enlargements

This topic is 2107 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

Hi I am trying to implement a few image resizing algorithms into my library I know how bicubic reducing works you calculate the destination pixel from the bicubic weights of a 4x4 pixel field around the nearest pixel coordinate in the source image [a href="http://astronomy.swin.edu.au/~pbourke/colour/bicubic/"]becubic interpolation[/a] my problem is how can i enlarge the image e.g.: having a 32*32 image and scale it to 256*256 in order to enlarge i would calculate the 4x4 pixel values out of the 32*32 image and write them to the 256*256 image but in order to do this i hade to interatively rescale 32*32->64*64->128*128->256*256 or is there a simpler solution e.g.: when i downscale i use a 4x4 field so 64*64->32*32 using 4x4 and 256x256->32*32 using a 64x64 field? so i had to distribute one pixel of the 32*32 image to a 64x64 field in the 256*256 image? any idea on how to do this correctly?

Share this post


Link to post
Share on other sites
Advertisement
Hi,

you "just" oversample the pickture.

so to go from 32*32 to 256*128 (this is to show you it could be done this way)


dx = 32 / 256;
dy = 32 / 128;

for(int y=0; y < 128; y++)
{
for(int x=0; x < 256; x++)
{
float ix = x*dx;
float iy = y*dy;
float s = ix - (float)((int)(ix+.5));
float t = iy - (float)((int)(iy+.5));
int ox = (int)ix;
int oy = (int)oy;

new_pic[y*256+x] = orig_pic[oy*32+ox]*(1-s)*(1-t)
+ orig_pic[(oy+1)*32+ox]*(1-s)*t
+ orig_pic[oy*32+ox+1]*s*(1-t)
+ orig_pic[(oy+1)*32+ox+1]*s*t;
}
}


Share this post


Link to post
Share on other sites
isn t this the bilinear approach?


i just found this link on google
http://www.inq7.net/inf/2003/jun/10/inf_37-2.htm

there they mention SI(staired interpolation which is basically what I mentioned above with 32*32->64*64->128*128->256*256

so maybe I should implement it like that

thx

Share this post


Link to post
Share on other sites
just think of it as a texture mapping problem, use bilinear interpolation to smooth it out, if this is giving to blocky results you can smooth further by bluring the input image b4 you do it.

Share this post


Link to post
Share on other sites
the problem with bluring is that I want to use it for a heightfield generator
and too blurry heightmaps don t look that good

i just try the SI approach now maybe it delivers acceptable results

Share this post


Link to post
Share on other sites
I am still having problems to get this implementation of cubic interpolation to run

I used this article as a basis for the implementation

http://astronomy.swin.edu.au/~pbourke/colour/bicubic/

What I am doing:
1. I calculate the factor sourcesize/destinationsize (images are powers of 2)
2. I loop through the destination coordinates and calculate the corresponding source coordinates "i*fact" & "j*fact"
3.then I find the nearest neightbour pixel and calculate the deltas dx & dy

4. I map the is and js to the source coordinates
5. I loop through the 4x4 field of neighbouring pixes in the source image and try to add them to the destination pixel
the cubicweight function should return the blend factors for each neighbouring pixel but all it does is returning 0s i have already tries to use
"dy - n" and "n - dy" nothing changed though

any idea what's wrong here?
Addition:
In the time gamedev.net has been down I was able to get it to work for downsampling and in comparsion to photoshop the results are at least 10-20x sharper :)

Now all I can t get to work is up sampling, can I use this method for upsampling at all?
or do you just take the source pixels calculate the destination coordinate and write to the current source pixel (i,j) to the destinationpixel (id,jd) +=(i,j)*bicubicweight(parameters...)?




[source lang ="cpp"]
//sample image up( powers of 2)
template<class U, class W> void samplebicubic(const U& s, W& d)
{
uint32 i,j;
int32 is,js,m,n;
float x,y,fact,dx,dy;
float test;

fact = U::MAP_SIZE/ W::MAP_SIZE;

for(i=0;i<W::MAP_SIZE;i++)
{
//calculate source coordinates
x = i * fact;
is = static_cast<int32>(x);
dx = x - is;
is = (is + W::MAP_SIZE)%W::MAP_SIZE;

for(j=0;j<W::MAP_SIZE;j++)
{
//calculate source coordinates
y = j * fact;
js = static_cast<int32>(y);
dy = y - js;
js = (js + W::MAP_SIZE)%W::MAP_SIZE;

d.m_Map[j] = 0.0f;
for(m=-1;m<3;m++)
{
for(n=-1;n<3;n++)
{
test = cubicweight(m-dx) * cubicweight(n-dy);
d.m_Map[j] += s.m_Map[(is + m + U::MAP_SIZE)%U::MAP_SIZE][(js + n + U::MAP_SIZE)%U::MAP_SIZE]
*test;
}
}
}
}
};






cubic weight function from the article


//cubic weight function
float cubicweight(float x)
{
float result;
float tmp;

//P(x+2)^3
tmp = (x+2)>0?x+2:0;
result = tmp*tmp*tmp;


//-4*P(x+1)^3
tmp = (x+1)>0?x+1:0;
result += -4*tmp*tmp*tmp;

//6*P(x)^3
tmp = x>0?x:0;
result += 6*tmp*tmp*tmp;

//-4P(x-1)^3
tmp = (x-1)>0?x-1:0;
result += -4*tmp*tmp*tmp;

result*=0.1666666f;
return result;
};





[Edited by - Basiror on August 5, 2005 6:32:38 AM]

Share this post


Link to post
Share on other sites
If you know how to linearly interpolate from 32,32 to 256,256 then you can do it using cubic, cosine, any other method that uses t from 0 to 1 as a parameter.

For linear interpolation you have

lerp(x,y,t)

to return a value between x and y based on t.

For cubic you have

cubic(a,b,c,d,t)

to return a value between b and c based on t.

Share this post


Link to post
Share on other sites
If you're using it for heightfield resizing, and you want "more detail" and don't care whether it's perfect or not, you could try introducing fractal noise to generate some bumpy looking terrain in the expansion gaps.

You can probably look up "Fractal random heightfield generator" in google and find the algorithm that produces random mountains without any source bitmap... and just modify it so that it works to fill in expansion gaps instead.

Share this post


Link to post
Share on other sites
I am still having trouble with the bicubic interpolation

i have 2 functions now
one with cubic interpolation and one with b spline cubic interpolation
the first function delivers results comparable with bilinear interpolation
and the second function which uses b splines delivers smoother results than photoshops implementation



here the cubic function:
i get the coordinates in the source image

then i calculate the weights of 4 pixels in a column

and once this is done i calculate the weighted value of the 4 weights
illustrated here

http://www.olympusmicro.com/primer/java/digitalimaging/processing/geometricaltransformation/
any idea what i am doing wrong here?

do i need another interpolation factor or whats wrong here?



//sample image up( powers of 2)
template<class U, class W> void sample_bicubic2(const U& s, W& d)
{
uint32 i,j;
int32 is,js;
float x,y,fact,dx,dy;
int32 XCoords[4];
int32 YCoords[4];
float weights[4];

fact = static_cast<float>(U::MAP_SIZE)/ static_cast<float>(W::MAP_SIZE);

for(i=0;i<W::MAP_SIZE;i++)
{
//calculate source coordinates
x = i * fact;
is = static_cast<int32>(x);
dx = x - is;

XCoords[0] = is-1;
XCoords[1] = is;
XCoords[2] = is+1;
XCoords[3] = is+2;

for(j=0;j<W::MAP_SIZE;j++)
{
//calculate source coordinates
y = j * fact;
js = static_cast<int32>(y);
dy = y - js;

YCoords[0] = js-1;
YCoords[1] = js;
YCoords[2] = js+1;
YCoords[3] = js+2;

weights[0] = cubicweight2(
s.m_Map[(XCoords[0] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[0] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[0] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[1] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[0] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[2] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[0] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[3] + U::MAP_SIZE)%U::MAP_SIZE],
0.5f);

weights[1] = cubicweight2(
s.m_Map[(XCoords[1] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[0] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[1] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[1] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[1] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[2] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[1] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[3] + U::MAP_SIZE)%U::MAP_SIZE],
0.5f);

weights[2] = cubicweight2(
s.m_Map[(XCoords[2] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[0] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[2] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[1] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[2] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[2] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[2] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[3] + U::MAP_SIZE)%U::MAP_SIZE],
0.5f);
weights[3] = cubicweight2(
s.m_Map[(XCoords[3] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[0] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[3] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[1] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[3] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[2] + U::MAP_SIZE)%U::MAP_SIZE],
s.m_Map[(XCoords[3] + U::MAP_SIZE)%U::MAP_SIZE][(YCoords[3] + U::MAP_SIZE)%U::MAP_SIZE],
0.5f);

d.m_Map[j] = cubicweight2(weights[0],weights[1],weights[2],weights[3],0.5f);
}
}
};



and here with b splines


//sample image up( powers of 2)
template<class U, class W> void sample_bicubic(const U& s, W& d)
{
uint32 i,j;
int32 is,js,m,n;
float x,y,fact,dx,dy;
float test;

fact = static_cast<float>(U::MAP_SIZE)/ static_cast<float>(W::MAP_SIZE);

for(i=0;i<W::MAP_SIZE;i++)
{
//calculate source coordinates
x = i * fact;
is = static_cast<int32>(x);
dx = x - is;
//is = (is + W::MAP_SIZE)%W::MAP_SIZE;

for(j=0;j<W::MAP_SIZE;j++)
{
//calculate source coordinates
y = j * fact;
js = static_cast<int32>(y);
dy = y - js;
//js = (js + W::MAP_SIZE)%W::MAP_SIZE;

d.m_Map[j] = 0.0f;
for(m=-1;m<3;m++)
{
test = cubicweight(dx-m);
for(n=-1;n<3;n++)
{

d.m_Map[j] += s.m_Map[(is + m + U::MAP_SIZE)%U::MAP_SIZE][(js + n + U::MAP_SIZE)%U::MAP_SIZE]
*test* cubicweight(dy-n);;
//std::cout<<std::endl;
}

}
}
}
};
//cubic weight function
float cubicweight(float x)
{
float result;
float tmp;

//P(x+2)^3
tmp = (x+2)>0?x+2:0;
result = tmp*tmp*tmp;


//-4*P(x+1)^3
tmp = (x+1)>0?x+1:0;
result += -4*tmp*tmp*tmp;

//6*P(x)^3
tmp = x>0?x:0;
result += 6*tmp*tmp*tmp;

//-4P(x-1)^3
tmp = (x-1)>0?x-1:0;
result += -4*tmp*tmp*tmp;

result*=0.1666666f;
return result;
};

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!