为加快处理速度,在图像处理算法中,往往需要把彩色图像抓换成灰色图像,24位彩色图像每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝)。当R、G、B分量值不同是,表示为彩色图像;当R、G、B分量值相同时,表现为灰度图像,也就是求这个值。

黑白处理原理:彩色图像处理成黑白效果通常有3种算法;
(1).最大值法:使每个像素点的R,G,B值等于原像素点的RGB(颜色值)中最大的一个;
(2).平均值法:使用每个像素点的R,G,B值等于原像素点的RGB值的平均值;
(3).加权平均值法:对每个像素点的R,G,B值进行加权;

公式

一般来说,转换工式有3个。

  • 第一种转换公式为:

    其中,Gray(i,j)为转换后的灰度图像在(i,j)点处的灰度值。该方面虽然简单,但人眼对颜色的感应是不同的。
  • 第二种转换公式:

    观察上面的公司,发现绿色所占的比重最大,所以转换时可以直接使用G 值作为转换后的灰度:

Bitmap类介绍

Bitmap对象封装了GDI+中的一个位图,该位图由图形图像及其属性的像素数据组成。因此Bitmap是用于处理由像素数据定义的图像的对象。该类的主要方法和属性如下:

GetPixel方法和 SetPixel方法: 获取和设置一个图像的指定像素的颜色。
PixelFormat : 返回图像的像素格式
Palette : 获取或设置图像所使用的颜色调色板
Height 、Width : 返回图像的高度和宽度
LockBits 、UnlockBits : 分别锁定和解锁系统内存中的位图像素。

在基于像素点的图像处理方法中使用LockBits 和 UnlockBits是一个很好的方式,这两种方法可以使我们通过指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理的需要。每次调用LockBits之后都应该调用一次UnlockBits。

BitmapData类介绍

BitmapData对象指定了位图的属性:
Height属性,被锁定位图的高度。
Width属性,被锁定位图的宽度。
PixelFormat属性,数据的实际像素格式。
Scan0属性,被锁定数组的首字节地址。
Stride属性,步幅,也称扫描宽度。

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

假设有一张图片宽度为6,因为是Format24bppRgb格式(每像素3字节。在以下的讨论中,除非特别说明,否则Bitmap都被认为是24位RGB)的,显然,每一行需要63=18个字节存储。
对于Bitmap就是如此。但对于BitmapData,虽然BitmapData.Width还是等于Bitmap.Width,但大概是出于显示性能的考虑,每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是Stride。
就此例而言,18不是4的整倍数,而比18大的离18最近的4的倍数是20,所以这个BitmapData.Stride=20。
显然,当宽度本身就是4的倍数时,BitmapData.Stride=Bitmap.Width
3。

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

图像处理的3种方法

提取像素法

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

            //加载图像var curBitmap = (Bitmap)Image.FromFile(filePath);Color curColor;int ret;//循环读取像素转换灰度值for (int i = 0; i < curBitmap.Width; i++){for (int j = 0; j < curBitmap.Height ; j++){curColor = curBitmap.GetPixel(i,j);ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));}}

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

内存法

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

   //加载图像var curBitmap = (Bitmap)Image.FromFile(filePath);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;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){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);

指针法

该方法与内存法相似,开始都是通过LockBits方法来获取位图的首地址。但该方法更简洁,直接应用指针对位图进行操作。
为了保持类型安全,在默认情况下,C#是不支持指针运算的,因为使用指针会带来相关的风险。所以C#只允许在特别标记的代码块中使用指针。通过使用unsafe关键字,可以定义可使用指针的不安全上下文。

                //加载图像var curBitmap = (Bitmap)Image.FromFile(filePath);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++){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);

效果预览

总结

内存法和指针法比提取像素法要快得多。提取像素法应用GDI+中的方法,易于理解,方法简单,很适合于C#的初学者使用,但它的运行速度最慢,效率最低。内存法把图像复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大。
指针法直接应用指针来对图像进行处理,所以速度最快。但在C#中,是不建议使用指针的,因为使用指针,代码不仅难以编写和调试,而且无法通过 CLR的内存类型安全检查,不能发挥C#的特长。只有对C#和指针有了充分的理解,才能用好该方法。

究竟要使用哪种方法,还要看具体情况而定。但3种方法都能有效地对图像进行处理。

参考链接:https://www.cnblogs.com/zh7791/p/16194609.html

参考链接:http://www.360doc.com/content/17/0414/20/39573434_645648120.shtml

C#编程,图像转换灰度图的几种方法相关推荐

  1. RGB图像转为灰度图的几种方法

    RGB图像灰度化 RGB图像 我们来看看下面这张图,美不美 这么好看的图是咋个整出来的呢?哦!原来是这样:一幅图像 I I I由很多个像素点组成的,而每个像素点又包含RGB(red,green,blu ...

  2. 图像由彩色图转化为灰度图的三种方法

    一.原理 对于图像由彩色图转化为灰度图有三种方法 分别为 加权法 均值法 最大值法 加权法就是  GRAY==0.3*R+0.59*G+0.11*B 均值法就是 GRAY==(R+G+B)/3 最大值 ...

  3. Java BufferImage图片处理(获取宽高、图片截取、转换灰度图)

    Java BufferImage图片处理(获取宽高.截取.转换灰度图) 1. 效果图 2. 源码 参考 这篇博客将介绍如何使用Java读取图片为byte[]数组,或者BufferedImage及互相转 ...

  4. Android提高十六篇之使用NDK把彩图转换灰度图

    在Android上使用JAVA实现彩图转换为灰度图,跟J2ME上的实现类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK来提高速度了.本文主要通过JAVA和NDK这两种方式来分别实现彩图转换为 ...

  5. python用numpy和pil处理图像成灰度图_「火炉炼AI」机器学习047-图像的直方图均衡化操作...

    [火炉炼AI]机器学习047-图像的直方图均衡化操作 [火炉炼AI]机器学习047-图像的直方图均衡化操作 (本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, sc ...

  6. android png转灰度,Android提高之使用NDK把彩图转换灰度图的方法

    一般而言在Android上使用JAVA实现彩图转换为灰度图,与J2ME上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK来提高速度了.本文主要通过JAVA和NDK这两种方式来分别实 ...

  7. matlab 图像转视频教程,Matlab制作视频并转换成gif动态图的两种方法

    一.第一个方法比较简单,就是使用movie(f)直接取生成AVI视频文件. %% f(t)-->f(4*t+12) 并且验证%% function Signal_change() tic%记录程 ...

  8. html页面转换成图片的三种方法——canvas、dom-to-image、html2canvas

    html页面转换成图片的三种方法--canvas.dom-to-image.html2canvas canvas绘制网络图片报错(跨域) 使用canvas将html页面转成图片 dom-to-imag ...

  9. badatatable转成json_C# DataTable 转换成JSON数据 三种方法

    在web开发中,我们可能会有这样的需求,为了便于前台的JS的处理,我们需要将查询出的数据源格式比如:List.DataTable转换为Json格式.特别在使用Extjs框架的时候,Ajax异步请求的数 ...

最新文章

  1. 使用VSCode调试C#控制台程序
  2. 超图球面与平面场景的区别和地理坐标系
  3. 决胜大数据时代:HadoopYarnSpark企业级最佳实践(3天)
  4. nginx部署laravel需要修改的配置
  5. 字符串比较函数实现,超简单的面试题,回过头来发现原来我的c多么的薄弱
  6. 第八课 魔棒 画笔工具和铅笔工具
  7. sql 排序 分组 层级 筛选 - God聚会啊
  8. vue.js v-if
  9. win7计算机记忆窗口,Win7系统关闭和打开搜索记忆功能的方法(图文教程)
  10. 5g鸿蒙概念,华为5G概念机,真全面屏+鸿蒙系统,颜值再登巅峰
  11. blockUI弹出层
  12. cad中如何关掉坐标系显示
  13. React生命周期钩子函数
  14. linux查看目录是不是btrfs,Linux 文件系统Btrfs 的Kconfig分析
  15. 【Disturbed People】【CodeForces - 1077B】(思维水题)
  16. 百家争鸣的低代码平台
  17. Multi-modal Transformer for Video Retrieval
  18. java php同时访问数据库,Java Spring中同时访问多种不同数据库的代码实例分享
  19. 如何对自己的Unity项目代码进行加密混淆?
  20. 玖月:如果真的能够穿越回到过去,我可能只会给自己一个微笑

热门文章

  1. UART在rtt下驱动实现
  2. 煮饭的机器人作文_做饭机器人作文3篇
  3. 云e办(后端)——员工管理
  4. 【ChatGPT】ChatGPT 在电商B端业务中的应用落地场景产品化思考
  5. 2D和3D游戏动作区分
  6. Android中图片资源文件找不到的问题
  7. ZEGO教程:如何通过electron构建桌面跨平台音视频应用
  8. android高级进阶之12条代码优化以及性能优化
  9. 海康威视热成像实时测温java
  10. 智能手机厂商押注加速技术,是黔驴技穷还是另辟蹊径