图像灰度化的实现
2016-05-29 21:44
211 查看
来源:http://blog.csdn.net/likezhaobin/article/details/6915754
在进行视频流目标识别与跟踪时,通常第一个步骤就是对采集到的彩色图像进行灰度化,这是因为黑白照片数据量小,相比彩照更易实现实时算法,另一方面黑白照片是由未处理的光线所形成的照片,因此从图像处理学角度来看,这种未经特殊滤光处理的图片所涵盖的信息更有价值。
目前,在图像处理过程中,最常用的彩色图片格式有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开放库所采用的灰度权值,第五种为从人体生理学角度所提出的一种权值(人眼对绿色的敏感最高,对蓝色敏感最低)。
关于HSV以及HLS颜色空间的彩色图灰度化,可以参考网页《HSL和HSV色彩空间》,该网页中所述方法可将几种不同颜色表达方式进行转换,将其转换到RGB空间,然后再采用上述公式进行灰度化。
关于YUV空间的彩色图像,其Y的分量的物理意义本身就是像素点的亮度,由该值反映亮度等级,因此可根据RGB和YUV颜色空间的变化关系建立亮度Y与R、G、B三个颜色分量的对应:Y=0.3R+0.59G+0.11B,以这个亮度值表达图像的灰度值。
本文旨在对整个实现原理及思路进行总结,因此以下基于OpenCv的基本函数实现这几种变化过程,至于位图以及其他形式的图像,在获取了图像原始数据后,处理方法都一样,仅需注意指针的位置操作即可。具体代码如下:
[cpp] view
plain copy
print?
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);
在进行视频流目标识别与跟踪时,通常第一个步骤就是对采集到的彩色图像进行灰度化,这是因为黑白照片数据量小,相比彩照更易实现实时算法,另一方面黑白照片是由未处理的光线所形成的照片,因此从图像处理学角度来看,这种未经特殊滤光处理的图片所涵盖的信息更有价值。
目前,在图像处理过程中,最常用的彩色图片格式有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,以这个亮度值表达图像的灰度值。
3、代码实现
本文旨在对整个实现原理及思路进行总结,因此以下基于OpenCv的基本函数实现这几种变化过程,至于位图以及其他形式的图像,在获取了图像原始数据后,处理方法都一样,仅需注意指针的位置操作即可。具体代码如下:[cpp] view
plain copy
print?
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);
相关文章推荐
- 二维费用的背包问题
- 二叉树的深度优先遍历和广度优先遍历
- 偶遇processing
- 第13周项目1 (2)
- 【Leetcode】Coin Change
- python脚本: 双向统计文件字符、单词数、行数
- 无痛安装MS出品的android虚拟机
- python 字符串前加r的作用
- 简单的K-means算法C语言实现代码
- JavaScript框架思想3
- 关于sync_with_stdio(false);
- php-联想搜索
- 【Leetcode】Word Break
- B/S之CSS简介
- 关于性能测试几个名词概念的说明
- Servlet的历史与规范
- |NOIOJ|NOIP2015|二分|10:河中跳房子
- 哇咔咔咔,第一次优秀
- 线程-Pthread 笔记
- 【Leetcode】Gas Station