C#本身自带有一定的图像处理能力,即使在不依赖Emgu CV的情况下,也是有很大的潜质的。

不过,最近在处理大量图片时,发现图片数量较少时,处理本身所带来的延时不会让人敏感,但是数量较大时,程序花费大量时间在预处理图片上,导致程序很容易误报线程时延过大,导致误判程序异常。对于这个问题苦恼很久,毕竟不是CS专业出身,对于图像处理以及一些算法和库的运用上感到毕竟吃力。

今天在阅读了一些数字图像处理的书之后感到收益很大,现在来做点试验对照一下之前自己的错误在哪里。

之前看MS的C#API时候发现有一个Graphics挺适合我现在使用,于是便二话不说开干,今天才发现越来封装的太好,反而会带来许多拖累,不如操起指针畅快的运行。

不多说,试验对比的是Graphics、操作内存、操作指针三者在性能上差距。

试验内容:对同一张照片进行灰度处理,直接看三者之间延时有多大

1.试验基本场景,比较丑陋,就凑合看着。。。

2.提取像素Button中,调用Graphics灰度化处理

private void button2_Click(object sender, EventArgs e)
{
if (curBitMap1 != null)
{
Color curColor;
int ret;
//个人运行时间判断类
GetRunTime getRunTime = new GetRunTime();
//stopWatch启动
getRunTime.Start();
//Graphics//灰度化
for (int i = (int)(0); i < (int)(curBitMap1.Width ); i++)
{
for (int j = 0; j < curBitMap1.Height; j++)
{
//获取像素
curColor = curBitMap1.GetPixel(i, j);
//获取RGB
ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
//设置像素
curBitMap1.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
}
}
Invalidate(); labelGetPixel.Text = "提取像素花费时间:" + getRunTime.getRunTime() + "ms"; }
}

  

3.内存法Button中,直接复制数据到内存,直接操作

private void button5_Click(object sender, EventArgs e)
{
if (curBitMap2 != null)
{
GetRunTime getRunTime = new GetRunTime();
getRunTime.Start();
Rectangle rect = new Rectangle(0, 0, curBitMap2.Width, curBitMap2.Height);
//以读写方式锁定位图
System.Drawing.Imaging.BitmapData bmpData =
curBitMap2.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, curBitMap2.PixelFormat);
//首地址
IntPtr ptr = bmpData.Scan0;
//24位bmp的总字节数
int bytes = curBitMap2.Width * curBitMap2.Height * 3;
byte[] rgbValues = new byte[bytes];
//复制被锁定的图像到rgbValues
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
double colorTemp = 0;
//灰度化
for (int i = 0; i < bmpData.Height; i++)
{
for (int j = 0; j < bmpData.Width * 3; j+=3)
{
//跳过空白块
colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299
+ rgbValues[i * bmpData.Stride + j + 1] * 0.587
+ rgbValues[i * bmpData.Stride + j] * 0.114;
rgbValues[i * bmpData.Stride + j + 2]
= rgbValues[i * bmpData.Stride + j + 1]
= rgbValues[i * bmpData.Stride + j] = (byte)colorTemp;
}
}
//复制回位图
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
curBitMap2.UnlockBits(bmpData);
Invalidate();
labelCaChe.Text = "提取像素内存法花费时间:" + getRunTime.getRunTime() + "ms";
}
}

  

4.指针法Button中,直接复制数据到内存,指针操作 

private void button6_Click(object sender, EventArgs e)
{
GetRunTime getRunTime = new GetRunTime();
getRunTime.Start();
Rectangle rect = new Rectangle(0, 0, curBitMap3.Width, curBitMap3.Height);
//以读写方式锁定位图
System.Drawing.Imaging.BitmapData bmpData =
curBitMap3.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, curBitMap3.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++ )
{
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;
}
}
//解锁位图
curBitMap3.UnlockBits(bmpData); Invalidate();
labelPoint.Text = "提取像素内存法花费时间:" + getRunTime.getRunTime() + "ms";
}

5,简单完善一下就开始打开图片看看运行时间之间的对比吧

总结:虽然电脑烂,但还是看得出三者之间的差距吧。复制进内存直接操作和用指针操作都是极大的提高效率,如果处理一张图片节约60ms,那处理大量的图片时候将会节约多少时间?所以今后处理图像的时候,如果不用Emgu,尽量也别用Graphics,还是自己动手操作内存。(肯定会有人说,你为毛不去用C++,好吧,我其实就是在黑Graphics,你咬我呀~)

C# 处理图像三种方法对比的更多相关文章

  1. Sql"列转行"三种方法对比

    SQL code------ 合并列值  --***************************************************************************** ...

  2. Sql 列转行 三种方法对比

    合并列值   --******************************************************************************************* ...

  3. 高并发下用pdo,文件排它锁,redis三种方法对比

    <?php header('content-type:text/html;charset=utf-8');                 // //无控制     // $DB_DSN = ' ...

  4. 两个Map的对比,三种方法,将对比结果写入文件。

    三种方法的思维都是遍历一个map的Key,然后2个Map分别取这2个Key值所得到的Value. #第一种用entry private void compareMap(Map<String, S ...

  5. opencv图像阈值设置的三种方法

    1.简单阈值设置   像素值高于阈值时,给这个像素赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色).这个函数就是 cv2.threshhold().这个函数的第一个参数就是原图像 ...

  6. Halcon一日一练:读取文件目录图像的三种方法

    第一种方法: 读了一个单一图像: read_image(Image,'fabrik') 这种方式可以快速的读取软件自身携带的库图像文件,系统设定了库图像映像文件的快速读取方式,我们也可以通过绝对地址的 ...

  7. c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)

    c#封装DBHelper类   public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...

  8. Qt 设置背景图片3种方法(三种方法:QPalette调色板,paintEvent,QSS)

    方法1. setStylSheet{"QDialog{background-image:url()"}}  //使用styleSheet 这种方法的好处是继承它的dialog都会自 ...

  9. C语言清空输入缓冲区的N种方法对比

    转自C语言清空输入缓冲区的N种方法对比 C语言中有几个基本输入函数: //获取字符系列 int fgetc(FILE *stream); int getc(FILE *stream); int get ...

随机推荐

  1. TOAD Menu Shortcuts 快捷键

    TOAD Menu Shortcuts Category Command Shortcut Conflict File AWR Browser File Compare Files File DBMS ...

  2. extjs动态树 动态grid 动态列

    由于项目需要做一个动态的extjs树.列等等,简而言之,就是一个都是动态的加载功能, 自己琢磨了半天,查各种资料,弄了将近两个星期,终于做出来了 首先,想看表结构,我的这个功能需要主从两张表来支持 代 ...

  3. Eclipse SVN插件安装与使用(2014.12.27——by小赞)

    安装参考:http://www.cnblogs.com/xdp-gacl/p/3497016.html 用法参考:http://blog.sina.com.cn/s/blog_8a3d83320100 ...

  4. HW4.30

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  5. tomcat详细日志配置

    在server.xml里的<host>标签下加上<Valve className="org.apache.catalina.valves.AccessLogValve&qu ...

  6. eclipse 反编译class 文件 插件-jad

    1.下载 jad.exe  http://pan.baidu.com/s/1i3Ga33n 2.下载jadeclipse http://pan.baidu.com/s/1bn4H1iZ  放在ecli ...

  7. 329. Longest Increasing Path in a Matrix

    最后更新 三刷? 找矩阵里的最长路径. 看起来是DFS,实际上也就是.但是如果从每个点都进行一次DFS然后保留最大的话,会超时. 这里需要结合DP,dp[i][j]表示以此点开始的最长路径,这样每次碰 ...

  8. Java intern()方法

    intern()方法: public String intern() JDK源代码如下图: 返回字符串对象的规范化表示形式. 一个初始时为空的字符串池,它由类 String 私有地维护. 当调用 in ...

  9. Material Design之TextInputLayout、Snackbar的使用

    这两个控件也是Google在2015 I/O大会上公布的Design Library包下的控件,使用比較简单,就放在一起讲了,但有的地方也是须要特别注意一下. TextInputLayout Text ...

  10. springMVC3学习(八)--全球异常处理

    在springMVC在配置文件: <bean id="exceptionResolver" class="org.springframework.web.servl ...