C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

您所在的位置:网站首页 浮雕效果滤镜 C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

2024-05-08 14:50| 来源: 网络整理| 查看: 265

弹指一挥间

好好做事,学习待人 (大数据分析/.NET/JAVA)技术交流QQ:860280456; .NET/JAVA技术交流群:192028174

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理 公告 C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

 

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 originalnew Point(100, 100),// destination for upper-right point of originalnew Point(0, 0)}; // destination for lower-left point of originalg.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 originalnew Point(100, 100),// destination for upper-right point of originalnew Point(0, 0)}; // destination for lower-left point of originalg.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 originalnew Point(100, 0), // destination for upper-right point of originalnew Point(50, 100)};// destination for lower-left point of originalg.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 rectangleGraphicsUnit.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 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];   }  现在看看那些地方需要注意的了。其中 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循环中的拷贝部分的处理, 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); } } 二. 浮雕效果 原理: 对图像像素点的像素值分别与相邻像素点的像素值相减后加上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); } } 三. 黑白效果 原理: 彩色图像处理成黑白效果通常有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 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 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 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, "信息提示"); } }                         浅谈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(); } }其中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(); } }三、对像素的访问我们可以来建立一个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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3