YCrCb也称为YUV,主要用于优化彩色视频信号的传输。与RGB视频信号传输相比,它最大的优点在于只需占用极少的频宽(RGB要求三个独立的视频信号同时传输)。
其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;
而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。
YCrCb颜色空间在做肤色检测上有很好的效果,比HSV颜色空间要好一些
查阅一些网上的资料得知,正常黄种人的Cr分量大约在140 ~ 175之间,Cb分量大约在100 ~ 120之间。
OpenCV中RGB转YCrCb的函数:
cvtColor(inputImage, outputImage, CV_BGR2YCrCb);
效果如下:
这个受光线环境的影响还是挺大的,并不是特别完美的算法。当然可能还要加点滤波程序,比如中值滤波什么的,效果更好一些
代码如下:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
using namespace std;
using namespace cv;
extern int ex;
vector<Mat> get_YCrCb(Mat image);
int main()
{
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << endl << "没有检测到摄像头" << endl;
return -1;
}
namedWindow("result");
namedWindow("frame");
Mat frame, tmp;
Mat result;
Mat Y, Cr, Cb;
vector<Mat> channels;
bool stop = false;
while (!stop)
{
cap >> frame; //读取视频帧
frame.copyTo(tmp);
channels=get_YCrCb(tmp); //转换颜色空间并分割颜色通道
Y = channels.at(0);
Cr = channels.at(1);
Cb = channels.at(2);
//初始化Mat类型的变量 result
result.create(frame.rows, frame.cols, CV_8UC1); //CV_8UC1为单通道类型
//遍历图像,将符合阈值范围的像素设置为255,其余为0
for (int j = 1; j < Y.rows - 1; j++)
{ //ptr< uchar>(j)[i]是第j行的第i个元素,也就是j行i列的像素点
uchar* currentCr = Cr.ptr< uchar>(j);
uchar* currentCb = Cb.ptr< uchar>(j);
uchar* current = result.ptr< uchar>(j);
for (int i = 1; i < Y.cols - 1; i++)
{
if ((currentCr[i] > 137) && (currentCr[i] < 175) && (currentCb[i] > 100) && (currentCb[i] < 118))
current[i] = 255; //满足条件为白
else
current[i] = 0; //否则为黑
}
}
/*
void cv::putText(
cv::Mat& img, // 待绘制的图像
const string& text, // 待绘制的文字
cv::Point origin, // 文本框的左下角
int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
double fontScale, // 尺寸因子,值越大文字越大
cv::Scalar color, // 线条的颜色(RGB)
int thickness = 1, // 线条宽度
int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
bool bottomLeftOrigin = false // true='origin at lower left'
);*/
string text = "Press ESC to exit";
putText(frame, text, Point(frame.cols / 2, frame.rows / 2), FONT_HERSHEY_PLAIN, 2, Scalar(0, 255, 255), 2, 8, 0);
imshow("frame", frame);
imshow("result", result);
if (waitKey(30) == 27)
break;
}
return 0;
}
vector<Mat> get_YCrCb(Mat image) { //转换颜色空间并分割颜色通道
vector<Mat> threeChannels;
cvtColor(image, image, CV_BGR2YCrCb);
split(image, threeChannels);
return threeChannels;
}