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. [转]NHibernate之旅(7):初探NHibernate中的并发控制

    本节内容 什么是并发控制? 悲观并发控制(Pessimistic Concurrency) 乐观并发控制(Optimistic Concurrency) NHibernate支持乐观并发控制 实例分析 ...

  2. 微软原版SQLHelper类

    代码 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-- ...

  3. JavaScript---网络编程(12)--DHTML技术演示(5)-form表单验证技术(正则)

    这里不进行很复杂的后台验证以及JavaScript的正则表达式,只是简单的介绍下这个技术,简单的后台接收与跳转,大概了解怎么验证的就可以.具体的技术,我后面还会继续写博客的.本人也还在学习中. 表单验 ...

  4. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  5. Tyvj P3119 核电站问题 动态规划

    题目:http://tyvj.cn/p/3119 P3119 核电站问题 时间: 1000ms / 空间: 65536KiB / Java类名: Main 描述 一个核电站有N个放核物质的坑,坑排列在 ...

  6. 【转】shell 教程——03 Shell脚本语言与编译型语言的差异

    大体上,可以将程序设计语言可以分为两类:编译型语言和解释型语言. 编译型语言 很多传统的程序设计语言,例如Fortran.Ada.Pascal.C.C++和Java,都是编译型语言.这类语言需要预先将 ...

  7. myEclipse和eclipse修改或复制项目名称后-更新部署名称

    一.myEclipse 复制后修改名称,访问不到项目 这是因为,你只是改了项目的名称,而没有改 下面是解决方法: 方法 1.右击你的项目,选择“properties”,在“type filter te ...

  8. 非常实用的PHP常用函数汇总

    这篇文章主要介绍了非常实用的PHP常用函数,汇总了加密解密.字符串操作.文件操作.SQL注入等函数的实例与用法说明,在PHP项目开发中非常具有实用价值,需要的朋友可以参考下 本文实例总结了一些在php ...

  9. Least Common Multiple

    地址:http://www.codewars.com/kata/5259acb16021e9d8a60010af/train/python 题目: Write a function that calc ...

  10. Apache Solr配置

    Solr配置 Solr的主要功能是全文检索,该功能分为两个过程:创建索引和对索引进行搜索: 在创建索引之前,需要重点关注两个配置文件:SOLR_HOME/collection1/conf/schema ...