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

     最近有一段时间做图像处理方面的东西,遇到了一些样张需要进行分辨率的增强或者说是放大图像,如何在图像不失真的情况下放大图像呢?总的来说就是插值,插值包括零阶插值、双线性插值(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相对比较复杂,公式如下:    

图像分辨率增强或者改变图像大小_第1张图片

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

图像分辨率增强或者改变图像大小_第2张图片

 

    由此可以计算插值像素点的灰度值。该插值方法的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))); }

    大家不一定有耐心去看懂它,双线性插值的方法也是这样写,只不过比这个要简单!

 

你可能感兴趣的:(算法,图像处理)