您的位置:首页 > 其它

图像分辨率增强或者改变图像大小

2010-08-04 14:48 423 查看
最近有一段时间做图像处理方面的东西,遇到了一些样张需要进行分辨率的增强或者说是放大图像,如何在图像不失真的情况下放大图像呢?总的来说就是插值,插值包括零阶插值、双线性插值(Bilinear Interpolation)、立方卷积法(Bicubic Interpolation)等方法。

我实验了双线性插值和双三次插值,双三次插值的计算量比较大,但是效果也相对较好。有一篇叫“数字图像最佳插值算法研究”的中文论文中详细介绍了这三种方法的理论,还做了简单的比较。

Bilinear Interpolation的公式很简单,就是一个线性插值,f(i+u,j+ v)=(1-u)(1-v)f(i,j)+(1-u)vf(i,j+1) + u(1-v)f(i+1,j)+uvf(i+1,j+1),与(i,j)相邻的四个像素点乘以权值的加和即为插值后的灰度值。

Bicubic Interpolation相对比较复杂,公式如下:



f(x,y) = A*B*C,其中:



由此可以计算插值像素点的灰度值。该插值方法的C#代码如下:
//把图像放大两倍
private void resizeToolStripMenuItem_Click(object sender, EventArgs e)
{
Graphics dc = this.CreateGraphics();
dc.DrawImage(picture, 10, 30, this.ClientSize.Width - 20, this.ClientSize.Height - 20);
Color color;
pic = new Bitmap(picture);

int i, j;
int width = picture.Width;
int height = picture.Height;

int newWidth = Convert.ToInt32(picture.Width * 2);
int newHeight = Convert.ToInt32(picture.Height * 2);
Bitmap newpic = new Bitmap(newWidth, newHeight);
//int pixelSize =3;
int pixelSize = 1;
int srcStride = width-1;

int dstOffset = newWidth - pixelSize * newWidth;

double xFactor = (double)width / newWidth;
double yFactor = (double)height / newHeight;

// do the job
byte[,] src = new byte[width, height]; //(byte*)sourceData.ImageData.ToPointer();
byte[,] dst = new byte[newWidth, newHeight];//(byte*)destinationData.ImageData.ToPointer();

//double[,] pBuffer = new double[usW, usH];
//double[,] pBuffer1 = new double[usW, usH];
// coordinates of source points and coefficiens
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;
// temporary pointer
//byte* p;

for (i = 0; i < width; i++)
{
for (j = 0; j < height; j++)
{
color = pic.GetPixel(i, j);
src[i, j] =(byte)((color.R + color.G + color.B) / 3);
}
}

for (int y = 0; y < newHeight; y++)
{
// Y coordinates
oy = (double)y * yFactor - 0.5;
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
g = 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;
//    int tmp = oy2 * srcStride;
g += k2 * src[ox2, oy2];
}
}
dst[x,y] = (byte)g;
}
}

int gray = 0;
for (i = 0; i < newWidth; i++)
{
for (j = 0; j < newHeight; j++)
{
gray = dst[i, j];
color = Color.FromArgb(gray, gray, gray);

newpic.SetPixel(i, j, color);
}
}
//Show the processing result
dc.DrawImage(newpic, 10, 30, this.ClientSize.Width - 20, this.ClientSize.Height - 20);
image = new Bitmap(newpic);
pic.Dispose();
}

public  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)));
}

大家不一定有耐心去看懂它,双线性插值的方法也是这样写,只不过比这个要简单!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐