OpenCV学习笔记(06):OpenCV颜色空间转换的两种方式

1.背景知识

1)什么是色域?

在计算机图形当中,色域是对颜色进行编码的一种方案,最常见的编码方案是RGB模式。

我个人的理解是,色域是计算机描述色彩空间的一种量化方式,颜色对于人而言,是一种感性而主观的概念(比如说,蓝蓝的天空,白白的云),但在计算机中,对于颜色的描述必须数字化,以0和1的方式表达,那么如何规定这些表达,色域遍应运而生,比如在计算机内存中,蓝色为RGB(0,0,255),对应值#0000FF,白色为RGB(255,255,255),对应值#FFFFFF。计算机在内存中以0和1编码方式存储这些值,然后再根据不同的值调用屏幕显示设备不同的显示输出,得到对应的像素点颜色显示。
OpenCV学习笔记(06):OpenCV颜色空间转换的两种方式_第1张图片

2)什么是颜色空间?

本质上,颜色空间是坐标系统和子空间的阐述。位于系统的每种颜色都有单个点表示。采用的大多数颜色模型都是面向硬件或面向应用的。颜色空间从提出到现在已经有上百种,大部分只是局部的改变或专用于某一领域。颜色空间有许多种,常用有RGB,CMY,HSV,HSI等。
OpenCV学习笔记(06):OpenCV颜色空间转换的两种方式_第2张图片
以RGB为例,举个例子——

我们知道,一幅图像的基本组成单位是以RGB为基础展开的,为此可以理解为一个图像由RGB这样的三个元素组成,R为一个红色通道,表示为1;G为一个绿色通道,表示为2;B 为一个蓝色通道,表示为3;有一处白色图像则为4,它是由1、2、3处的通道颜色混合而成,这相当于我们使用的调色板,几种颜色混合在一起将产生一种新的颜色

2.使用cvtColor函数进行颜色空间的转换

OpenCV对于色彩空间的转换提供了很好的支持,cvtColor函数可以直接用于部分空间的色彩转换

cvtColor函数

void cv::cvtColor	(InputArray 	src,
OutputArray 	dst,
int 	code,
int 	dstCn = 0
)		

第一个参数表示输入图像
第二个参数表示输出图像
第三个参数表示转换的编码,比如,RGB转灰度图对应COLOR_BGR2GRAY
第四个参数表示输出图像的通道数,默认为0,表示由参数code来决定

一个例子,RGB转灰度图

#include
#include
using namespace std;
using namespace cv;
int main()
{
	Mat src = imread("E:\\Test.jpg");
	Mat dst(src.rows,src.cols, src.type());
	
	cvtColor(src, dst, COLOR_BGR2GRAY);
	imshow("BGR", src);
	imshow("GRAY", dst);
	waitKey(0);

	return 0;
}

运行结果

注意:
  1.OpenCV里图像的默认模式是BGR,而不是RGB;
  2.如果转换模式对应的编号填错的话,会产生运行时异常;
  3.cvtColor支持原地操作。

3.自己编写转换函数——RGB到YIQ的转换

如果遇到OpenCV不支持的色域空间,该怎么办?

下面我们通过RGB转YIQ的例子,来介绍一种简单粗暴的解决方案——

思路: 我们可以通过色域转换矩阵对图像像素的每一个元素进行转换,进而得到最后的结果

RGB转YIQ的转换矩阵为

即,

Y=0.299R+0.587G+0.114B
I=0.596R-0.274G-0.322B
Q=0.211R-0.523G+0.312B

程序实现如下——

#include
using namespace cv;

int main()
{
	Mat src = imread("E:\\1.jpg");
	src.convertTo(src, CV_32FC3);
	
	Mat dst = src.clone();

	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++){
			dst.at<Vec3f>(i, j)[2] = (((0.299*src.at<Vec3f>(i, j)[2] +
				0.587*src.at<Vec3f>(i, j)[1] +
				0.114*src.at<Vec3f>(i, j)[0])) / 255);
			dst.at<Vec3f>(i, j)[1] = (((0.596*src.at<Vec3f>(i, j)[2] +
				-0.274*src.at<Vec3f>(i, j)[1] +
				-0.322*src.at<Vec3f>(i, j)[0])) / 255);
			dst.at<Vec3f>(i, j)[0] = (((0.211*src.at<Vec3f>(i, j)[2] +
				-0.523*src.at<Vec3f>(i, j)[1] +
				0.312*src.at<Vec3f>(i, j)[0])) / 255);
		}
	}

	imshow("YIQ", dst);
	waitKey(0);

	return 0;
}

运行结果

一些说明:

  • 由公式不难看出,该转换矩阵涉及到浮点型运算,因此,为了提高运算精度,我们也应当把矩阵转换为浮点型。并且,需要注意的是,整型RGB取值范围是0255,浮点型对应01,故而,在运算过程中,做了除以255的归一性处理;
  • imshow对于图像显示会因存储类型的不同而不同,如果矩阵是浮点型,那么必须保证其值在0~1范围内,不然图片很可能显示纯白或者纯黑(超出范围,默认为0或者1,对应黑色和白色),因此,从整型到浮点型,除了covertTo函数转换类型外,归一化处理,必不可少。

4. 参考文献

[1] http://blog.csdn.net/yjhxdzyx/article/details/43488153

你可能感兴趣的:(OpenCV)