出来的效果是椭圆或圆形,呈涡状,视原始图片而定。
总体来说,这个代码处理的速度很慢,如果使用不安全代码的话,在性能上会有很大的提升。
private void button1_Click(object sender, EventArgs e)
{
Bitmap image = new Bitmap(@"c:/DSC_0096_S.JPG");
int x, y;
float x1, y1;
float fx, fy, xmid, ymid, ar;
Bitmap image2 = new Bitmap(image);
xmid = (float)(image.Width / 2.0);
ymid = (float)(image.Height / 2.0);
ar = (float)(image.Height) / (float)(image.Width);
for (y = 0; y < image.Height; y++)
{
for (x = 0; x < image.Width; x++)
{
ComputePixel(ar * (x - xmid), y - ymid, out fx, out fy);
x1 = xmid + fx / ar;
y1 = ymid + fy;
image2.SetPixel(x, y, GetPixelColorInterpolated(ref image, x1, y1));
}
}
this.pictureBox1.Image = image2;
}
static int ComputePixel(float x, float y, out float x1, out float y1)
{
double r, nn;
if (x == 0 && y == 0)
{
x1 = x;
y1 = y;
return 1;
}
nn = Math.Sqrt(x * x + y * y);
r = (Math.Abs(x) > Math.Abs(y)) ? Math.Abs(nn / x) : Math.Abs(nn / y);
x1 = (float)(r * x);
y1 = (float)(r * y);
return 1;
}
static Color GetPixelColorInterpolated(ref Bitmap image, float x, float y)
{
int xi = (int)(x);
if (x < 0) xi--;
int yi = (int)(y);
if (y < 0) yi--;
if (xi < -1 || xi >= image.Width || yi < -1 || yi >= image.Height)
{
return GetPixelColorWithOverflow(ref image, -999, -999);
}
//get four neighbouring pixels
if ((xi + 1) < image.Width && xi >= 0 && (yi + 1) < image.Height && yi >= 0)
{
ushort wt1 = (ushort)((x - xi) * 256.0f), wt2 = (ushort)((y - yi) * 256.0f);
ushort wd = (ushort)(wt1 * wt2 >> 8);
ushort wb = (ushort)(wt1 - wd);
ushort wc = (ushort)(wt2 - wd);
ushort wa = (ushort)(256 - wt1 - wc);
ushort wrr, wgg, wbb;
Color clr = image.GetPixel(xi, yi);
wbb = (ushort)(wa * clr.B);
wgg = (ushort)(wa * clr.G);
wrr = (ushort)(wa * clr.R);
clr = image.GetPixel(xi + 1, yi);
wbb += (ushort)(wb * clr.B);
wgg += (ushort)(wb * clr.G);
wrr += (ushort)(wb * clr.R);
clr = image.GetPixel(xi, yi + 1);
wbb += (ushort)(wc * clr.B);
wgg += (ushort)(wc * clr.G);
wrr += (ushort)(wc * clr.R);
clr = image.GetPixel(xi + 1, yi + 1);
wbb += (ushort)(wd * clr.B);
wgg += (ushort)(wd * clr.G);
wrr += (ushort)(wd * clr.R);
return Color.FromArgb(255, wrr >> 8, wgg >> 8, wbb >> 8);
}
else
{
float t1 = x - xi, t2 = y - yi;
float d = t1 * t2;
float b = t1 - d;
float c = t2 - d;
float a = 1 - t1 - c;
Color rgb11, rgb21, rgb12, rgb22;
rgb11 = GetPixelColorWithOverflow(ref image, xi, yi);
rgb21 = GetPixelColorWithOverflow(ref image, xi + 1, yi);
rgb12 = GetPixelColorWithOverflow(ref image, xi, yi + 1);
rgb22 = GetPixelColorWithOverflow(ref image, xi + 1, yi + 1);
//calculate linear interpolation
return Color.FromArgb(255,
(byte)(a * rgb11.R + b * rgb21.R + c * rgb12.R + d * rgb22.R),
(byte)(a * rgb11.G + b * rgb21.G + c * rgb12.G + d * rgb22.G),
(byte)(a * rgb11.B + b * rgb21.B + c * rgb12.B + d * rgb22.B));
}
}
static Color GetPixelColorWithOverflow(ref Bitmap image, long x, long y)
{
if (!IsInside(ref image, x, y))
{
return Color.FromArgb(255, 255, 255, 255);
}
return image.GetPixel((int)x, (int)y);
}
static bool IsInside(ref Bitmap image, long x, long y)
{
return (0 <= y && y < image.Height && 0 <= x && x < image.Width);
}