代码改变世界

图像处理的3种方法 @ Lennon

2010-07-29 14:03  张抗  阅读(634)  评论(1)    收藏  举报

      主要介绍图像处理的3种方法以及对3种处理方法优缺点和性能耗时比较

      C#图像处理的3种方法:提取像素法、内存法和指针法

      1.提取像素法

      该方法主要使用GDI+中的Bitmap.GetPixel和Bitmap.SetPixel方法。为了将位图的颜色设置成灰度或其他颜色,就需要使用GetPixel来读取当前像素的颜色,在计算灰度值,最后使用SetPixel来应用新的颜色。

     

 

//提取像素法
private void 提取像素法_Click(object sender, EventArgs e)
{
if(curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
Color curColor;
int ret;

//二维图像数组循环
for (int i = 0; i < curBitmap.Width; i++)
{
for (int j = 0; j < curBitmap.Height ; j++)
{
//获取该点像素的RGB颜色值
curColor = curBitmap.GetPixel(i,j);
//利用公式(2,2)计算灰度值
ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
//设置该点像素的灰度值,R=G=B=ret
curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
}
}
//性能测试计算
myTimer.Stop();
timeBox.Text
= myTimer.Duration.ToString("####.##") + " 毫秒";
//对窗体进行重新绘制,这将强制执行Paint事件处理程序
Invalidate();
}
}

 

         2.内存法

         该方法就是把图像数据直接复制到内存中,这样就使程序的运行速度大大提高。

        

//内存法
private void 内存法_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
//位图矩形
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;
//24位BMP位图字节数
int bytes = curBitmap.Width * curBitmap.Height * 3;
//定义位图数组
byte[] rgbValues = new byte[bytes];
//复制被锁定的位图像素值到该数组内
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

//灰度化
double colorTemp = 0;
for (int i = 0; i < rgbValues.Length; i += 3)
{
//利用公式(2,2)计算灰度值
colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;
rgbValues[i]
= rgbValues[i + 1] = rgbValues[i + 2] = (byte)colorTemp;
}
//把数组复制回位图
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
//解锁位图像素
curBitmap.UnlockBits(bmpData);
//性能测试时间
myTimer.Stop();
timeBox.Text
= myTimer.Duration.ToString("####.##") + " 毫秒";
//对窗体进行重新绘制,这样强制执行Paint事件处理程序
Invalidate();
}
}

 

 

         3.指针法

         该方法与内存法相似,开始都是通过LockBits方法来获取位图的首地址。但该方法更简洁,直接应用指针对位图进行操作。

         为了保持类型安全,在默认情况下,C#是不支持指针运算符,因为使用指针会带来相关的风险。所以C#只允许在特别标记的代码块中使用指针。通过使用unsafe关键字,可以定义可使用指针的不安全上下文。

 

//指针法
private void 指针法_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
myTimer.ClearTimer();
myTimer.Start();
//位图矩形
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);
byte temp = 0;
//启动不安全模式
unsafe
{
//得到首地址
byte* ptr = (byte*)(bmpData.Scan0);
//二维图像循环
for (int i = 0; i < bmpData.Height; i++)
{
for (int j = 0; j < bmpData.Width; j++)
{
//利用公式(2,2)计算灰度值
temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
ptr[
0] = ptr[1] = ptr[2] = temp;
//指向下一个像素
ptr += 3;
}
//指向下一行数组的首个字节
ptr += bmpData.Stride - bmpData.Width * 3;
}
}
//解锁位图像素
curBitmap.UnlockBits(bmpData);
//测试性能时间
myTimer.Stop();
timeBox.Text
= myTimer.Duration.ToString("####.##") + " 毫秒";
//对窗体进行重新绘制,这将强制执行Paint事件处理程序
Invalidate();
}
}

3种方法比较结果:

方  法                          提取像素法                 内 存 法               指 针 法

平均运行时间(ms)               635                       10                          9

以上结果来分析

提取像素法应用GDI+中的方法,易于理解,方法简单,适合C#初学者使用,但它的运行速度最慢,效率最低。

内存法把图像复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大。

指针法直接应用指针来对图像进行处理,所以速度最快。但在C#中,是不建议使用指针的。C#特性之一,代码都是受托管的,代码不仅难以编写和调试,而且无法通过CLR的内存类型安全检查。

个人觉得内存法最为合适。