图像处理的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的内存类型安全检查。
个人觉得内存法最为合适。
浙公网安备 33010602011771号