图像灰度化方法总结及其VC实现
最近一段时间作者开始进行运动目标识别定位系统设计,本文以及后续的几篇文章都是从一个图像处理初学者的角度来总结目标检测定位过程中所应用到的各种常见的算法,尤其是解决算法实现过程中由于粗心大意或者C编程基本功不扎实所引起的各种问题。本文主要对彩色图片灰度化的方法及其实现过程进行总结,最终给出实现的C代码。
在进行视频流目标识别与跟踪时,通常第一个步骤就是对采集到的彩色图像进行灰度化,这是因为黑白照片数据量小,相比彩照更易实现实时算法,另一方面黑白照片是由未处理的光线所形成的照片,因此从图像处理学角度来看,这种未经特殊滤光处理的图片所涵盖的信息更有价值。
目前,在图像处理过程中,最常用的彩色图片格式有RGB,HSV、YUV以及HLS三种。以下分别对这三种格式的彩色图像进行灰度化实现。
1、RGB空间图像
定义于RGB空间的彩色图,其每个像素点的色彩由R、G、B三个分量共同决定。每个分量在内存所占的位数共同决定了图像深度,即每个像素点所占的字节数。以常见的24深度彩色RGB图来说,其三个分量各占1个字节,这样每个分量可以取值为0~255,这样一个像素点可以有1600多万(255*255*255)的颜色的变化范围。对这样一幅彩色图来说,其对应的灰度图则是只有8位的图像深度(可认为它是RGB三个分量相等),这也说明了灰度图图像处理所需的计算量确实要少。不过需要注意的是,虽然丢失了一些颜色等级,但是从整幅图像的整体和局部的色彩以及亮度等级分布特征来看,灰度图描述与彩色图的描述是一致的。
对于RGB图像进行灰度化,通俗点说就是对图像的RGB三个分量进行加权平均得到最终的灰度值。最常见的加权方法如下:
1)Gray=B;Gray=G;Gray=R
2)Gray=max(B+G+R)
3)Gray=(B+G+R)/3
4)Gray= 0.072169B+ 0.715160G+ 0.212671R
5)Gray= 0.11B+ 0.59G+ 0.3R
这三种方法中,第一种为分量法,即用RGB三个分量的某一个分量作为该点的灰度值;第二种方法为最大值法,将彩色图像中的三分量亮度的最大值作为灰度图的灰度值。第三种方法将彩色图像中的三分量亮度求平均得到一个灰度图;后两种都是属于加权平均法,其中第四种是OpenCV开放库所采用的灰度权值,第五种为从人体生理学角度所提出的一种权值(人眼对绿色的敏感最高,对蓝色敏感最低)。
2、其他颜色空间的灰度化
关于HSV以及HLS颜色空间的彩色图灰度化,可以参考网页《HSL和HSV色彩空间》,该网页中所述方法可将几种不同颜色表达方式进行转换,将其转换到RGB空间,然后再采用上述公式进行灰度化。
关于YUV空间的彩色图像,其Y的分量的物理意义本身就是像素点的亮度,由该值反映亮度等级,因此可根据RGB和YUV颜色空间的变化关系建立亮度Y与R、G、B三个颜色分量的对应:Y=0.3R+0.59G+0.11B,以这个亮度值表达图像的灰度值。
HSL和HSV都是一种将RGB色彩模型中的点在圆柱坐标系中的表示法。这两种表示法试图做到比RGB基于笛卡尔坐标系的几何结构更加直观。
HSL即色相、饱和度、亮度(英语:Hue, Saturation, Lightness),又称HLS。
HSV即色相、饱和度、明度(英语:Hue, Saturation, Value),又称HSB,其中B即英语:Brightness。
- 色相(H)是色彩的基本属性,就是平常所说的颜色名称,如红色、黄色等。
- 饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。
- 明度(V),亮度(L),取0-100%。
从RGB到HSL或HSV的转换[编辑]
设 (r, g, b)分别是一个颜色的红、绿和蓝坐标,它们的值是在0到1之间的实数。设max等价于r, g和b中的最大者。设min等于这些值中的最小者。要找到在HSL空间中的 (h, s, l)值,这里的h ∈ [0, 360)度是角度的色相角,而s, l ∈ [0,1]是饱和度和亮度,计算为:
h的值通常规范化到位于0到360°之间。而h = 0用于max = min的(就是灰色)时候而不是留下h未定义。
HSL和HSV有同样的色相定义,但是其他分量不同。HSV颜色的s和v的值定义如下:
从HSL到RGB的转换[编辑]
给定HSL空间中的 (h, s, l)值定义的一个颜色,带有h在指示色相角度的值域[0, 360)中,分别表示饱和度和亮度的s和l在值域[0, 1]中,相应在RGB空间中的 (r, g, b)三原色,带有分别对应于红色、绿色和蓝色的r, g和b也在值域[0, 1]中,它们可计算为:
首先,如果s = 0,则结果的颜色是非彩色的、或灰色的。在这个特殊情况,r, g和b都等于l。注意h的值在这种情况下是未定义的。
当s ≠ 0的时候,可以使用下列过程:[1]
- (h进行单位换算成[0,1)转内)
对于每个颜色向量Color = (ColorR, ColorG, ColorB) = (r, g, b),
从HSV到RGB的转换[编辑]
类似的,给定在HSV中 (h, s, v)值定义的一个颜色,带有如上的h,和分别表示饱和度和明度的s和v变化于0到1之间,在RGB空间中对应的 (r, g, b)三原色可以计算为(R,G,B变化于0到1之间):
对于每个颜色向量 (r, g, b),
3、代码实现
本文旨在对整个实现原理及思路进行总结,因此以下基于OpenCv的基本函数实现这几种变化过程,至于位图以及其他形式的图像,在获取了图像原始数据后,处理方法都一样,仅需注意指针的位置操作即可。具体代码如下:
- IplImage *ColorImage; //定义相应的图像指针
- IplImage *GrayImage1; //从1~5代表5中不同权值的结果
- IplImage *GrayImage2;
- IplImage *GrayImage3;
- IplImage *GrayImage4;
- IplImage *GrayImage5;
- IplImage *GrayImage6;
- IplImage *GrayImage7;
- ColorImage = cvLoadImage( "49138.jpg", -1 ); //读取图片
- if (ColorImage == NULL)
- return;
- GrayImage1 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage2 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage3 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage4 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage5 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage6 = cvCreateImage(cvGetSize(ColorImage),8,1);
- GrayImage7 = cvCreateImage(cvGetSize(ColorImage),8,1);
- CvMat* pGrayMat1 = NULL; //定义与图像关联的数据指针
- CvMat* pGrayMat2 = NULL;
- CvMat* pGrayMat3 = NULL;
- CvMat* pGrayMat4 = NULL;
- CvMat* pGrayMat5 = NULL;
- CvMat* pGrayMat6 = NULL;
- CvMat* pGrayMat7 = NULL;
- pGrayMat1 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat2 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat3 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat4 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat5 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat6 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- pGrayMat7 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);
- BYTE data1; //中间过程变量
- BYTE data2;
- BYTE data3;
- BYTE data4;
- BYTE data5;
- BYTE data6;
- BYTE data7;
- for(int j=0; j<ColorImage->height; j++)
- {
- for(int i=0; i<ColorImage->width; i++)
- {
- data1 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3]; //B分量
- data2 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3 + 1];//G分量
- data3 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3 + 2];//R分量
- data4 = max(data1, max(data2, data3)); //最大值
- data5 = (BYTE)((data1 + data2 + data3)/3);
- data6 = (BYTE)(0.072169*data1 + 0.715160*data2 + 0.212671*data3);
- data7 = (BYTE)(0.11*data1 + 0.59*data2 + 0.30*data3);
- cvmSet(pGrayMat1, j, i, data1);
- cvmSet(pGrayMat2, j, i, data2);
- cvmSet(pGrayMat3, j, i, data3);
- cvmSet(pGrayMat4, j, i, data4);
- cvmSet(pGrayMat5, j, i, data5);
- cvmSet(pGrayMat6, j, i, data6);
- cvmSet(pGrayMat7, j, i, data6);
- }
- }
- cvConvert(pGrayMat1, GrayImage1);
- cvConvert(pGrayMat2, GrayImage2);
- cvConvert(pGrayMat3, GrayImage3);
- cvConvert(pGrayMat4, GrayImage4);
- cvConvert(pGrayMat5, GrayImage5);
- cvConvert(pGrayMat6, GrayImage6);
- cvConvert(pGrayMat7, GrayImage7);
- cvNamedWindow( "ColorImage",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage1",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage2",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage3",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage4",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage5",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage6",CV_WINDOW_AUTOSIZE);
- cvNamedWindow( "GrayImage7",CV_WINDOW_AUTOSIZE);
- cvShowImage("ColorImage", ColorImage);
- cvShowImage("GrayImage1", GrayImage1);
- cvShowImage("GrayImage2", GrayImage2);
- cvShowImage("GrayImage3", GrayImage3);
- cvShowImage("GrayImage4", GrayImage4);
- cvShowImage("GrayImage5", GrayImage5);
- cvShowImage("GrayImage6", GrayImage6);
- cvShowImage("GrayImage7", GrayImage7);
- cvWaitKey(0);
- cvDestroyWindow("ColorImage");
- cvDestroyWindow("GrayImage1");
- cvDestroyWindow("GrayImage2");
- cvDestroyWindow("GrayImage3");
- cvDestroyWindow("GrayImage4");
- cvDestroyWindow("GrayImage5");
- cvDestroyWindow("GrayImage6");
- cvDestroyWindow("GrayImage7");
- cvReleaseImage(&ColorImage);
- cvReleaseImage(&GrayImage1);
- cvReleaseImage(&GrayImage2);
- cvReleaseImage(&GrayImage3);
- cvReleaseImage(&GrayImage4);
- cvReleaseImage(&GrayImage5);
- cvReleaseImage(&GrayImage6);
- cvReleaseImage(&GrayImage7);
- cvReleaseMat(&pGrayMat1);
- cvReleaseMat(&pGrayMat2);
- cvReleaseMat(&pGrayMat3);
- cvReleaseMat(&pGrayMat4);
- cvReleaseMat(&pGrayMat5);
- cvReleaseMat(&pGrayMat6);
- cvReleaseMat(&pGrayMat7);
IplImage *ColorImage; //定义相应的图像指针IplImage *GrayImage1; //从1~5代表5中不同权值的结果IplImage *GrayImage2;IplImage *GrayImage3;IplImage *GrayImage4;IplImage *GrayImage5;IplImage *GrayImage6;IplImage *GrayImage7;ColorImage = cvLoadImage( "49138.jpg", -1 ); //读取图片if (ColorImage == NULL)return; GrayImage1 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage2 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage3 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage4 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage5 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage6 = cvCreateImage(cvGetSize(ColorImage),8,1);GrayImage7 = cvCreateImage(cvGetSize(ColorImage),8,1);CvMat* pGrayMat1 = NULL; //定义与图像关联的数据指针CvMat* pGrayMat2 = NULL;CvMat* pGrayMat3 = NULL;CvMat* pGrayMat4 = NULL;CvMat* pGrayMat5 = NULL;CvMat* pGrayMat6 = NULL;CvMat* pGrayMat7 = NULL;pGrayMat1 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat2 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat3 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat4 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat5 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat6 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);pGrayMat7 = cvCreateMat(ColorImage->height, ColorImage->width, CV_32FC1);BYTE data1; //中间过程变量BYTE data2;BYTE data3;BYTE data4;BYTE data5;BYTE data6;BYTE data7;for(int j=0; j<ColorImage->height; j++){for(int i=0; i<ColorImage->width; i++){ data1 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3]; //B分量data2 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3 + 1]; //G分量data3 = (BYTE)ColorImage->imageData[j*ColorImage->widthStep + i*3 + 2]; //R分量data4 = max(data1, max(data2, data3)); //最大值data5 = (BYTE)((data1 + data2 + data3)/3);data6 = (BYTE)(0.072169*data1 + 0.715160*data2 + 0.212671*data3);data7 = (BYTE)(0.11*data1 + 0.59*data2 + 0.30*data3);cvmSet(pGrayMat1, j, i, data1);cvmSet(pGrayMat2, j, i, data2);cvmSet(pGrayMat3, j, i, data3);cvmSet(pGrayMat4, j, i, data4);cvmSet(pGrayMat5, j, i, data5);cvmSet(pGrayMat6, j, i, data6);cvmSet(pGrayMat7, j, i, data6);}}cvConvert(pGrayMat1, GrayImage1);cvConvert(pGrayMat2, GrayImage2);cvConvert(pGrayMat3, GrayImage3);cvConvert(pGrayMat4, GrayImage4);cvConvert(pGrayMat5, GrayImage5);cvConvert(pGrayMat6, GrayImage6);cvConvert(pGrayMat7, GrayImage7);cvNamedWindow( "ColorImage",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage1",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage2",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage3",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage4",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage5",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage6",CV_WINDOW_AUTOSIZE);cvNamedWindow( "GrayImage7",CV_WINDOW_AUTOSIZE);cvShowImage("ColorImage", ColorImage);cvShowImage("GrayImage1", GrayImage1);cvShowImage("GrayImage2", GrayImage2);cvShowImage("GrayImage3", GrayImage3);cvShowImage("GrayImage4", GrayImage4);cvShowImage("GrayImage5", GrayImage5);cvShowImage("GrayImage6", GrayImage6);cvShowImage("GrayImage7", GrayImage7);cvWaitKey(0);cvDestroyWindow("ColorImage");cvDestroyWindow("GrayImage1");cvDestroyWindow("GrayImage2");cvDestroyWindow("GrayImage3");cvDestroyWindow("GrayImage4");cvDestroyWindow("GrayImage5");cvDestroyWindow("GrayImage6");cvDestroyWindow("GrayImage7");cvReleaseImage(&ColorImage);cvReleaseImage(&GrayImage1);cvReleaseImage(&GrayImage2);cvReleaseImage(&GrayImage3);cvReleaseImage(&GrayImage4);cvReleaseImage(&GrayImage5);cvReleaseImage(&GrayImage6);cvReleaseImage(&GrayImage7);cvReleaseMat(&pGrayMat1);cvReleaseMat(&pGrayMat2);cvReleaseMat(&pGrayMat3);cvReleaseMat(&pGrayMat4);cvReleaseMat(&pGrayMat5);cvReleaseMat(&pGrayMat6);cvReleaseMat(&pGrayMat7);
各种不同方法实现灰度化的效果图对比如下;
图1 待处理的原始图像—脱离低级趣味的猫
图2 分量灰度化—B分量
图3 分量灰度化—G分量
图4 分量灰度化—R分量
图5 最大值灰度化
图6 均值灰度化
图7 OpenCV权值系数灰度化
图8 网络常用权值灰度化
4、思考
上文的代码实现中,以最后一种方法为例,用到了如下代码:
Gray= (0.11* Blue + 0.59* Green + 0.30* Red);
实际计算机处理时,这种方法已经很快了,但实际上还存在可以优化的余地。以上代码所采用的是浮点运算。而在图像处理中,速度就是生命,实时性往往是很重要的指标,这就要求我们在实现算法时必须考虑到代码的效率问题。所以有一个原则:在图像处理中,能不用浮点运算,就最好不要用!
因此,上述代码可以等效的优化为:
Gray = (30 * Red + 59 *Green + 11 * Blue) / 100;
这样一改,可以有效避免浮点运算,因此可以提高代码的效率
对这行代码还可以继续改进为如下:
Gray= HiByte(77 * Red + 151 * Green + 28 * Blue);
其中77,151,28分别除以256,即为上文的三个系数。
同样的,还可以实现为:
Gray= (77 * Red + 151 * Green + 28 * Blue) shr 8;
这种方法实现了移位运算,避免了除法,效率上又有所提高。
关于具体的代码效率问题,可以参考博文《由图像的灰度化看基本图像处理》。
文章出处:http://blog.csdn.net/likezhaobin/article/details/6915754
图像灰度化方法总结及其VC实现相关推荐
- 基于机器视觉的图像灰度化方法比较分析
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 01. 引言 由于现代工业生产中大部分的工件是彩色物件,而对于计算 ...
- 图像彩色化方法(深度学习)
无论是基于局部颜色扩展的着色方法,还是基于颜色传递的着色方法,都是具有一定的局限性,而将深度学习的思想应用于图像着色中,可以对于传统着色方法的局限性有针对性的进行改进.利用深度神经网络和彩色图像数据集 ...
- java 求集合平均数_图像二值化方法介绍(转载学习)
ImageJ中图像二值化方法介绍 概述 二值图像分析在对象识别与模式匹配中有重要作用,同时也在机器人视觉中也是图像处理的关键步骤,选择不同图像二值化方法得到的结果也不尽相同.本文介绍超过十种以上的基于 ...
- 图像二值化方法及适用场景分析(OTSU Trangle 自适应阈值分割)
图像二值化 应用场景 二值图像定义 阈值获取的方法 手动阈值法 自动阈值法 灰度均值法 基于直方图均值法 OTSU Triangle 自适应均值阈值分割方法 总结 参考文献 应用场景 二值图像处理与分 ...
- 清华大学提出基于生成对抗神经网络的自然图像多风格卡通化方法并开源代码...
近日,清华大学刘永进教授课题组在 IEEE Transactions on Visualization and Computer Graphics 上发表论文,提出基于生成对抗神经网络的自然图像多风格 ...
- 清华大学提出基于生成对抗神经网络的自然图像多风格卡通化方法并开源代码
近日,清华大学刘永进教授课题组在 IEEE Transactions on Visualization and Computer Graphics 上发表论文,提出基于生成对抗神经网络的自然图像多风格 ...
- 图像配准方法之灰度信息法
这系列文章是5年前的,也是从自己的QQ(632846506)日志中移过来的.https://user.qzone.qq.com/632846506/infocenter. 图像配准的方法主要有三种:基 ...
- 8.OpenCvSharp图像灰度处理(分量法、最大值法、平均法、加权平均法)——c#OpenCvSharp学习笔记
OpenCvSharp图像灰度处理(分量法.最大值法.平均法.加权平均法) 项目概述 项目实现了基于OpenCvSharp实现了图像灰度处理,包含了分量法.最大值法.平均法.加权平均法等灰度处理方法的 ...
- 图像灰度化的三种方法(matlab、C++、Python实现)
灰度化处理就是将一幅色彩图像转化为灰度图像的过程.彩色图像分为R,G,B三个分量,分别显示出红绿蓝等各种颜色,灰度化就是使彩色的R,G,B分量相等的过程.灰度值大的像素点比较亮(像素值最大为255,为 ...
最新文章
- 大厂围城:千辛万苦杀进来,为何他们选择出逃?
- POSA2:Wrapper Facade模式
- Win10环境下安装压缩包版本MySQL-8.0.13
- rabbitmq队列的exclusive,durability,auto-delete属性以及消息可靠传输设计
- python 发邮件 timeout_python3 发送邮件 出现的问题(新手)
- python要求将字符串循环右移n次_python 基础知识
- 爬虫之requests库的使用
- 数据库查询·聚合分支格式化日期·思维导图要点误点(含示例)
- sql 查询关联字段 最好取别名 不然会被第一个覆盖
- Uploading File using Ajax and receiving binary data in Asp.net (C#)[转]
- 雕刻机可以制作PCB
- Ubuntu设置双显示器
- 发帖机python_有没有自动发帖机,用python写得
- JavaScript,for循环效率测试,不同遍历循环测试,数组添加效率测试,大数组拼接测试,for循环遍历修改 和 string replace效率
- 好用的图形工具yEd Graph Editor
- HDU - 1573 X问题
- 前端之jQuery框架/全面教程/一小时速成/常用点整合 【附代码、前端必备之一】
- 项目集成腾讯移动直播总结--后端
- VSS 2005 安装,配置简明手册 及VSS2005下载地址
- 手机GPS天线设计对GPS定位有影响
热门文章
- android studio 布局设计,Andriod界面设计适配和Android Studio中的资源
- listview中getview异步加载网络图片
- Java线程专栏文章汇总(转)
- 一个python停车管理系统_Python简易版的停车管理系统
- html盒子优先级设置,CSS 基础(盒模型、选择器、权重、优先级)
- 虚拟服务器配置推荐,如何选择虚拟主机配置
- 关于pad、智能手机功能增进的设想
- java collection 常用类_分析Collection常用的实现类
- 公布几个流氓软件分析报告——哇哇资讯精灵
- 基于GDAL实现的PCA变换(主成分分析)