实验3 图像的几何运算实验名称:图像的几何运算实验内容:图像的几何运算与点运算相对立,几何运算的目的在于改变像素之间的空间位置和空间关系,但没有改变灰度等级值,包括两个独立的算法:空间变换和灰度插值。
其中空间变换又包括平移和镜像处理,应用空间变换和灰度插值算法可以实现对图像的缩放和旋转处理。
图像的几何中心作为坐标原点,x轴由左向右递增,Y轴由上至下递增。
因此,在进行图像旋转时,是以图像的几何中心为基准进行旋转的;在进行图像缩放时,也是以图像的几何中心为基准,其上下左右均等地向内收缩或向外扩大的。
这种坐标转换会使图像变换更自然。
另外,在进行几何运算的时候,保持原图像的尺寸大小不变,如果变换后的图像超出该尺寸,超出部分会被截断,而不足部分会以白色像素填充。
本此实验内容包括:图像平移、图像镜像、图像缩放、图像旋转。
实验步骤:1、界面设计如下:打开图像代码:private void open_Click(object sender, EventArgs e){OpenFileDialog opnDlg = new OpenFileDialog();opnDlg.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;" +"*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf|" +"位图( *.bmp; *.jpg; *.png;...) | *.bmp; *.pcx; *.png; *.jpg; *.gif; *.tif; *.ico|" + "矢量图( *.wmf; *.eps; *.emf;...) | *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";opnDlg.Title = "打开图像文件";opnDlg.ShowHelp = true;if (opnDlg.ShowDialog() == DialogResult.OK){curFileName = opnDlg.FileName;try{curBitmap = (Bitmap)Image.FromFile(curFileName);}catch (Exception exp){MessageBox.Show(exp.Message);}}Invalidate();}关闭程序代码:private void close_Click(object sender, EventArgs e){this.Close();}Paint事件代码:private void Form1_Paint(object sender, PaintEventArgs e){Graphics g = e.Graphics;if (curBitmap != null){g.DrawImage(curBitmap, 160, 20, curBitmap.Width, curBitmap.Height);}}图像平移代码:private void translation_Click(object sender, EventArgs e){if (curBitmap != null){Translation traForm = new translation();if (traForm.ShowDialog() == DialogResult.OK){Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = curBitmap.Width * curBitmap.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);int x = Convert.ToInt32(traForm.GetXOffset);int y = Convert.ToInt32(traForm.GetYOffset);byte[] tempArray = new byte[bytes];//Array.Clear(tempArray, 0, bytes);for (int i = 0; i < bytes; i++){tempArray[i] = 255;}for (int i = 0; i < curBitmap.Height; i++){if ((i + y) < curBitmap.Height && (i + y) > 0){for (int j = 0; j < curBitmap.Width; j++){if ((j + x) < curBitmap.Width && (j + x) > 0){tempArray[(j + x) + (i + y) * curBitmap.Width] = grayValues[j + i * curBitmap.Width];}}}}grayValues = (byte[])tempArray.Clone();System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes); curBitmap.UnlockBits(bmpData);}Invalidate();}}上段代码理解:在对图像进行处理之前,总要判断一下是否存在图像,如:if (curBitmap != null)在图像处理过程中,需要用户输入相关参数,这时候可以打开其他对话框的方式获取参数,如:if (traForm.ShowDialog() == DialogResult.OK),为什么要这么做?这样做可以判断参数是否有效输入。
我这里,这个对话框的名字有个名字,叫traForm,里面还有些代码的,看看namespace geometry_operations{public partial class translation : Form{public translation(){InitializeComponent();}private void start_Click(object sender, EventArgs e){this.DialogResult = DialogResult.OK;}private void close_Click(object sender, EventArgs e){this.Close();}public string GetXOffset{get{return xOffset.Text;}}public string GetYOffset{get{return yOffset.Text;}}private void translation_Load(object sender, EventArgs e){}}}上面的代码定义了two个属性:GetXOffset、GetYOffset,这里要好好看看怎么C#里面怎么为类定义属性的,其实语法很简单:Public 类型属性名称{get{获得属性值代码}set{设置属性值代码}}好好学习下!试着给它加个属性。
在对图像处理时,总要先获取图像的像素值,获取图像像素值的方法可以参照图象灰度化的内存法,代码为:Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = curBitmap.Width * curBitmap.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);这样处理后就获得了一个图像灰度值得数组(注意:是1维的)下面的语句就是对图像灰度值得计算了,注意这时需要操作的图像实际上是个一维的数组grayValues,具体过程是这样的:先声名个临时的数组,并通过一个循环将数组初始化:byte[] tempArray = new byte[bytes];//Array.Clear(tempArray, 0, bytes);for (int i = 0; i < bytes; i++){tempArray[i] = 255;}关键的图像平移代码来啦!先看看?for (int i = 0; i < curBitmap.Height; i++){if ((i + y) < curBitmap.Height && (i + y) > 0){for (int j = 0; j < curBitmap.Width; j++){if ((j + x) < curBitmap.Width && (j + x) > 0){tempArray[(j + x) + (i + y) * curBitmap.Width] = grayValues[j + i * curBitmap.Width];}}}}这个对话框的代码:public mirror(){InitializeComponent();}private void startMirror_Click(object sender, EventArgs e) {this.DialogResult = DialogResult.OK;}private void close_Click(object sender, EventArgs e){this.Close();}public bool GetMirror{get{return horMirror.Checked;}}关键代码来了,实现镜像的功能的代码:private void mirror_Click(object sender, EventArgs e){if (curBitmap != null){mirror mirForm = new mirror();if (mirForm.ShowDialog() == DialogResult.OK){Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = curBitmap.Width * curBitmap.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);int halfWidth = curBitmap.Width / 2;int halfHeight = curBitmap.Height / 2;byte temp;if (mirForm.GetMirror){for (int i = 0; i < curBitmap.Height; i++){for (int j = 0; j < halfWidth; j++){temp = grayValues[i * curBitmap.Width + j];grayValues[i * curBitmap.Width + j] = grayValues[(i + 1) * curBitmap.Width - 1 - j];grayValues[(i + 1) * curBitmap.Width - 1 - j] = temp;}}}else{for (int i = 0; i < curBitmap.Width; i++){for (int j = 0; j < halfHeight; j++){temp = grayValues[j * curBitmap.Width + i];grayValues[j * curBitmap.Height + i] =grayValues[(curBitmap.Height - j - 1) * curBitmap.Width + i];grayValues[(curBitmap.Height - j - 1) * curBitmap.Width + i] = temp;}}}System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes); curBitmap.UnlockBits(bmpData);}Invalidate();}}实验结果如下:3.图像缩放的代码private void zoom_Click(object sender, EventArgs e){if (curBitmap != null){zoom zoomForm = new zoom();if (zoomForm.ShowDialog() == DialogResult.OK){Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = curBitmap.Width * curBitmap.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);double x = Convert.ToDouble(zoomForm.GetXZoom);double y = Convert.ToDouble(zoomForm.GetYZoom);int halfWidth = (int)(curBitmap.Width / 2);int halfHeight = (int)(curBitmap.Height / 2);int xz = 0;int yz = 0;int tempWidth = 0;int tempHeight = 0;byte[] tempArray = new byte[bytes];if (zoomForm.GetNearOrBil == true){for (int i = 0; i < curBitmap.Height; i++){for (int j = 0; j < curBitmap.Width; j++){tempHeight = i - halfHeight;tempWidth = j - halfWidth;if (tempWidth > 0){xz = (int)(tempWidth / x + 0.5);}else{xz = (int)(tempWidth / x - 0.5);}if (tempHeight > 0){yz = (int)(tempHeight / y + 0.5);}else{yz = (int)(tempHeight / y - 0.5);}tempWidth = xz + halfWidth;tempHeight = yz + halfHeight;if(tempWidth < 0 || tempWidth >= curBitmap.Width || tempHeight < 0 || tempHeight >= curBitmap.Height){tempArray[i * curBitmap.Width + j] = 255;}else{tempArray[i * curBitmap.Width + j] = grayValues[tempHeight * curBitmap.Width + tempWidth];}}}}else{double tempX, tempY, p, q;for (int i = 0; i < curBitmap.Height; i++){for (int j = 0; j < curBitmap.Width; j++){tempHeight = i - halfHeight;tempWidth = j - halfWidth;tempX = tempWidth / x;tempY = tempHeight / y;if (tempWidth > 0){xz = (int)tempX;}else{xz = (int)(tempX - 1);}if (tempHeight > 0){yz = (int)tempY;}else{yz = (int)(tempY - 1);}p = tempX - xz;q = tempY - yz;tempWidth = xz + halfWidth;tempHeight = yz + halfHeight;if (tempWidth < 0 || (tempWidth + 1) >= curBitmap.Width || tempHeight < 0 || (tempHeight + 1) >= curBitmap.Height){tempArray[i * curBitmap.Width + j] = 255;}else{tempArray[i * curBitmap.Width + j] = (byte)((1.0 - q) * ((1.0 - p) * grayValues[tempHeight * curBitmap.Width + tempWidth] + p * grayValues[tempHeight * curBitmap.Width + tempWidth + 1]) +q * ((1.0 - p) * grayValues[(tempHeight + 1) * curBitmap.Width + tempWidth] + p * grayValues[(tempHeight + 1) * curBitmap.Width + 1 + tempWidth]));}}}}grayValues = (byte[])tempArray.Clone();System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes); curBitmap.UnlockBits(bmpData);}Invalidate();}}4.图像旋转的代码private void rotation_Click(object sender, EventArgs e){if (curBitmap != null){rotation rotForm = new rotation();if (rotForm.ShowDialog() == DialogResult.OK){Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height); System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);IntPtr ptr = bmpData.Scan0;int bytes = curBitmap.Width * curBitmap.Height;byte[] grayValues = new byte[bytes];System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);int degree = Convert.ToInt32(rotForm.GetDegree);double radian = degree * Math.PI / 180.0;double mySin = Math.Sin(radian);double myCos = Math.Cos(radian);int halfWidth = (int)(curBitmap.Width / 2);int halfHeight = (int)(curBitmap.Height / 2);int xr = 0;int yr = 0;int tempWidth = 0;int tempHeight = 0;byte[] tempArray = new byte[bytes];double tempX, tempY, p, q;for (int i = 0; i < curBitmap.Height; i++){for (int j = 0; j < curBitmap.Width; j++){tempHeight = i - halfHeight;tempWidth = j - halfWidth;tempX = tempWidth * myCos - tempHeight * mySin;tempY = tempHeight * myCos + tempWidth * mySin;if (tempWidth > 0){xr = (int)tempX;}else{xr = (int)(tempX - 1);}if (tempHeight > 0){yr = (int)tempY;}else{yr = (int)(tempY - 1);}p = tempX - xr;q = tempY - yr;tempWidth = xr + halfWidth;tempHeight = yr + halfHeight;if(tempWidth < 0 || (tempWidth + 1) >= curBitmap.Width || tempHeight < 0 || (tempHeight + 1) >= curBitmap.Height){tempArray[i * curBitmap.Width + j] = 255;}else{tempArray[i * curBitmap.Width + j] = (byte)((1.0 - q) * ((1.0 - p) * grayValues[tempHeight * curBitmap.Width + tempWidth] + p * grayValues[tempHeight * curBitmap.Width + tempWidth + 1]) +q * ((1.0 - p) * grayValues[(tempHeight + 1) * curBitmap.Width + tempWidth] + p * grayValues[(tempHeight + 1) * curBitmap.Width + 1 + tempWidth]));}}}grayValues = (byte[])tempArray.Clone();System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes); curBitmap.UnlockBits(bmpData);}Invalidate();}实验结果如下:。