1、颜色空间
- OpenCV有超过150多种可用的颜色空间转换方法。
- 在imgproc中提供的函数是void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0),其中src是一副8位无符号、16位无符号或单精度浮点输入图像;dst是与src相同尺寸和深度的输出图像;code是颜色空间转换代码,例如COLOR_BGR2GRAY和COLOR_YCrCb2BGR;dstCn是目标图像的通道数,如果为0或省略,由src和cod自动产生。
①RGB
- RGB是一种加性模型,一副图像由三个独立的图像平面或通道组成(RGB),以及一个可选项透明度,也称为alpha通道。
- void split(InputArray m, OutputArrayOfArrays mv)
- void merge(InputArrayOfArrays mv, OutputArray dst)
②灰度图
- 灰度图中,每个像素只有灰度强度信息单一值,由不同的灰色阴影特别形成的一副图像。
- 转换参数有:COLOR_BGR2GRAY、COLOR_RGB2GRAY、COLOR_GRAY2BGR、COLOR_GRAY2RGB
③CIE XYZ
- 该系统用一个亮度分量Y来描述颜色,它与人类视觉的亮度灵敏度和两个附加通道X和Z相关。
- 转换参数有:COLOR_BGR2XYZ、COLOR_RGB2XYZ、COLOR_XYZ2BGR、COLOR_XYZ2RGB
- 示例代码
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
vector<Mat> showSeparatedChannels(vector<Mat> channnels);
int main()
{
Mat src,dst;
//读入图片
src = imread("test.jpg");
imshow("Ori", src);
//转换为CIEXYZ
cvtColor(src, src, COLOR_BGR2XYZ);
//拆分每个通道并显示
vector<Mat> channels;
split(src, channels);
//在灰度空间中显示通道
namedWindow("X channel(gray)", WINDOW_AUTOSIZE);
imshow("X channel(gray)", channels[0]);
namedWindow("X channel(gray)", WINDOW_AUTOSIZE);
imshow("Y channel(gray)", channels[1]);
namedWindow("X channel(gray)", WINDOW_AUTOSIZE);
imshow("Z channel(gray)", channels[2]);
//在BGR中显示通道
vector<Mat> separatedChannels = showSeparatedChannels(channels);
for(int i=0;i<3;i++){
cvtColor(separatedChannels[i], separatedChannels[i], COLOR_XYZ2BGR);
}
namedWindow("X channel", WINDOW_AUTOSIZE);
imshow("X channel", separatedChannels[0]);
namedWindow("Y channel", WINDOW_AUTOSIZE);
imshow("Y channel", separatedChannels[1]);
namedWindow("Z channel", WINDOW_AUTOSIZE);
imshow("Z channel", separatedChannels[2]);
waitKey();
return 0;
}
vector<Mat> showSeparatedChannels(vector<Mat> channnels) {
vector<Mat> separatedChannels;
//创建每副图像的每个通道
for (int i = 0; i < 3; i++) {
Mat zer = Mat::zeros(channnels[0].rows, channnels[0].cols, channnels[0].type());
vector<Mat> aux;
for (int j = 0; j < 3; j++) {
if (j == i)
aux.push_back(channnels[i]);
else
aux.push_back(zer);
}
Mat chann;
merge(aux, chann);
separatedChannels.push_back(chann);
}
return separatedChannels;
}
④YCrCb
- Y通道表示亮度,Cr和Cb表示红色色差和蓝色色差(Y和R的差值、Y和B的差值)。该颜色空间广泛应用于MPEG和JPEG等视频和图像压缩方案。
- 转换参数有:COLOR_BGR2YCrCb、COLOR_RGB2YCrCb、COLOR_YCrCb2BGR、COLOR_YCrCb2RGB
⑤HSV
- HSV的三个通道表示色度(H给出颜色光谱构成的一种度量),饱和度(S给出主波长中的纯光比例,这表明一种颜色距离相同亮度灰度的程度)和纯度(V给出相对于白色光光照强度的亮度)
- OpenCV的imshow函数以RGB显示图像,如果在其他颜色空间中有一副图像并希望正确显示它,应该先将其转为RGB。
- 示例代码
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat src;
//读入图片
src = imread("test.jpg");
imshow("Ori", src);
//转换为CIEXYZ
cvtColor(src, src, COLOR_BGR2HSV);
//拆分每个通道并显示
vector<Mat> channels;
split(src, channels);
//在灰度空间中显示通道
namedWindow("H channel(gray)", WINDOW_AUTOSIZE);
imshow("H channel(gray)", channels[0]);
namedWindow("S channel(gray)", WINDOW_AUTOSIZE);
imshow("S channel(gray)", channels[1]);
namedWindow("V channel(gray)", WINDOW_AUTOSIZE);
imshow("V channel(gray)", channels[2]);
namedWindow("HSV", WINDOW_AUTOSIZE);
imshow("HSV", src);
waitKey();
return 0;
}
⑥HLS
- HLS与HSV类型,与HSV不同的是:由HLS定义的一种纯颜色的亮度等于一种中等灰色的亮度,而由HSV定义的一种纯颜色的亮度等于白色的亮度。
⑦CIE L*a*b*
- 由CIE XYZ衍生而来。L*表示颜色的亮度,a*表示在品红和绿色之间的位置,b*表示在黄色和蓝色之间的位置。
⑧CIE L*u*v*
- CIE XYZ空间和白色参考点的一种简化计算转换,尝试达到感知均匀性。L*亮度,u*表示位于绿色和红色间位置,v*表示在多大程度上是蓝色和紫色。
⑨Bayer
- Bayer像素空间组合 广泛应用于只有一个图像传感器的数字相机。
2、基于颜色空间的分割
- void inRange( InputArray src, InputArray loewrb, InputArray upperb, OutputArray dst )。检查一个元素数组是否位于两个其他数组的元素之间。获取一副图像src的像素集合,各个通道的值位于下边界lowerb和上边界upperb之间,得到一副图像dst。
①HSV分割
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat src,hsv,bw;
//读入图片
src = imread("test.jpg");
imshow("Ori", src);
//转换为CIEXYZ
cvtColor(src, hsv, COLOR_BGR2HSV);
//选取像素
inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw);
namedWindow("Select pixel", WINDOW_AUTOSIZE);
imshow("Select pixel", bw);
waitKey();
return 0;
}
②YCrCb分割
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat src,ycrcb,bw;
//读入图片
src = imread("test.jpg");
imshow("Ori", src);
//转换为CIEXYZ
cvtColor(src, ycrcb, COLOR_BGR2YCrCb);
//选取像素
inRange(ycrcb, Scalar(0, 133, 77), Scalar(255, 173, 177), bw);
namedWindow("Select pixel", WINDOW_AUTOSIZE);
imshow("Select pixel", bw);
waitKey();
return 0;
}
3、颜色变换
- 为修改一副图像的颜色,特别是在有必要删除一个主要或不希望的颜色场合,方法之一就是颜色变换。
- colorTransfer示例代码
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
Mat src,tar,src_lab,tar_lab,output;
//读入图片
src = imread("test1.jpg");
tar = imread("test2.jpg");
//变换到Lab空间和CV_32F1
cvtColor(src, src_lab, COLOR_BGR2Lab);
cvtColor(tar, tar_lab, COLOR_BGR2Lab);
src_lab.convertTo(src_lab, CV_32FC1);
tar_lab.convertTo(tar_lab, CV_32FC1);
//为每副图像找到每个通道的均值和std值
Mat mean_src, mean_tar, stdd_src, stdd_tar;
meanStdDev(src_lab, mean_src, stdd_src);
meanStdDev(tar_lab, mean_tar, stdd_tar);
//拆分成独立的通道
vector<Mat> src_chan, tar_chan;
split(src_lab, src_chan);
split(tar_lab, tar_chan);
for (int i = 0; i < 3; i++) {
tar_chan[i] -= mean_tar.at<double>(i);
tar_chan[i] *= (stdd_src.at<double>(i) / stdd_src.at<double>(i));
tar_chan[i] += mean_src.at<double>(i);
}
//合并通道,转换到CV_8UC1,并转到BGR
merge(tar_chan, output);
output.convertTo(output, CV_8UC1);
cvtColor(output, output, COLOR_Lab2BGR);
namedWindow("Ori", WINDOW_AUTOSIZE);
imshow("Ori", src);
namedWindow("tar", WINDOW_AUTOSIZE);
imshow("tar", tar);
namedWindow("output", WINDOW_AUTOSIZE);
imshow("output", output);
waitKey();
return 0;
}
4、参考资料
《OpenCV 图像处理》Gloria Bueno Garcia、Oscar Deniz Suarez、Jose Luis Espinosa Aranda著,刘冰 翻译,机械工业出版社出版,2016年11月