As I posted before I was looking for a bicubic resize algorithm for images to be used in Silverlight. I thought I ported the code properly from C# to VB but then yesterday when I was testing the code some more, I realized that there was a weird pattern of noise present in the picture. It looked like a square grid of sorts being overlaid onto the image. My experience told me that, that's because something screwed up when interpolating the pixel values (duh!) I didn't notice it previously because my previous test images didn't cause it to show up.
So what was I left to do? I had to port over the C# version to a lib on it's own then.
Bicubic Interpolation
/// <summary>
/// Bicubic resize algorithm suitable for use in Silverlight
/// </summary>
/// <param name="src"></param>
/// <param name="dest"></param>
/// <remarks>Original Source For This Function - http://www.codeproject.com/KB/recipes/aforge.aspx</remarks>
public static void resizeBicubic(System.Windows.Media.Imaging.WriteableBitmap src, WriteableBitmap dest)
{
int height = src.PixelHeight;
int width = src.PixelWidth;
int newHeight = dest.PixelHeight;
int newWidth = dest.PixelWidth;
double xFactor = (double)width / newWidth;
double yFactor = (double)height / newHeight;
// coordinates of source points and cooefficiens
double ox, oy, dx, dy, k1, k2;
int ox1, oy1, ox2, oy2;
// destination pixel values
double r, g, b;
// width and height decreased by 1
int ymax = height - 1;
int xmax = width - 1;
int p;
// RGB
for (int y = 0; y < newHeight; y++)
{
// Y coordinates
oy = (double)y * yFactor - 0.5f;
oy1 = (int)oy;
dy = oy - (double)oy1;
for (int x = 0; x < newWidth; x++)
{
// X coordinates
ox = (double)x * xFactor - 0.5f;
ox1 = (int)ox;
dx = ox - (double)ox1;
// initial pixel value
r = g = b = 0;
for (int n = -1; n < 3; n++)
{
// get Y cooefficient
k1 = BiCubicKernel(dy - (double)n);
oy2 = oy1 + n;
if (oy2 < 0)
oy2 = 0;
if (oy2 > ymax)
oy2 = ymax;
for (int m = -1; m < 3; m++)
{
// get X cooefficient
k2 = k1 * BiCubicKernel((double)m - dx);
ox2 = ox1 + m;
if (ox2 < 0)
ox2 = 0;
if (ox2 > xmax)
ox2 = xmax;
// get pixel of original image
// p = src + oy2 * srcStride + ox2 * 3;
int srcPixel=src.Pixels[ox2+(width*oy2)];
r += k2 * ((srcPixel>>16) & 0xff);
g += k2 * ((srcPixel >>8) & 0xff);
b += k2 * (srcPixel & 0xff);
}
}
dest.Pixels[x+(newWidth*y)]=(int)(0xff000000 | ((byte)r<<16) | ((byte)g<<8) |(byte) b);
}
}
}
public static double BiCubicKernel(double x)
{
if (x > 2.0)
return 0.0;
double a, b, c, d;
double xm1 = x - 1.0;
double xp1 = x + 1.0;
double xp2 = x + 2.0;
a = (xp2 <= 0.0) ? 0.0 : xp2 * xp2 * xp2;
b = (xp1 <= 0.0) ? 0.0 : xp1 * xp1 * xp1;
c = (x <= 0.0) ? 0.0 : x * x * x;
d = (xm1 <= 0.0) ? 0.0 : xm1 * xm1 * xm1;
return (0.16666666666666666667 * (a - (4.0 * b) + (6.0 * c) - (4.0 * d)));
}
Pretty much a direct port of the original code since it was in C# already previously, just changed the way pixels are read and set. Same caveat applies as the previous code, no alpha premultiplication done yet.
The C# code didn't produce the weird grid like overlay pattern. So... what happened? Well my guess would have to be that I haven't properly ported the code to VB, and somewhere there's a fractional number being cast to a whole number causing some problems.
I'll have to be more careful when porting code that involves fractions in the future then.