在.NET编程中,由于GDI+的出现,使得对于图像的处理功能大大增强。在文通过一个简单黑白处理实例介绍在.NET中常见的图片处理方法和原理并比较各种方法的性能。

黑白处理原理:彩色图像处理成黑白效果通常有3种算法;

(1).最大值法: 使每个像素点的 R, G, B 值等于原像素点的 RGB (颜色值) 中最大的一个;

(2).平均值法: 使用每个像素点的 R,G,B值等于原像素点的RGB值的平均值;

(3).加权平均值法: 对每个像素点的 R, G, B值进行加权

自认为第三种方法做出来的黑白效果图像最 "真实".

1.GetPixel方法

GetPixel(i,j)和SetPixel(i, j,Color)可以直接得到图像的一个像素的Color结构,但是处理速度比较慢.

 /// <summary>/// 像素法/// </summary>/// <param name="curBitmap"></param>private void PixelFun(Bitmap curBitmap){int width = curBitmap.Width;int height = curBitmap.Height;for (int i = 0; i <width; i++) //这里如果用i<curBitmap.Width做循环对性能有影响{for (int j = 0; j < height; j++){Color  curColor = curBitmap.GetPixel(i, j);int ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));}}}

这里提一下,在循环次数控制时尽量不要用i<curBitmap.Width做循环条件,而是应当将其取出保存到一个变量中,这样循环时不用每次从curBitmp中取Width属性,从而提高性能。

尽管如此,直接提取像素法对大像素图片处理力不从心,处理一张1440*900的图片耗时2182ms.本人配置单:

处理之前截图:

处理后:

可以直观地看出用时间2056ms.多次测试有少许波动。

2.内存拷贝法

内存拷贝法就是采用System.Runtime.InteropServices.Marshal.Copy将图像数据拷贝到数组中,然后进行处理,这不需要直接对指针进行操作,不需采用unsafe,处理速度和指针处理相差不大,处理一副1440*900的图像大约需要34ms。

内存拷贝发和指针法都需用到的一个类:BitmapData

BitmapData类

BitmapData对象指定了位图的属性

1.       Height属性:被锁定位图的高度.

2.       Width属性:被锁定位图的高度.

3.       PixelFormat属性:数据的实际像素格式.

4.       Scan0属性:被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.

5.       Stride属性:步幅,也称为扫描宽度.

如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为4的倍数.

假设有一张图片宽度为6,因为是Format24bppRgb格式(每像素3字节。在以下的讨论中,除非特别说明,否则Bitmap都被认为是24位RGB)的,显然,每一行需要6*3=18个字节存储。对于Bitmap就是如此。但对于BitmapData,虽然BitmapData.Width还是等于Bitmap.Width,但大概是出于显示性能的考虑,每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是Stride。就此例而言,18不是4的整倍数,而比18大的离18最近的4的倍数是20,所以这个BitmapData.Stride = 20。显然,当宽度本身就是4的倍数时,BitmapData.Stride = Bitmap.Width * 3。画个图可能更好理解(此图仅代表PixelFormat= PixelFormat. Format24bppRgb时适用,每个像素占3个字节共24位)。R、G、B 分别代表3个原色分量字节,BGR就表示一个像素。为了看起来方便我在每个像素之间插了个空格,实际上是没有的。X表示补足4的倍数而自动插入的字节。为了符合人类的阅读习惯我分行了,其实在计算机内存中应该看成连续的一大段。Scan0||-------Stride-----------||-------Width---------|  |BGR BGR BGR BGR BGR BGR XXBGR BGR BGR BGR BGR BGR XXBGR BGR BGR BGR BGR BGR XX.则对于Format24bppRgb格式,满足:

BitmapData.Width*3 + 每行未使用空间(上图的XX)=BitmapData.Stride

 

同理,很容易推倒对于Format32bppRgb或Format32bppPArgb格式,满足:

BitmapData.Width*4 + 每行未使用空间(上图的XX)=BitmapData.Stride

  /// <summary>/// 内存拷贝法/// </summary>/// <param name="curBitmap"></param>private unsafe void MemoryCopy(Bitmap curBitmap){int width = curBitmap.Width;int height = curBitmap.Height;Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);//curBitmap.PixelFormatIntPtr ptr = bmpData.Scan0;int bytesCount = bmpData.Stride * bmpData.Height;byte[] arrDst = new byte[bytesCount];Marshal.Copy(ptr, arrDst, 0, bytesCount);for (int i = 0; i < bytesCount; i+=3){byte colorTemp = (byte)(arrDst[i + 2] * 0.299 + arrDst[i + 1] * 0.587 + arrDst[i] * 0.114);arrDst[i] = arrDst[i + 1] = arrDst[i + 2] = (byte)colorTemp;}Marshal.Copy(arrDst, 0, ptr, bytesCount);curBitmap.UnlockBits(bmpData);}

3.指针法

指针在c#中属于unsafe操作,需要用unsafe括起来进行处理,速度最快,处理一副180*180的图像大约需要18ms。

 

采用byte* ptr = (byte*)(bmpData.Scan0); 获取图像数据根位置的指针,然后用bmpData.Scan0获取图像的扫描宽度,就可以进行指针操作了。

    /// <summary>/// 指针法/// </summary>/// <param name="curBitmap"></param>private unsafe void PointerFun(Bitmap curBitmap){int width = curBitmap.Width; int height = curBitmap.Height;Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb );//curBitmap.PixelFormatbyte temp = 0;int w = bmpData.Width;int h = bmpData.Height;byte* ptr = (byte*)(bmpData.Scan0);for (int i = 0; i < h; i++){for (int j = 0; j <w; j++){temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);ptr[0] = ptr[1] = ptr[2] = temp;ptr +=3; //Format24bppRgb格式每个像素占3字节}ptr += bmpData.Stride - bmpData.Width * 3 ;//每行读取到最后“有用”数据时,跳过未使用空间XX}curBitmap.UnlockBits(bmpData);    }

以下是多组测试数据:
 
1920*1080
1440*900
1208*800
1024*768
500*544
200*169
直接提取像素法
1705ms
1051ms
1710ms
1340ms
450ms
32ms
内存拷贝法
54ms
33ms
26ms
20ms
7ms
0ms
指针法
28ms
17ms
14ms
10ms
3ms
0ms
 
由此可见,指针法与直接提取像素法效率竟隔两个数量级!

比较以上方法优缺点:

1.总体上性能 指针法略强于内存拷贝法,直接提取像素法性能最低;

2.对大图片处理指针法和内存拷贝法性能提升明显,对小图片都比较快;

3.直接提取像素法简单易用,而且不必关注图片像素格式(PixelFormat),为安全代码;内存拷贝法和指针法如果不改变原图片像素格式要针对不同的像素格式做不同的处理,且为不安全代码。

C#图片处理常见方法性能比较相关推荐

  1. WEB前端性能优化常见方法

    web前端是应用服务器处理之前的部分,前端主要包括:HTML,CSS,javascript,image等各种资源,针对不同的资源有不同的优化方式. 1. 内容优化 (1)减少HTTP请求数:这条策略是 ...

  2. 性能测试之前端性能优化(前端基础知识,前端性能测试常用工具,前端性能优化常见方法)

    目录 1. 前端基础知识 1.1 为什么要关注前端页面的性能,了解页面的加载,渲染方式和顺序? 1.2 一次页面请求会经历哪些步骤? 1.3 页面的展示过程 2. 前端性能测试的常用工具 2.1 Go ...

  3. 可解释机器学习发展和常见方法!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 来源:新智元,编辑:数据派THU 本文约2000字,建议阅读5分钟 本文 ...

  4. 灰度图像阈值化分割常见方法总结及VC实现

    灰度图像阈值化分割常见方法总结及VC实现 分类: 图像处理 OpenCV2011-11-11 23:20 609人阅读 评论(11) 收藏 举报 在图像处理领域,二值图像运算量小,并且能够体现图像的关 ...

  5. [分布式]事务处理的常见方法

    处理事务的常见方法有排队法.排他锁.读写锁.MVCC等方式. 排队法 事务处理中最重要也是最简单的方案是排队法,单线程地处理一堆数据. 在Redis中,如果数据全部在内存中,那么单线程处理所有Put. ...

  6. SQL Server中一些常见的性能问题

    SQL Server中一些常见的性能问题: 1.在对查询进行优化时,应当尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.我们应当尽量避免使用 left jo ...

  7. java 弱引用定位_手把手教你定位常见Java性能问题

    概述 性能优化一向是后端服务优化的重点,但是线上性能故障问题不是经常出现,或者受限于业务产品,根本就没办法出现性能问题,包括笔者自己遇到的性能问题也不多,所以为了提前储备知识,当出现问题的时候不会手忙 ...

  8. 过拟合解决方法python_《python深度学习》笔记---4.4、过拟合与欠拟合(解决过拟合常见方法)...

    <python深度学习>笔记---4.4.过拟合与欠拟合(解决过拟合常见方法) 一.总结 一句话总结: 减小网络大小 添加权重正则化 添加 dropout 正则化 1.机器学习的根本问题? ...

  9. .NET应用程序7种最常见的性能问题及其解决方案

    译者注:这篇文章依然是介绍.NET Framework框架下的性能问题排查,可能并不直接适用于.NET Core,但有时也能提供一些参考. .NET应用程序7种最常见的性能问题及其解决方案 原文地址: ...

最新文章

  1. 换了路由器电脑都连不上网了_技术丨电脑连不上网,我要如何冲浪?
  2. 2.3系列系统中不支持SimpleDateFormat作字段被序列化
  3. php如何实现用户报警,php封装实现钉钉机器人报警接口的示例代码
  4. Android Linux下开发环境搭建
  5. PXE高效批量安装和Kickstart无人值守安装——真正完成批量自动安装
  6. 学习生物信息的系列书籍
  7. docker 改host_所以到底该如何修改 docker 容器的端口映射!!!
  8. kali字典WiFi
  9. python中返回上一步操作的快捷键_在计算机中返回上一步的快捷键
  10. 成功解决 MDK5中No ST-LINK detected的问题
  11. Audio解析strategy配置文件
  12. 中国叶酒市场趋势报告、技术动态创新及市场预测
  13. 一键重装系统后电脑黑屏怎么办,电脑系统重装黑屏
  14. Linux驱动:网卡驱动分析之三--MAC驱动及PHY驱动框架了解
  15. php access 教程 pdf,Access 2007 以PDF 格式保存文件
  16. LeetCode 417. 太平洋大西洋水流问题 JAVA dfs
  17. 深圳云计算培训学习:Apache 访问控制--【千锋】
  18. 共享电动车的产品分析
  19. 2020年最新在线CRM免费下载
  20. python最简单爬虫让人头疼

热门文章

  1. Oracle EBS R12 运行adadmin 安装中文语言包过程中意外中断后的处理
  2. 毫米波雷达、ADAS中的应用以及毫米波雷达的检测、测距、测速和角度测量
  3. 远程过程调用RPC简介
  4. 吴恩达老师深度学习视频课笔记:循环神经网络
  5. Windows7下OpenGL简单使用举例
  6. 【Qt】QtCreator updatePchInfo:switching to none
  7. java 线程通讯_java多线程(五)线程通讯
  8. webkit内核 css,纯CSS改变webkit内核浏览器的滚动条样式
  9. mysql数据库备份方案_MySQL平台数据库备份方案详细说明
  10. qt 5.9 mysql 5.7_Qt 5.9.1 连 MYSQL 5.7数据库