C#图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)
一、各种旋转、改变大小
注意:先要添加画图相关的using引用。
- //向右旋转图像90°代码如下:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");//加载图像
- g.FillRectangle(Brushes.White, this.ClientRectangle);//填充窗体背景为白色
- Point[] destinationPoints = {
- new Point(100, 0), // destination for upper-left point of original
- new Point(100, 100),// destination for upper-right point of original
- new Point(0, 0)}; // destination for lower-left point of original
- g.DrawImage(bmp, destinationPoints);
- }
- //旋转图像180°代码如下:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");
- g.FillRectangle(Brushes.White, this.ClientRectangle);
- Point[] destinationPoints = {
- new Point(0, 100), // destination for upper-left point of original
- new Point(100, 100),// destination for upper-right point of original
- new Point(0, 0)}; // destination for lower-left point of original
- g.DrawImage(bmp, destinationPoints);
- }
- //图像切变代码:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");
- g.FillRectangle(Brushes.White, this.ClientRectangle);
- Point[] destinationPoints = {
- new Point(0, 0), // destination for upper-left point of original
- new Point(100, 0), // destination for upper-right point of original
- new Point(50, 100)};// destination for lower-left point of original
- g.DrawImage(bmp, destinationPoints);
- }
- //图像截取:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");
- g.FillRectangle(Brushes.White, this.ClientRectangle);
- Rectangle sr = new Rectangle(80, 60, 400, 400);//要截取的矩形区域
- Rectangle dr = new Rectangle(0, 0, 200, 200);//要显示到Form的矩形区域
- g.DrawImage(bmp, dr, sr, GraphicsUnit.Pixel);
- }
- //改变图像大小:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");
- g.FillRectangle(Brushes.White, this.ClientRectangle);
- int width = bmp.Width;
- int height = bmp.Height;
- // 改变图像大小使用低质量的模式
- g.InterpolationMode = InterpolationMode.NearestNeighbor;
- g.DrawImage(bmp, new Rectangle(10, 10, 120, 120), // source rectangle
- new Rectangle(0, 0, width, height), // destination rectangle
- GraphicsUnit.Pixel);
- // 使用高质量模式
- //g.CompositingQuality = CompositingQuality.HighSpeed;
- g.InterpolationMode = InterpolationMode.HighQualityBicubic;
- g.DrawImage(
- bmp,
- new Rectangle(130, 10, 120, 120),
- new Rectangle(0, 0, width, height),
- GraphicsUnit.Pixel);
- }
- //设置图像的分辩率:
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Bitmap bmp = new Bitmap("rama.jpg");
- g.FillRectangle(Brushes.White, this.ClientRectangle);
- bmp.SetResolution(300f, 300f);
- g.DrawImage(bmp, 0, 0);
- bmp.SetResolution(1200f, 1200f);
- g.DrawImage(bmp, 180, 0);
- }
- //用GDI+画图
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics gForm = e.Graphics;
- gForm.FillRectangle(Brushes.White, this.ClientRectangle);
- for (int i = 1; i <= 7; ++i)
- {
- //在窗体上面画出橙色的矩形
- Rectangle r = new Rectangle(i*40-15, 0, 15,
- this.ClientRectangle.Height);
- gForm.FillRectangle(Brushes.Orange, r);
- }
- //在内存中创建一个Bitmap并设置CompositingMode
- Bitmap bmp = new Bitmap(260, 260,
- System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- Graphics gBmp = Graphics.FromImage(bmp);
- gBmp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
- // 创建一个带有Alpha的红色区域
- // 并将其画在内存的位图里面
- Color red = Color.FromArgb(0x60, 0xff, 0, 0);
- Brush redBrush = new SolidBrush(red);
- gBmp.FillEllipse(redBrush, 70, 70, 160, 160);
- // 创建一个带有Alpha的绿色区域
- Color green = Color.FromArgb(0x40, 0, 0xff, 0);
- Brush greenBrush = new SolidBrush(green);
- gBmp.FillRectangle(greenBrush, 10, 10, 140, 140);
- //在窗体上面画出位图 now draw the bitmap on our window
- gForm.DrawImage(bmp, 20, 20, bmp.Width, bmp.Height);
- // 清理资源
- bmp.Dispose();
- gBmp.Dispose();
- redBrush.Dispose();
- greenBrush.Dispose();
- }
- //在窗体上面绘图并显示图像
- private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
- {
- Graphics g = e.Graphics;
- Pen blackPen = new Pen(Color.Black, 1);
- if (ClientRectangle.Height / 10 > 0)
- {
- for (int y = 0; y < ClientRectangle.Height; y += ClientRectangle.Height / 10)
- {
- g.DrawLine(blackPen, new Point(0, 0), new Point(ClientRectangle.Width, y));
- }
- }
- blackPen.Dispose();
- }
//向右旋转图像90°代码如下: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg");//加载图像 g.FillRectangle(Brushes.White, this.ClientRectangle);//填充窗体背景为白色 Point[] destinationPoints = { new Point(100, 0), // destination for upper-left point of original new Point(100, 100),// destination for upper-right point of original new Point(0, 0)}; // destination for lower-left point of original g.DrawImage(bmp, destinationPoints); } //旋转图像180°代码如下: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg"); g.FillRectangle(Brushes.White, this.ClientRectangle); Point[] destinationPoints = { new Point(0, 100), // destination for upper-left point of original new Point(100, 100),// destination for upper-right point of original new Point(0, 0)}; // destination for lower-left point of original g.DrawImage(bmp, destinationPoints); } //图像切变代码: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg"); g.FillRectangle(Brushes.White, this.ClientRectangle); Point[] destinationPoints = { new Point(0, 0), // destination for upper-left point of original new Point(100, 0), // destination for upper-right point of original new Point(50, 100)};// destination for lower-left point of original g.DrawImage(bmp, destinationPoints); } //图像截取: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg"); g.FillRectangle(Brushes.White, this.ClientRectangle); Rectangle sr = new Rectangle(80, 60, 400, 400);//要截取的矩形区域 Rectangle dr = new Rectangle(0, 0, 200, 200);//要显示到Form的矩形区域 g.DrawImage(bmp, dr, sr, GraphicsUnit.Pixel); } //改变图像大小: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg"); g.FillRectangle(Brushes.White, this.ClientRectangle); int width = bmp.Width; int height = bmp.Height; // 改变图像大小使用低质量的模式 g.InterpolationMode = InterpolationMode.NearestNeighbor; g.DrawImage(bmp, new Rectangle(10, 10, 120, 120), // source rectangle new Rectangle(0, 0, width, height), // destination rectangle GraphicsUnit.Pixel); // 使用高质量模式 //g.CompositingQuality = CompositingQuality.HighSpeed; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage( bmp, new Rectangle(130, 10, 120, 120), new Rectangle(0, 0, width, height), GraphicsUnit.Pixel); } //设置图像的分辩率: private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Bitmap bmp = new Bitmap("rama.jpg"); g.FillRectangle(Brushes.White, this.ClientRectangle); bmp.SetResolution(300f, 300f); g.DrawImage(bmp, 0, 0); bmp.SetResolution(1200f, 1200f); g.DrawImage(bmp, 180, 0); } //用GDI+画图 private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics gForm = e.Graphics; gForm.FillRectangle(Brushes.White, this.ClientRectangle); for (int i = 1; i <= 7; ++i) { //在窗体上面画出橙色的矩形 Rectangle r = new Rectangle(i*40-15, 0, 15, this.ClientRectangle.Height); gForm.FillRectangle(Brushes.Orange, r); } //在内存中创建一个Bitmap并设置CompositingMode Bitmap bmp = new Bitmap(260, 260, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics gBmp = Graphics.FromImage(bmp); gBmp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy; // 创建一个带有Alpha的红色区域 // 并将其画在内存的位图里面 Color red = Color.FromArgb(0x60, 0xff, 0, 0); Brush redBrush = new SolidBrush(red); gBmp.FillEllipse(redBrush, 70, 70, 160, 160); // 创建一个带有Alpha的绿色区域 Color green = Color.FromArgb(0x40, 0, 0xff, 0); Brush greenBrush = new SolidBrush(green); gBmp.FillRectangle(greenBrush, 10, 10, 140, 140); //在窗体上面画出位图 now draw the bitmap on our window gForm.DrawImage(bmp, 20, 20, bmp.Width, bmp.Height); // 清理资源 bmp.Dispose(); gBmp.Dispose(); redBrush.Dispose(); greenBrush.Dispose(); } //在窗体上面绘图并显示图像 private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { Graphics g = e.Graphics; Pen blackPen = new Pen(Color.Black, 1); if (ClientRectangle.Height / 10 > 0) { for (int y = 0; y < ClientRectangle.Height; y += ClientRectangle.Height / 10) { g.DrawLine(blackPen, new Point(0, 0), new Point(ClientRectangle.Width, y)); } } blackPen.Dispose(); }
C# 使用Bitmap类进行图片裁剪
在Mapwin(手机游戏地图编辑器)生成的地图txt文件中添加自己需要处理的数据后转换成可在手机(Ophone)开发环境中使用的字节流地图文件的小工具,其中就涉及到图片的裁剪和生成了。有以下几种方式。
方法一:拷贝像素。
当然这种方法是最笨的,效率也就低了些。
在Bitmap类中我们可以看到这样两个方法:GetPixel(int x, int y)和SetPixel(int x, int y, Color color)方法。从字面的含以上就知道前者是获取图像某点像素值,是用Color对象返回的;后者是将已知像素描画到制定的位置。
下面就来做个实例检验下:
1.首先创建一个Windows Form窗体程序,往该窗体上拖放7个PictureBox控件,第一个用于放置并显示原始的大图片,其后6个用于放置并显示裁剪后新生成的6个小图;
2.放置原始大图的PictureBox控件name属性命名为pictureBoxBmpRes,其后pictureBox1到pictureBox6依次命名,并放置在合适的位置;
3.双击Form窗体,然后在Form1_Load事件中加入下面的代码即可。
- //导入图像资源
- Bitmap bmpRes = null;
- String strPath = Application.ExecutablePath;
- try{
- int nEndIndex = strPath.LastIndexOf('//');
- strPath = strPath.Substring(0,nEndIndex) + "//Bmp//BmpResMM.bmp";
- bmpRes = new Bitmap(strPath);
- //窗体上显示加载图片
- pictureBoxBmpRes.Width = bmpRes.Width;
- pictureBoxBmpRes.Height = bmpRes.Height;
- pictureBoxBmpRes.Image = bmpRes;
- }
- catch(Exception ex)
- {
- System.Windows.Forms.MessageBox.Show("图片资源加载失败!/r/n" + ex.ToString());
- }
- //裁剪图片(裁成2行3列的6张图片)
- int nYClipNum = 2, nXClipNum = 3;
- Bitmap[] bmpaClipBmpArr = new Bitmap[nYClipNum * nXClipNum];
- for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++)
- {
- for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++)
- {
- int nClipWidth = bmpRes.Width / nXClipNum;
- int nClipHight = bmpRes.Height / nYClipNum;
- int nBmpIndex = nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);
- bmpaClipBmpArr[nBmpIndex] = new Bitmap(nClipWidth, nClipHight);
- for(int nY = 0; nY < nClipHight; nY++)
- {
- for(int nX = 0; nX < nClipWidth; nX++)
- {
- int nClipX = nX + nClipWidth * nXClipNumIndex;
- int nClipY = nY + nClipHight * nYClipNumIndex;
- Color cClipPixel = bmpRes.GetPixel(nClipX, nClipY);
- bmpaClipBmpArr[nBmpIndex].SetPixel(nX, nY, cClipPixel);
- }
- }
- }
- }
- PictureBox[] picbShow = new PictureBox[nYClipNum * nXClipNum];
- picbShow[0] = pictureBox1;
- picbShow[1] = pictureBox2;
- picbShow[2] = pictureBox3;
- picbShow[3] = pictureBox4;
- picbShow[4] = pictureBox5;
- picbShow[5] = pictureBox6;
- for (int nLoop = 0; nLoop < nYClipNum * nXClipNum; nLoop++)
- {
- picbShow[nLoop].Width = bmpRes.Width / nXClipNum;
- picbShow[nLoop].Height = bmpRes.Height / nYClipNum;
- picbShow[nLoop].Image = bmpaClipBmpArr[nLoop];
- }
//导入图像资源 Bitmap bmpRes = null; String strPath = Application.ExecutablePath; try{ int nEndIndex = strPath.LastIndexOf('//'); strPath = strPath.Substring(0,nEndIndex) + "//Bmp//BmpResMM.bmp"; bmpRes = new Bitmap(strPath); //窗体上显示加载图片 pictureBoxBmpRes.Width = bmpRes.Width; pictureBoxBmpRes.Height = bmpRes.Height; pictureBoxBmpRes.Image = bmpRes; } catch(Exception ex) { System.Windows.Forms.MessageBox.Show("图片资源加载失败!/r/n" + ex.ToString()); } //裁剪图片(裁成2行3列的6张图片) int nYClipNum = 2, nXClipNum = 3; Bitmap[] bmpaClipBmpArr = new Bitmap[nYClipNum * nXClipNum]; for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++) { for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++) { int nClipWidth = bmpRes.Width / nXClipNum; int nClipHight = bmpRes.Height / nYClipNum; int nBmpIndex = nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0); bmpaClipBmpArr[nBmpIndex] = new Bitmap(nClipWidth, nClipHight); for(int nY = 0; nY < nClipHight; nY++) { for(int nX = 0; nX < nClipWidth; nX++) { int nClipX = nX + nClipWidth * nXClipNumIndex; int nClipY = nY + nClipHight * nYClipNumIndex; Color cClipPixel = bmpRes.GetPixel(nClipX, nClipY); bmpaClipBmpArr[nBmpIndex].SetPixel(nX, nY, cClipPixel); } } } } PictureBox[] picbShow = new PictureBox[nYClipNum * nXClipNum]; picbShow[0] = pictureBox1; picbShow[1] = pictureBox2; picbShow[2] = pictureBox3; picbShow[3] = pictureBox4; picbShow[4] = pictureBox5; picbShow[5] = pictureBox6; for (int nLoop = 0; nLoop < nYClipNum * nXClipNum; nLoop++) { picbShow[nLoop].Width = bmpRes.Width / nXClipNum; picbShow[nLoop].Height = bmpRes.Height / nYClipNum; picbShow[nLoop].Image = bmpaClipBmpArr[nLoop]; }
现在看看那些地方需要注意的了。其中
int nBmpIndex =
nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);
这句定义了存储裁剪图片对象在数组中的索引,需要注意的就是后面的(nYClipNumIndex > 0?1:0)——因为只有当裁剪的对象处于第一行以外的行时需要将索引加1;
另外,因为这种方法的效率不高,程序运行起来还是顿了下。如果有兴趣的话,可以将以上的代码放到一个按钮Click事件函数中,当单击该按钮时就可以感觉到了。
方法二:运用Clone函数局部复制。
同样在Bitmap中可以找到Clone()方法,该方法有三个重载方法。Clone(),Clone(Rectangle, PixelFormat)和Clone(RectangleF, PixelFormat)。第一个方法将创建并返回一个精确的实例对象,后两个就是我们这里需要用的局部裁剪了(其实后两个方法本人觉得用法上差不多)。
将上面的程序稍稍改进下——将裁剪的处理放到一个按钮事件函数中,然后再托一个按钮好窗体上,最后将下面的代码复制到该按钮的事件函数中。
- for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++)
- {
- for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++)
- {
- int nClipWidth = bmpRes.Width / nXClipNum;
- int nClipHight = bmpRes.Height / nYClipNum;
- int nBmpIndex =
- nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0 ? 1 : 0);
- Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,
- nClipHight * nYClipNumIndex,
- nClipWidth,
- nClipHight);
- bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);
- }
- }
for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++) { for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++) { int nClipWidth = bmpRes.Width / nXClipNum; int nClipHight = bmpRes.Height / nYClipNum; int nBmpIndex = nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0 ? 1 : 0); Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex, nClipHight * nYClipNumIndex, nClipWidth, nClipHight); bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat); } }
运行程序,单击按钮检验下,发现速度明显快可很多。
其实这种方法较第一中方法不同的地方仅只是变换了for循环中的拷贝部分的处理,
- Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,
- nClipHight * nYClipNumIndex,
- nClipWidth,
- nClipHight);
- bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);
Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex, nClipHight * nYClipNumIndex, nClipWidth, nClipHight); bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);
一. 底片效果
原理: GetPixel方法获得每一点像素的值, 然后再使用SetPixel方法将取反后的颜色值设置到对应的点.
效果图:
代码实现:
- private void button1_Click(object sender, EventArgs e)
- {
- //以底片效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap newbitmap = new Bitmap(Width, Height);
- Bitmap oldbitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel;
- for (int x = 1; x < Width; x++)
- {
- for (int y = 1; y < Height; y++)
- {
- int r, g, b;
- pixel = oldbitmap.GetPixel(x, y);
- r = 255 - pixel.R;
- g = 255 - pixel.G;
- b = 255 - pixel.B;
- newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
- }
- }
- this.pictureBox1.Image = newbitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
private void button1_Click(object sender, EventArgs e) { //以底片效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap newbitmap = new Bitmap(Width, Height); Bitmap oldbitmap = (Bitmap)this.pictureBox1.Image; Color pixel; for (int x = 1; x < Width; x++) { for (int y = 1; y < Height; y++) { int r, g, b; pixel = oldbitmap.GetPixel(x, y); r = 255 - pixel.R; g = 255 - pixel.G; b = 255 - pixel.B; newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b)); } } this.pictureBox1.Image = newbitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } }
二. 浮雕效果
原理: 对图像像素点的像素值分别与相邻像素点的像素值相减后加上128, 然后将其作为新的像素点的值.
效果图:
代码实现:
- private void button1_Click(object sender, EventArgs e)
- {
- //以浮雕效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap newBitmap = new Bitmap(Width, Height);
- Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel1, pixel2;
- for (int x = 0; x < Width - 1; x++)
- {
- for (int y = 0; y < Height - 1; y++)
- {
- int r = 0, g = 0, b = 0;
- pixel1 = oldBitmap.GetPixel(x, y);
- pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
- r = Math.Abs(pixel1.R - pixel2.R + 128);
- g = Math.Abs(pixel1.G - pixel2.G + 128);
- b = Math.Abs(pixel1.B - pixel2.B + 128);
- if (r > 255)
- r = 255;
- if (r < 0)
- r = 0;
- if (g > 255)
- g = 255;
- if (g < 0)
- g = 0;
- if (b > 255)
- b = 255;
- if (b < 0)
- b = 0;
- newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
- }
- }
- this.pictureBox1.Image = newBitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
private void button1_Click(object sender, EventArgs e) { //以浮雕效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap newBitmap = new Bitmap(Width, Height); Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image; Color pixel1, pixel2; for (int x = 0; x < Width - 1; x++) { for (int y = 0; y < Height - 1; y++) { int r = 0, g = 0, b = 0; pixel1 = oldBitmap.GetPixel(x, y); pixel2 = oldBitmap.GetPixel(x + 1, y + 1); r = Math.Abs(pixel1.R - pixel2.R + 128); g = Math.Abs(pixel1.G - pixel2.G + 128); b = Math.Abs(pixel1.B - pixel2.B + 128); if (r > 255) r = 255; if (r < 0) r = 0; if (g > 255) g = 255; if (g < 0) g = 0; if (b > 255) b = 255; if (b < 0) b = 0; newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b)); } } this.pictureBox1.Image = newBitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } }
三. 黑白效果
原理: 彩色图像处理成黑白效果通常有3种算法;
(1).最大值法: 使每个像素点的 R, G, B 值等于原像素点的 RGB (颜色值) 中最大的一个;
(2).平均值法: 使用每个像素点的 R,G,B值等于原像素点的RGB值的平均值;
(3).加权平均值法: 对每个像素点的 R, G, B值进行加权
---自认为第三种方法做出来的黑白效果图像最 "真实".
效果图:
代码实现:
- private void button1_Click(object sender, EventArgs e)
- {
- //以黑白效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap newBitmap = new Bitmap(Width, Height);
- Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {
- pixel = oldBitmap.GetPixel(x, y);
- int r, g, b, Result = 0;
- r = pixel.R;
- g = pixel.G;
- b = pixel.B;
- //实例程序以加权平均值法产生黑白图像
- int iType =2;
- switch (iType)
- {
- case 0://平均值法
- Result = ((r + g + b) / 3);
- break;
- case 1://最大值法
- Result = r > g ? r : g;
- Result = Result > b ? Result : b;
- break;
- case 2://加权平均值法
- Result = ((int)(0.7 * r) + (int)(0.2 * g) + (int)(0.1 * b));
- break;
- }
- newBitmap.SetPixel(x, y, Color.FromArgb(Result, Result, Result));
- }
- this.pictureBox1.Image = newBitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示");
- }
- }
private void button1_Click(object sender, EventArgs e) { //以黑白效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap newBitmap = new Bitmap(Width, Height); Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image; Color pixel; for (int x = 0; x < Width; x++) for (int y = 0; y < Height; y++) { pixel = oldBitmap.GetPixel(x, y); int r, g, b, Result = 0; r = pixel.R; g = pixel.G; b = pixel.B; //实例程序以加权平均值法产生黑白图像 int iType =2; switch (iType) { case 0://平均值法 Result = ((r + g + b) / 3); break; case 1://最大值法 Result = r > g ? r : g; Result = Result > b ? Result : b; break; case 2://加权平均值法 Result = ((int)(0.7 * r) + (int)(0.2 * g) + (int)(0.1 * b)); break; } newBitmap.SetPixel(x, y, Color.FromArgb(Result, Result, Result)); } this.pictureBox1.Image = newBitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示"); } }
四. 柔化效果
原理: 当前像素点与周围像素点的颜色差距较大时取其平均值.
效果图:
代码实现:
- private void button1_Click(object sender, EventArgs e)
- {
- //以柔化效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap bitmap = new Bitmap(Width, Height);
- Bitmap MyBitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel;
- //高斯模板
- int[] Gauss ={ 1, 2, 1, 2, 4, 2, 1, 2, 1 };
- for (int x = 1; x < Width - 1; x++)
- for (int y = 1; y < Height - 1; y++)
- {
- int r = 0, g = 0, b = 0;
- int Index = 0;
- for (int col = -1; col <= 1; col++)
- for (int row = -1; row <= 1; row++)
- {
- pixel = MyBitmap.GetPixel(x + row, y + col);
- r += pixel.R * Gauss[Index];
- g += pixel.G * Gauss[Index];
- b += pixel.B * Gauss[Index];
- Index++;
- }
- r /= 16;
- g /= 16;
- b /= 16;
- //处理颜色值溢出
- r = r > 255 ? 255 : r;
- r = r < 0 ? 0 : r;
- g = g > 255 ? 255 : g;
- g = g < 0 ? 0 : g;
- b = b > 255 ? 255 : b;
- b = b < 0 ? 0 : b;
- bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
- }
- this.pictureBox1.Image = bitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示");
- }
- }
private void button1_Click(object sender, EventArgs e) { //以柔化效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap bitmap = new Bitmap(Width, Height); Bitmap MyBitmap = (Bitmap)this.pictureBox1.Image; Color pixel; //高斯模板 int[] Gauss ={ 1, 2, 1, 2, 4, 2, 1, 2, 1 }; for (int x = 1; x < Width - 1; x++) for (int y = 1; y < Height - 1; y++) { int r = 0, g = 0, b = 0; int Index = 0; for (int col = -1; col <= 1; col++) for (int row = -1; row <= 1; row++) { pixel = MyBitmap.GetPixel(x + row, y + col); r += pixel.R * Gauss[Index]; g += pixel.G * Gauss[Index]; b += pixel.B * Gauss[Index]; Index++; } r /= 16; g /= 16; b /= 16; //处理颜色值溢出 r = r > 255 ? 255 : r; r = r < 0 ? 0 : r; g = g > 255 ? 255 : g; g = g < 0 ? 0 : g; b = b > 255 ? 255 : b; b = b < 0 ? 0 : b; bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b)); } this.pictureBox1.Image = bitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示"); } }
五.锐化效果
原理:突出显示颜色值大(即形成形体边缘)的像素点.
效果图:
实现代码:
- private void button1_Click(object sender, EventArgs e)
- {
- //以锐化效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap newBitmap = new Bitmap(Width, Height);
- Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel;
- //拉普拉斯模板
- int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 };
- for (int x = 1; x < Width - 1; x++)
- for (int y = 1; y < Height - 1; y++)
- {
- int r = 0, g = 0, b = 0;
- int Index = 0;
- for (int col = -1; col <= 1; col++)
- for (int row = -1; row <= 1; row++)
- {
- pixel = oldBitmap.GetPixel(x + row, y + col); r += pixel.R * Laplacian[Index];
- g += pixel.G * Laplacian[Index];
- b += pixel.B * Laplacian[Index];
- Index++;
- }
- //处理颜色值溢出
- r = r > 255 ? 255 : r;
- r = r < 0 ? 0 : r;
- g = g > 255 ? 255 : g;
- g = g < 0 ? 0 : g;
- b = b > 255 ? 255 : b;
- b = b < 0 ? 0 : b;
- newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
- }
- this.pictureBox1.Image = newBitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示");
- }
- }
private void button1_Click(object sender, EventArgs e) { //以锐化效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap newBitmap = new Bitmap(Width, Height); Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image; Color pixel; //拉普拉斯模板 int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 }; for (int x = 1; x < Width - 1; x++) for (int y = 1; y < Height - 1; y++) { int r = 0, g = 0, b = 0; int Index = 0; for (int col = -1; col <= 1; col++) for (int row = -1; row <= 1; row++) { pixel = oldBitmap.GetPixel(x + row, y + col); r += pixel.R * Laplacian[Index]; g += pixel.G * Laplacian[Index]; b += pixel.B * Laplacian[Index]; Index++; } //处理颜色值溢出 r = r > 255 ? 255 : r; r = r < 0 ? 0 : r; g = g > 255 ? 255 : g; g = g < 0 ? 0 : g; b = b > 255 ? 255 : b; b = b < 0 ? 0 : b; newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b)); } this.pictureBox1.Image = newBitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示"); } }
六. 雾化效果
原理: 在图像中引入一定的随机值, 打乱图像中的像素值
效果图:
实现代码:
- private void button1_Click(object sender, EventArgs e)
- {
- //以雾化效果显示图像
- try
- {
- int Height = this.pictureBox1.Image.Height;
- int Width = this.pictureBox1.Image.Width;
- Bitmap newBitmap = new Bitmap(Width, Height);
- Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
- Color pixel;
- for (int x = 1; x < Width - 1; x++)
- for (int y = 1; y < Height - 1; y++)
- {
- System.Random MyRandom = new Random();
- int k = MyRandom.Next(123456);
- //像素块大小
- int dx = x + k % 19;
- int dy = y + k % 19;
- if (dx >= Width)
- dx = Width - 1;
- if (dy >= Height)
- dy = Height - 1;
- pixel = oldBitmap.GetPixel(dx, dy);
- newBitmap.SetPixel(x, y, pixel);
- }
- this.pictureBox1.Image = newBitmap;
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "信息提示");
- }
- }
private void button1_Click(object sender, EventArgs e) { //以雾化效果显示图像 try { int Height = this.pictureBox1.Image.Height; int Width = this.pictureBox1.Image.Width; Bitmap newBitmap = new Bitmap(Width, Height); Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image; Color pixel; for (int x = 1; x < Width - 1; x++) for (int y = 1; y < Height - 1; y++) { System.Random MyRandom = new Random(); int k = MyRandom.Next(123456); //像素块大小 int dx = x + k % 19; int dy = y + k % 19; if (dx >= Width) dx = Width - 1; if (dy >= Height) dy = Height - 1; pixel = oldBitmap.GetPixel(dx, dy); newBitmap.SetPixel(x, y, pixel); } this.pictureBox1.Image = newBitmap; } catch (Exception ex) { MessageBox.Show(ex.Message, "信息提示"); } }
浅谈Visual C#进行图像处理
作者:彭军 http://pengjun.org.cn
这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用Visual C#进行图像的读入、保存以及对像素的访问。而不涉及太多的算法。
一、读入图像
在Visual C#中我们可以使用一个Picture Box控件来显示图片,如下
- private void btnOpenImage_Click(object sender, EventArgs e)
- {
- OpenFileDialog ofd = new OpenFileDialog();
- ofd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
- ofd.CheckFileExists = true;
- ofd.CheckPathExists = true;
- if (ofd.ShowDialog() == DialogResult.OK)
- {
- //pbxShowImage.ImageLocation = ofd.FileName;
- bmp = new Bitmap(ofd.FileName);
- if (bmp==null)
- {
- MessageBox.Show("加载图片失败!", "错误");
- return;
- }
- pbxShowImage.Image = bmp;
- ofd.Dispose();
- }
- }
private void btnOpenImage_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*"; ofd.CheckFileExists = true; ofd.CheckPathExists = true; if (ofd.ShowDialog() == DialogResult.OK) { //pbxShowImage.ImageLocation = ofd.FileName; bmp = new Bitmap(ofd.FileName); if (bmp==null) { MessageBox.Show("加载图片失败!", "错误"); return; } pbxShowImage.Image = bmp; ofd.Dispose(); } }
其中bmp为类的一个对象:private Bitmap bmp=null;
在使用Bitmap类和BitmapData类之前,需要使用using System.Drawing.Imaging;
二、保存图像
- private void btnSaveImage_Click(object sender, EventArgs e)
- {
- if (bmp == null) return;
- SaveFileDialog sfd = new SaveFileDialog();
- sfd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
- if (sfd.ShowDialog() == DialogResult.OK)
- {
- pbxShowImage.Image.Save(sfd.FileName);
- MessageBox.Show("保存成功!","提示");
- sfd.Dispose();
- }
- }
private void btnSaveImage_Click(object sender, EventArgs e) { if (bmp == null) return; SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*"; if (sfd.ShowDialog() == DialogResult.OK) { pbxShowImage.Image.Save(sfd.FileName); MessageBox.Show("保存成功!","提示"); sfd.Dispose(); } }
三、对像素的访问
我们可以来建立一个GrayBitmapData类来做相关的处理。整个类的程序如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Windows.Forms;
- namespace ImageElf
- {
- class GrayBitmapData
- {
- public byte[,] Data;//保存像素矩阵
- public int Width;//图像的宽度
- public int Height;//图像的高度
- public GrayBitmapData()
- {
- this.Width = 0;
- this.Height = 0;
- this.Data = null;
- }
- public GrayBitmapData(Bitmap bmp)
- {
- BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
- this.Width = bmpData.Width;
- this.Height = bmpData.Height;
- Data = new byte[Height, Width];
- unsafe
- {
- byte* ptr = (byte*)bmpData.Scan0.ToPointer();
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- //将24位的RGB彩色图转换为灰度图
- int temp = (int)(0.114 * (*ptr++)) + (int)(0.587 * (*ptr++))+(int)(0.299 * (*ptr++));
- Data[i, j] = (byte)temp;
- }
- ptr += bmpData.Stride - Width * 3;//指针加上填充的空白空间
- }
- }
- bmp.UnlockBits(bmpData);
- }
- public GrayBitmapData(string path)
- : this(new Bitmap(path))
- {
- }
- public Bitmap ToBitmap()
- {
- Bitmap bmp=new Bitmap(Width,Height,PixelFormat.Format24bppRgb);
- BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,Width,Height),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
- unsafe
- {
- byte* ptr=(byte*)bmpData.Scan0.ToPointer();
- for(int i=0;i<Height;i++)
- {
- for(int j=0;j<Width;j++)
- {
- *(ptr++)=Data[i,j];
- *(ptr++)=Data[i,j];
- *(ptr++)=Data[i,j];
- }
- ptr+=bmpData.Stride-Width*3;
- }
- }
- bmp.UnlockBits(bmpData);
- return bmp;
- }
- public void ShowImage(PictureBox pbx)
- {
- Bitmap b = this.ToBitmap();
- pbx.Image = b;
- //b.Dispose();
- }
- public void SaveImage(string path)
- {
- Bitmap b=ToBitmap();
- b.Save(path);
- //b.Dispose();
- }
- //均值滤波
- public void AverageFilter(int windowSize)
- {
- if (windowSize % 2 == 0)
- {
- return;
- }
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- int sum = 0;
- for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
- {
- for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
- {
- int a = i + g, b = j + k;
- if (a < 0) a = 0;
- if (a > Height - 1) a = Height - 1;
- if (b < 0) b = 0;
- if (b > Width - 1) b = Width - 1;
- sum += Data[a, b];
- }
- }
- Data[i,j]=(byte)(sum/(windowSize*windowSize));
- }
- }
- }
- //中值滤波
- public void MidFilter(int windowSize)
- {
- if (windowSize % 2 == 0)
- {
- return;
- }
- int[] temp = new int[windowSize * windowSize];
- byte[,] newdata = new byte[Height, Width];
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- int n = 0;
- for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
- {
- for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
- {
- int a = i + g, b = j + k;
- if (a < 0) a = 0;
- if (a > Height - 1) a = Height - 1;
- if (b < 0) b = 0;
- if (b > Width - 1) b = Width - 1;
- temp[n++]= Data[a, b];
- }
- }
- newdata[i, j] = GetMidValue(temp,windowSize*windowSize);
- }
- }
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- Data[i, j] = newdata[i, j];
- }
- }
- }
- //获得一个向量的中值
- private byte GetMidValue(int[] t, int length)
- {
- int temp = 0;
- for (int i = 0; i < length - 2; i++)
- {
- for (int j = i + 1; j < length - 1; j++)
- {
- if (t[i] > t[j])
- {
- temp = t[i];
- t[i] = t[j];
- t[j] = temp;
- }
- }
- }
- return (byte)t[(length - 1) / 2];
- }
- //一种新的滤波方法,是亮的更亮、暗的更暗
- public void NewFilter(int windowSize)
- {
- if (windowSize % 2 == 0)
- {
- return;
- }
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- int sum = 0;
- for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
- {
- for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
- {
- int a = i + g, b = j + k;
- if (a < 0) a = 0;
- if (a > Height - 1) a = Height - 1;
- if (b < 0) b = 0;
- if (b > Width - 1) b = Width - 1;
- sum += Data[a, b];
- }
- }
- double avg = (sum+0.0) / (windowSize * windowSize);
- if (avg / 255 < 0.5)
- {
- Data[i, j] = (byte)(2 * avg / 255 * Data[i, j]);
- }
- else
- {
- Data[i,j]=(byte)((1-2*(1-avg/255.0)*(1-Data[i,j]/255.0))*255);
- }
- }
- }
- }
- //直方图均衡
- public void HistEqual()
- {
- double[] num = new double[256] ;
- for(int i=0;i<256;i++) num[i]=0;
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- num[Data[i, j]]++;
- }
- }
- double[] newGray = new double[256];
- double n = 0;
- for (int i = 0; i < 256; i++)
- {
- n += num[i];
- newGray[i] = n * 255 / (Height * Width);
- }
- for (int i = 0; i < Height; i++)
- {
- for (int j = 0; j < Width; j++)
- {
- Data[i,j]=(byte)newGray[Data[i,j]];
- }
- }
- }
- }
- }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; namespace ImageElf { class GrayBitmapData { public byte[,] Data;//保存像素矩阵 public int Width;//图像的宽度 public int Height;//图像的高度 public GrayBitmapData() { this.Width = 0; this.Height = 0; this.Data = null; } public GrayBitmapData(Bitmap bmp) { BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); this.Width = bmpData.Width; this.Height = bmpData.Height; Data = new byte[Height, Width]; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { //将24位的RGB彩色图转换为灰度图 int temp = (int)(0.114 * (*ptr++)) + (int)(0.587 * (*ptr++))+(int)(0.299 * (*ptr++)); Data[i, j] = (byte)temp; } ptr += bmpData.Stride - Width * 3;//指针加上填充的空白空间 } } bmp.UnlockBits(bmpData); } public GrayBitmapData(string path) : this(new Bitmap(path)) { } public Bitmap ToBitmap() { Bitmap bmp=new Bitmap(Width,Height,PixelFormat.Format24bppRgb); BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,Width,Height),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb); unsafe { byte* ptr=(byte*)bmpData.Scan0.ToPointer(); for(int i=0;i<Height;i++) { for(int j=0;j<Width;j++) { *(ptr++)=Data[i,j]; *(ptr++)=Data[i,j]; *(ptr++)=Data[i,j]; } ptr+=bmpData.Stride-Width*3; } } bmp.UnlockBits(bmpData); return bmp; } public void ShowImage(PictureBox pbx) { Bitmap b = this.ToBitmap(); pbx.Image = b; //b.Dispose(); } public void SaveImage(string path) { Bitmap b=ToBitmap(); b.Save(path); //b.Dispose(); } //均值滤波 public void AverageFilter(int windowSize) { if (windowSize % 2 == 0) { return; } for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { int sum = 0; for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++) { for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++) { int a = i + g, b = j + k; if (a < 0) a = 0; if (a > Height - 1) a = Height - 1; if (b < 0) b = 0; if (b > Width - 1) b = Width - 1; sum += Data[a, b]; } } Data[i,j]=(byte)(sum/(windowSize*windowSize)); } } } //中值滤波 public void MidFilter(int windowSize) { if (windowSize % 2 == 0) { return; } int[] temp = new int[windowSize * windowSize]; byte[,] newdata = new byte[Height, Width]; for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { int n = 0; for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++) { for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++) { int a = i + g, b = j + k; if (a < 0) a = 0; if (a > Height - 1) a = Height - 1; if (b < 0) b = 0; if (b > Width - 1) b = Width - 1; temp[n++]= Data[a, b]; } } newdata[i, j] = GetMidValue(temp,windowSize*windowSize); } } for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { Data[i, j] = newdata[i, j]; } } } //获得一个向量的中值 private byte GetMidValue(int[] t, int length) { int temp = 0; for (int i = 0; i < length - 2; i++) { for (int j = i + 1; j < length - 1; j++) { if (t[i] > t[j]) { temp = t[i]; t[i] = t[j]; t[j] = temp; } } } return (byte)t[(length - 1) / 2]; } //一种新的滤波方法,是亮的更亮、暗的更暗 public void NewFilter(int windowSize) { if (windowSize % 2 == 0) { return; } for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { int sum = 0; for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++) { for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++) { int a = i + g, b = j + k; if (a < 0) a = 0; if (a > Height - 1) a = Height - 1; if (b < 0) b = 0; if (b > Width - 1) b = Width - 1; sum += Data[a, b]; } } double avg = (sum+0.0) / (windowSize * windowSize); if (avg / 255 < 0.5) { Data[i, j] = (byte)(2 * avg / 255 * Data[i, j]); } else { Data[i,j]=(byte)((1-2*(1-avg/255.0)*(1-Data[i,j]/255.0))*255); } } } } //直方图均衡 public void HistEqual() { double[] num = new double[256] ; for(int i=0;i<256;i++) num[i]=0; for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { num[Data[i, j]]++; } } double[] newGray = new double[256]; double n = 0; for (int i = 0; i < 256; i++) { n += num[i]; newGray[i] = n * 255 / (Height * Width); } for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { Data[i,j]=(byte)newGray[Data[i,j]]; } } } } }
在GrayBitmapData类中,只要我们对一个二维数组Data进行一系列的操作就是对图片的操作处理。在窗口上,我们可以使用
一个按钮来做各种调用:
- //均值滤波
- private void btnAvgFilter_Click(object sender, EventArgs e)
- {
- if (bmp == null) return;
- GrayBitmapData gbmp = new GrayBitmapData(bmp);
- gbmp.AverageFilter(3);
- gbmp.ShowImage(pbxShowImage);
- }
- //转换为灰度图
- private void btnToGray_Click(object sender, EventArgs e)
- {
- if (bmp == null) return;
- GrayBitmapData gbmp = new GrayBitmapData(bmp);
- gbmp.ShowImage(pbxShowImage);
- }
//均值滤波 private void btnAvgFilter_Click(object sender, EventArgs e) { if (bmp == null) return; GrayBitmapData gbmp = new GrayBitmapData(bmp); gbmp.AverageFilter(3); gbmp.ShowImage(pbxShowImage); } //转换为灰度图 private void btnToGray_Click(object sender, EventArgs e) { if (bmp == null) return; GrayBitmapData gbmp = new GrayBitmapData(bmp); gbmp.ShowImage(pbxShowImage); }
四、总结
在Visual c#中对图像进行处理或访问,需要先建立一个Bitmap对象,然后通过其LockBits方法来获得一个BitmapData类的对象,然后通过获得其像素数据的首地址来对Bitmap对象的像素数据进行操作。当然,一种简单但是速度慢的方法是用Bitmap类的GetPixel和SetPixel方法。其中BitmapData类的Stride属性为每行像素所占的字节。
C# colorMatrix 对图片的处理 : 亮度调整 抓屏 翻转 随鼠标画矩形
1.图片亮度处理
- private void btn_Grap_Click(object sender, EventArgs e)
- {
- //亮度百分比
- int percent = 50;
- Single v = 0.006F * percent;
- Single[][] matrix = {
- new Single[] { 1, 0, 0, 0, 0 },
- new Single[] { 0, 1, 0, 0, 0 },
- new Single[] { 0, 0, 1, 0, 0 },
- new Single[] { 0, 0, 0, 1, 0 },
- new Single[] { v, v, v, 0, 1 }
- };
- System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix);
- System.Drawing.Imaging.ImageAttributes attr = new System.Drawing.Imaging.ImageAttributes();
- attr.SetColorMatrix(cm);
- //Image tmp
- Image tmp = Image.FromFile("1.png");
- this.pictureBox_Src.Image = Image.FromFile("1.png");
- Graphics g = Graphics.FromImage(tmp);
- try
- {
- Rectangle destRect = new Rectangle(0, 0, tmp.Width, tmp.Height);
- g.DrawImage(tmp, destRect, 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, attr);
- }
- finally
- {
- g.Dispose();
- }
- this.pictureBox_Dest.Image = (Image)tmp.Clone();
- }
private void btn_Grap_Click(object sender, EventArgs e) { //亮度百分比 int percent = 50; Single v = 0.006F * percent; Single[][] matrix = { new Single[] { 1, 0, 0, 0, 0 }, new Single[] { 0, 1, 0, 0, 0 }, new Single[] { 0, 0, 1, 0, 0 }, new Single[] { 0, 0, 0, 1, 0 }, new Single[] { v, v, v, 0, 1 } }; System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix); System.Drawing.Imaging.ImageAttributes attr = new System.Drawing.Imaging.ImageAttributes(); attr.SetColorMatrix(cm); //Image tmp Image tmp = Image.FromFile("1.png"); this.pictureBox_Src.Image = Image.FromFile("1.png"); Graphics g = Graphics.FromImage(tmp); try { Rectangle destRect = new Rectangle(0, 0, tmp.Width, tmp.Height); g.DrawImage(tmp, destRect, 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, attr); } finally { g.Dispose(); } this.pictureBox_Dest.Image = (Image)tmp.Clone(); }
2.抓屏将生成的图片显示在pictureBox
- private void btn_Screen_Click(object sender, EventArgs e)
- {
- Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
- Graphics g = Graphics.FromImage(myImage);
- g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
- //IntPtr dc1 = g.GetHdc(); //此处这两句多余,具体看最后GetHdc()定义
- //g.ReleaseHdc(dc1);
- g.Dispose();
- this.pictureBox_Src.SizeMode = PictureBoxSizeMode.StretchImage;
- this.pictureBox_Src.Image = myImage;
- myImage.Save("Screen", ImageFormat.Png);
- }
private void btn_Screen_Click(object sender, EventArgs e) { Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics g = Graphics.FromImage(myImage); g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)); //IntPtr dc1 = g.GetHdc(); //此处这两句多余,具体看最后GetHdc()定义 //g.ReleaseHdc(dc1); g.Dispose(); this.pictureBox_Src.SizeMode = PictureBoxSizeMode.StretchImage; this.pictureBox_Src.Image = myImage; myImage.Save("Screen", ImageFormat.Png); }
3.翻转
- private void btn_RotateFlip_Click(object sender, EventArgs e)
- {
- this.pictureBox_Src.Image = Image.FromFile("1.png");
- Image tmp = Image.FromFile("1.png");
- tmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
- this.pictureBox_Dest.Image = tmp;
- }
private void btn_RotateFlip_Click(object sender, EventArgs e) { this.pictureBox_Src.Image = Image.FromFile("1.png"); Image tmp = Image.FromFile("1.png"); tmp.RotateFlip(RotateFlipType.Rotate90FlipNone); this.pictureBox_Dest.Image = tmp; }
4.跟随鼠标在 pictureBox的图片上画矩形
- private int intStartX = 0;
- private int intStartY = 0;
- private bool isMouseDraw = false;
- private void pictureBox_Src_MouseDown(object sender, MouseEventArgs e)
- {
- isMouseDraw = true;
- intStartX = e.X;
- intStartY = e.Y;
- }
- private void pictureBox_Src_MouseMove(object sender, MouseEventArgs e)
- {
- if (isMouseDraw)
- {
- try
- {
- //Image tmp = Image.FromFile("1.png");
- Graphics g = this.pictureBox_Src.CreateGraphics();
- //清空上次画下的痕迹
- g.Clear(this.pictureBox_Src.BackColor);
- Brush brush = new SolidBrush(Color.Red);
- Pen pen = new Pen(brush, 1);
- pen.DashStyle = DashStyle.Solid;
- g.DrawRectangle(pen, new Rectangle(intStartX > e.X ? e.X : intStartX, intStartY > e.Y ? e.Y : intStartY, Math.Abs(e.X - intStartX), Math.Abs(e.Y - intStartY)));
- g.Dispose();
- //this.pictureBox_Src.Image = tmp;
- }
- catch (Exception ex)
- {
- ex.ToString();
- }
- }
- }
- private void pictureBox_Src_MouseUp(object sender, MouseEventArgs e)
- {
- isMouseDraw = false;
- intStartX = 0;
- intStartY = 0;
- }
private int intStartX = 0; private int intStartY = 0; private bool isMouseDraw = false; private void pictureBox_Src_MouseDown(object sender, MouseEventArgs e) { isMouseDraw = true; intStartX = e.X; intStartY = e.Y; } private void pictureBox_Src_MouseMove(object sender, MouseEventArgs e) { if (isMouseDraw) { try { //Image tmp = Image.FromFile("1.png"); Graphics g = this.pictureBox_Src.CreateGraphics(); //清空上次画下的痕迹 g.Clear(this.pictureBox_Src.BackColor); Brush brush = new SolidBrush(Color.Red); Pen pen = new Pen(brush, 1); pen.DashStyle = DashStyle.Solid; g.DrawRectangle(pen, new Rectangle(intStartX > e.X ? e.X : intStartX, intStartY > e.Y ? e.Y : intStartY, Math.Abs(e.X - intStartX), Math.Abs(e.Y - intStartY))); g.Dispose(); //this.pictureBox_Src.Image = tmp; } catch (Exception ex) { ex.ToString(); } } } private void pictureBox_Src_MouseUp(object sender, MouseEventArgs e) { isMouseDraw = false; intStartX = 0; intStartY = 0; }
5.取灰度
- private void btn_GetGray_Click(object sender, EventArgs e)
- {
- this.pictureBox_Src.Image = Image.FromFile("1.png");
- Bitmap currentBitmap = new Bitmap(this.pictureBox_Src.Image);
- Graphics g = Graphics.FromImage(currentBitmap);
- ImageAttributes ia = new ImageAttributes();
- float[][] colorMatrix = {
- new float[] {0.299f, 0.299f, 0.299f, 0, 0},
- new float[] {0.587f, 0.587f, 0.587f, 0, 0},
- new float[] {0.114f, 0.114f, 0.114f, 0, 0},
- new float[] {0, 0, 0, 1, 0},
- new float[] {0, 0, 0, 0, 1}
- };
- ColorMatrix cm = new ColorMatrix(colorMatrix);
- ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
- g.DrawImage(currentBitmap, new Rectangle(0, 0, currentBitmap.Width, currentBitmap.Height), 0, 0, currentBitmap.Width, currentBitmap.Height, GraphicsUnit.Pixel, ia);
- this.pictureBox_Dest.Image = (Image)(currentBitmap.Clone());
- g.Dispose();
- }
private void btn_GetGray_Click(object sender, EventArgs e) { this.pictureBox_Src.Image = Image.FromFile("1.png"); Bitmap currentBitmap = new Bitmap(this.pictureBox_Src.Image); Graphics g = Graphics.FromImage(currentBitmap); ImageAttributes ia = new ImageAttributes(); float[][] colorMatrix = { new float[] {0.299f, 0.299f, 0.299f, 0, 0}, new float[] {0.587f, 0.587f, 0.587f, 0, 0}, new float[] {0.114f, 0.114f, 0.114f, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }; ColorMatrix cm = new ColorMatrix(colorMatrix); ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(currentBitmap, new Rectangle(0, 0, currentBitmap.Width, currentBitmap.Height), 0, 0, currentBitmap.Width, currentBitmap.Height, GraphicsUnit.Pixel, ia); this.pictureBox_Dest.Image = (Image)(currentBitmap.Clone()); g.Dispose(); }
Graphics.GetHdc 方法
.NET Framework 4
获取与此 Graphics 关联的设备上下文的句柄。
命名空间: System.Drawing
程序集: System.Drawing(在 System.Drawing.dll 中)
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags =
SecurityPermissionFlag.UnmanagedCode)]
public IntPtr GetHdc()
返回值
类型:System.IntPtr
与此 Graphics 关联的设备上下文的句柄。
实现
设备上下文是一个基于 GDI 的 Windows 结构,它定义一组图形对象及其关联的特性,以及影响输出的图形模式。 此方法返回该设备上下文(字体除外)。由于未选择字体,使用 GetHdc 方法返回的句柄对 FromHdc 方法进行调用将会失败。
GetHdc 方法调用和 ReleaseHdc 方法调用必须成对出现。 在 GetHdc 和 ReleaseHdc 方法对的范围内,通常仅调用 GDI 函数。 在该范围内对 Graphics(它产生 hdc 参数)的 GDI+ 方法的调用因 ObjectBusy 错误而失败。 此外,GDI+ 忽略后续操作中对 hdc 参数的 Graphics 所做的所有状态更改。
下面的代码示例设计为与 Windows 窗体一起使用,它需要 PaintEventArgse,即 Paint 事件处理程序的一个参数。 该示例演示如何调用 Windows GDI 函数以执行与 GDI+ Graphics 方法相同的任务。 代码执行下列操作:
- 为 Windows DLL 文件 gdi32.dll 定义互操作性 DllImportAttribute 特性。 此 DLL 包含所需的 GDI 函数。
- 将该 DLL 中的 Rectangle 函数定义为外部函数。
- 创建一支红色钢笔。
- 利用该钢笔,使用 GDI+ DrawRectangle 方法将矩形绘制到屏幕。
- 定义内部指针类型变量 hdc 并将它的值设置为窗体的设备上下文句柄。
- 使用 GDI Rectangle 函数将矩形绘制到屏幕。
释放由 hdc 参数表示的设备上下文。
- public class GDI
- {
- [System.Runtime.InteropServices.DllImport("gdi32.dll")]
- internal static extern bool Rectangle(
- IntPtr hdc,
- int ulCornerX, int ulCornerY,
- int lrCornerX, int lrCornerY);
- }
- [System.Security.Permissions.SecurityPermission(
- System.Security.Permissions.SecurityAction.LinkDemand, Flags =
- System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
- private void GetHdcForGDI1(PaintEventArgs e)
- {
- // Create pen.
- Pen redPen = new Pen(Color.Red, 1);
- // Draw rectangle with GDI+.
- e.Graphics.DrawRectangle(redPen, 10, 10, 100, 50);
- // Get handle to device context.
- IntPtr hdc = e.Graphics.GetHdc();
- // Draw rectangle with GDI using default pen.
- GDI.Rectangle(hdc, 10, 70, 110, 120);
- // Release handle to device context.
- e.Graphics.ReleaseHdc(hdc);
- }
public class GDI { [System.Runtime.InteropServices.DllImport("gdi32.dll")] internal static extern bool Rectangle( IntPtr hdc, int ulCornerX, int ulCornerY, int lrCornerX, int lrCornerY); } [System.Security.Permissions.SecurityPermission( System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)] private void GetHdcForGDI1(PaintEventArgs e) { // Create pen. Pen redPen = new Pen(Color.Red, 1); // Draw rectangle with GDI+. e.Graphics.DrawRectangle(redPen, 10, 10, 100, 50); // Get handle to device context. IntPtr hdc = e.Graphics.GetHdc(); // Draw rectangle with GDI using default pen. GDI.Rectangle(hdc, 10, 70, 110, 120); // Release handle to device context. e.Graphics.ReleaseHdc(hdc); }