最近没事,有网上看到一篇关于图像处理的文章,觉得很好,结合它上面的原理,自己写了一个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 = "";
}
}
}