最近没事,有网上看到一篇关于图像处理的文章,觉得很好,结合它上面的原理,自己写了一个C#图像处理的例子。这个DEMO的界面的有两个PictrueBox控件,用来显示图片,一个是源图片,一个是经过转换的目标图片,UI下面部分有一些按钮,每个按钮实现一个转换功能。这个DEMO允许用户拖一张图片到源PictureBox中,然后通过这些功能按钮实现图片的效果转换。这些功能有把图片变成黑白、底片、浮雕、锐化、柔化等效果。首先来一张运行效果图:
这个DEMO主要有以下几个机能点:
图像处理
PictureBox的拖拽。
计算处理时间
对图像进行缩放处理
[DllImport("kernel32.dll")] private static extern bool QueryPerformanceCounter(ref long lpPerformanceCount); [DllImport("kernel32.dll")] private static extern bool QueryPerformanceFrequency(ref long lpFrequency);
Bitmap bitmap = new Bitmap(newWidth, newHeight, oldImage.PixelFormat); Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.Transparent); g.DrawImage(oldImage, new RectangleF(0, 0, newWidth, newHeight)); return Image.FromHbitmap(bitmap.GetHbitmap());
public enum ImageEffect { GrayScale = 0, // 黑白 Film = 1, // 底片 Relief = 2, // 浮雕 Soften = 3, // 柔化 Sharpen = 4, // 锐化 Canvas = 5, // 油画 }
在按钮处理程序中根据不同的按钮ID,给ImageEffectManager类的ChangeEffect方法传递不同的参数。ChangeEffect方法的定义如下:
public void ChangeEffect(ImageEffect effect) { switch(effect) { case ImageEffect .GrayScale : break; } }
ImageEffectManager.cs类 图像效果管理
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; namespace ImageEffectSample.Classes { public enum ImageEffect { GrayScale = 0, // 黑白 Film = 1, // 底片 Relief = 2, // 浮雕 Soften = 3, // 柔化 Sharpen = 4, // 锐化 Canvas = 5, // 油画 } public class ImageEffectManager { private Bitmap newBitmap = null; private Bitmap oldBitmap = null; #region Properties public Bitmap ConvertedBitmap { get { return this.newBitmap; } } public Bitmap OriginalBitmap { set { DisposeBitmap(); this.oldBitmap = value; } } public Size PixelSize { get { if (this.oldBitmap != null) { GraphicsUnit unit = GraphicsUnit.Pixel; RectangleF bounds = this.oldBitmap.GetBounds(ref unit); return new Size( (int)bounds.Width, (int)bounds.Height); } return new Size(0, 0); } } #endregion #region Methods public ImageEffectManager() { } public void DisposeBitmap() { if (this.newBitmap != null) { this.newBitmap.Dispose(); this.newBitmap = null; } } public void ChangeEffect(ImageEffect effect) { if (null == this.oldBitmap) { return; } Size size = PixelSize; int width = size.Width; int height = size.Height; this.DisposeBitmap(); this.newBitmap = new Bitmap(width, height); switch (effect) { case ImageEffect.GrayScale: MakeGrayScale(width, height); break; case ImageEffect.Film: MakeFilmEffect(width, height); break; case ImageEffect.Relief: MakeReliefEffect(width, height); break; case ImageEffect.Soften: MakeSoftenEffect(width, height); break; case ImageEffect.Sharpen: MakeSharpenEffect(width, height); break; } } private void MakeGrayScale(int width, int height) { Color c; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { c = this.oldBitmap.GetPixel(x, y); /////////////////////////////////////////////////////// // // Average // int value = (c.R + c.G + c.B) / 3; // /////////////////////////////////////////////////////// // Weighted average int value = (int)(0.7 * c.R) + (int)(0.2 * c.G) + (int)(0.1 * c.B); this.newBitmap.SetPixel(x, y, Color.FromArgb(c.A, value, value, value)); } } } private void MakeFilmEffect(int width, int height) { Color c; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { c = this.oldBitmap.GetPixel(x, y); this.newBitmap.SetPixel(x, y, Color.FromArgb(c.A, 255 - c.R, 255 - c.G, 255 - c.B)); } } } private void MakeReliefEffect(int width, int height) { Color c1; Color c2; int r, g, b = 0; for (int x = 0; x < width - 1; x++) { for (int y = 0; y < height - 1; y++) { c1 = this.oldBitmap.GetPixel(x, y); c2 = this.oldBitmap.GetPixel(x + 1, y + 1); r = Math.Abs(c1.R - c2.R + 128); g = Math.Abs(c1.G - c2.G + 128); b = Math.Abs(c1.B - c2.B + 128); r = (r > 255) ? 255 : ((r < 0) ? 0 : r); g = (g > 255) ? 255 : ((g < 0) ? 0 : g); b = (b > 255) ? 255 : ((b < 0) ? 0 : b); this.newBitmap.SetPixel(x, y, Color.FromArgb(c1.A, r, g, b)); } } } private void MakeSoftenEffect(int width, int height) { // The template of Gauss int[] Gauss = { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; Color pixel; 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 = this.oldBitmap.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; this.newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b)); } } } private void MakeSharpenEffect(int width, int height) { 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 = this.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; this.newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b)); } } } private void MakeCanvasEffect(int width, int height) { } #endregion } }
TimeCounter.cs类,用于计算处理时间
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace ImageEffectSample.Classes { public class TimeCounter { private static long startCount = 0; private static long elapsedCount = 0; #region Properties public static float Seconds { get { long freq = 0; float retValue = 0.0f; QueryPerformanceFrequency(ref freq); if (freq != 0) { retValue = (float)elapsedCount / (float)freq; } return retValue; } } #endregion #region Methods public static void Start() { startCount = 0; QueryPerformanceCounter(ref startCount); } public static void Stop() { long stopCount = 0; QueryPerformanceCounter(ref stopCount); elapsedCount = (stopCount - startCount); } #endregion #region Import API [DllImport("kernel32.dll")] private static extern bool QueryPerformanceCounter( ref long lpPerformanceCount); [DllImport("kernel32.dll")] private static extern bool QueryPerformanceFrequency( ref long lpFrequency); #endregion } }
UserControlPictureBox.cs类 封装了图像缩放,拖拽,显示等功能
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Imaging; namespace ImageEffectSample.UserControls { public partial class UserControlPictureBox : UserControl { private bool m_dragDropEnable = true; private bool m_isOriginalSize = false; #region Properties public PictureBox PictrueBoxObject { get { return this.pictureBox; } } public bool DragDropEnable { get { return this.m_dragDropEnable; } set { m_dragDropEnable = value; } } public bool IsOriginalSize { get { return this.m_isOriginalSize; } set { m_isOriginalSize = value; } } #endregion #region Methods public UserControlPictureBox() { InitializeComponent(); this.pictureBox.AllowDrop = true; this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom; this.pictureBox.DragDrop += new DragEventHandler(PictureBox_DragDrop); this.pictureBox.DragEnter += new DragEventHandler(PictureBox_DragEnter); } public void DisposeImage() { if (this.pictureBox.Image != null) { this.pictureBox.Image.Dispose(); this.pictureBox.Image = null; } } private Image ZoomImage(Image oldImage) { if (null == oldImage) { return null; } int width = oldImage.Width; int height = oldImage.Height; int newWidth = 0; int newHeight = 0; float ratioXY = (float)width / (float)height; if ((width > this.pictureBox.Width) || (height > this.pictureBox.Height)) { if (ratioXY >= 1.0) { newWidth = this.pictureBox.Width; newHeight = (int)((float)newWidth / ratioXY) + 1; } else { newHeight = this.pictureBox.Height; newWidth = (int)(newHeight * ratioXY); } Bitmap bitmap = new Bitmap(newWidth, newHeight, oldImage.PixelFormat); Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.Transparent); g.DrawImage(oldImage, new RectangleF(0, 0, newWidth, newHeight)); return Image.FromHbitmap(bitmap.GetHbitmap()); } return oldImage; } #endregion #region PictureBox drag and drop events private void PictureBox_DragEnter(object sender, DragEventArgs e) { bool bflag = e.Data.GetDataPresent(DataFormats.FileDrop); e.Effect = bflag && this.m_dragDropEnable ? e.Effect = DragDropEffects.Copy : DragDropEffects.None; } private void PictureBox_DragDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { String[] strfileNames = (String[])e.Data.GetData(DataFormats.FileDrop); Image dragImage = Image.FromFile(strfileNames[0]); if (dragImage != null) { this.DisposeImage(); this.pictureBox.Image = m_isOriginalSize ? dragImage : ZoomImage(dragImage); } } } #endregion } }
ImageEffectMainWindow.cs类,主窗体
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using ImageEffectSample.Classes; namespace ImageEffectSample.Windows { public partial class ImageEffectMainWindow : Form { ImageEffectManager effectManager = null; public ImageEffectMainWindow() { InitializeComponent(); this.effectManager = new ImageEffectManager(); this.convertedPictureBox.DragDropEnable = false; } private void CheckBoxOriginalSize_CheckedChanged(object sender, EventArgs e) { this.originalPictureBox.IsOriginalSize = this.checkBoxOriginalSize.Checked; } private void Button_Click(object sender, EventArgs e) { this.txtBoxTime.Text = ""; Button button = sender as Button; if (button != null) { TimeCounter.Start(); Image img = this.originalPictureBox.PictrueBoxObject.Image; if (img != null) { effectManager.OriginalBitmap = new Bitmap(img); switch (button.Name) { case "btnGrayScaleEffect": effectManager.ChangeEffect(ImageEffect.GrayScale); break; case "btnFileEffect": effectManager.ChangeEffect(ImageEffect.Film); break; case "btnReliefEffect": effectManager.ChangeEffect(ImageEffect.Relief); break; case "btnSoftenEffect": effectManager.ChangeEffect(ImageEffect.Soften); break; case "btnSharpenEffect": effectManager.ChangeEffect(ImageEffect.Sharpen); break; } this.convertedPictureBox.DisposeImage(); this.convertedPictureBox.PictrueBoxObject.Image = effectManager.ConvertedBitmap; TimeCounter.Stop(); this.txtBoxTime.Text = String.Format("Elapsed time: {0} s", TimeCounter.Seconds.ToString()); } } } private void ClearImagesButton_Click(object sender, EventArgs e) { this.convertedPictureBox.DisposeImage(); this.originalPictureBox.DisposeImage(); this.txtBoxTime.Text = ""; } } }