图像处理(Image Processing) ---------- 图像缩放 (C#实现)
发布时间
阅读量:
阅读量
图像的放大与缩小必然会伴随着该图像中像素数量的增加或减少。我们目前关注的重点则是这些变化涉及的具体类型与数量关系以及获取方式。
现在主流的放大方法:
- 最近邻域插值算法(Nearest Neighbor):该方法具有极高的执行效率,在图像处理中应用广泛。具体而言,在放大图像时需要将目标像素的位置映射回原始图像的空间坐标系中,在此坐标位置上找到对应的原始像素数据即可得到目标像素的灰度或颜色信息。
- 双线性插值算法(Bilinear Interpolation)在视觉效果上较nearest neighbor方法更为平滑自然,在计算复杂度方面也有显著提升。具体操作中需先确定目标像素在原始图像中的对应位置坐标系中存在非整数值的情况,则需通过计算该位置与周围四个 pixels的距离权重进行加权平均以获得最终的目标像素灰度或颜色信息。
- 双立方插值算法(Bicubic Interpolation)和自适应样条插值极其增强技术(S-Spline & S-Spline XL)等高级方法在图像处理领域得到了广泛应用。
个人认为缩小同样也可以使用上面的方法~~
反向映射计算方法具体来说,就是将无论是放大还是缩小后的图像坐标乘以其缩放倍数的倒数,从而大致确定其在原始图像中的位置。
如:22 放大 2倍 --> 44。
4*4 像素点反向映射:
(0,0)*1/2 = (0,0),(1,0)*1/2 = (0.5,0),(2,0)*1/2 = (1,0),(3,0)*1/2 = (1.5,0)
(1,1)*1/2 = (0.5,0.5),(2,2)*1/2 = (1,1),(3,3)*1/2 = (1.5,1.5) .........
本文主要采用C#语言来开发基于Nearest Neighbor和Bilinear Interpolation算法的图像缩放功能。具体代码实现如下:
本文主要采用C#语言来开发基于Nearest Neighbor和Bilinear Interpolation算法的图像缩放功能。具体代码实现如下:
//最邻近值放大缩小
public Bitmap zoomInImageNear(Bitmap Image ,double times)
{
int width = Image.Width;
int height = Image.Height;
int IOwidth = (int)Math.Round(width * times);
int IOheight = (int)Math.Round(height * times);
Bitmap IOimage = new Bitmap(IOwidth, IOheight, PixelFormat.Format24bppRgb);
for (int y1 = 0; y1 < IOheight; y1++)
{
for(int x1 = 0; x1 < IOwidth; x1++)
{
int x = (int)Math.Round(x1 * (1 / times));
int y = (int)Math.Round(y1 * (1 / times));
//反向映射坐标,不在原图內,直接取边界作为Pixel。
if (x > (width-1))
{
x = width - 1;
}
if (y> (height-1))
{
y = height - 1;
}
IOimage.SetPixel(x1, y1, Image.GetPixel(x, y));
}
}
return IOimage;
}
//双线性放大与缩小
public Bitmap zoomInImageLine(Bitmap Image,double times)
{
int width = Image.Width;
int height = Image.Height;
int IOwidth = (int)Math.Round(width * times);
int IOheight = (int)Math.Round(height * times);
Bitmap IOimage = new Bitmap(IOwidth, IOheight, PixelFormat.Format24bppRgb);
for (int y1 = 0; y1 < IOheight; y1++)
{
for (int x1 = 0; x1 < IOwidth; x1++)
{
double x = x1 * (1 / times);
double y = y1 * (1 / times);
//反向映射坐标在原图内
if (x <= (width - 1) & y <= (height - 1))
{
Color RGB = new Color();
int a1 = (int)x;
int b1 = (int)y;
int a2 = (int)Math.Ceiling(x);
int b2 = (int)y;
int a3 = (int)x;
int b3 = (int)Math.Ceiling(y);
int a4 = (int)Math.Ceiling(x);
int b4 = (int)Math.Ceiling(y);
double xa13 = x - a1;
double xa24 = a2 - x;
double yb12 = y - b1;
double yb34 = b3 - y;
if (xa13 != 0 & xa24 != 0 & yb12 != 0 & yb34 != 0)
{//对应回原图是非整数坐标,双线性插值。
byte R1 = Image.GetPixel(a1, b1).R;
byte G1 = Image.GetPixel(a1, b1).G;
byte B1 = Image.GetPixel(a1, b1).B;
byte R2 = Image.GetPixel(a2, b2).R;
byte G2 = Image.GetPixel(a2, b2).G;
byte B2 = Image.GetPixel(a2, b2).B;
byte R3 = Image.GetPixel(a3, b3).R;
byte G3 = Image.GetPixel(a3, b3).G;
byte B3 = Image.GetPixel(a3, b3).B;
byte R4 = Image.GetPixel(a4, b4).R;
byte G4 = Image.GetPixel(a4, b4).G;
byte B4 = Image.GetPixel(a4, b4).B;
byte R = (byte)((R1 * xa24 + R2 * xa13) * yb34 + (R3 * xa24 + R4 * xa13) * yb12);
byte G = (byte)((G1 * xa24 + G2 * xa13) * yb34 + (G3 * xa24 + G4 * xa13) * yb12);
byte B = (byte)((B1 * xa24 + B2 * xa13) * yb34 + (B3 * xa24 + B4 * xa13) * yb12);
RGB = Color.FromArgb(R, G, B);
}
else
{//对应回原图是整数坐标,直接取Pixel。
RGB = Image.GetPixel((int)Math.Round(x), (int)Math.Round(y));
}
IOimage.SetPixel(x1, y1, RGB);
}
else
{ //反向映射坐标在不在原图内,直接取边界Pixel作为新Pixel。
int x2 = (int)Math.Round(x);
int y2 = (int)Math.Round(y);
if (x2 > (width - 1))
{
x2 = width - 1;
}
if (y2 > (height - 1))
{
y2 = height - 1;
}
IOimage.SetPixel(x1, y1, Image.GetPixel(x2, y2));
}
}
}
return IOimage;
}
仅为个人理解,如有不足,请指教。 <>
全部评论 (0)
还没有任何评论哟~
