【OpenCV】4th-基于YCrCb颜色空间的颜色识别

opencv学习笔记(一):基于YCrCb颜色空间的肤色检测
颜色空间YCrCb

HSV颜色空间中H、S、V的标准差相对于YCrCb空间的标准差要大。而在YCrCb空间中,Y的标准差要明显大于其他两者。标准差越大则表明其值在亮度变化时波动大,因此选择标准差小的颜色通道比较好。

在人脸检测中也常常用到YCrCb空间,因为一般的图像都是基于RGB空间的,在RGB空间里人脸的肤色受亮度影响相当大,所以肤色点很难从非肤色点中分离出来,也就是说在此空间经过处理后,肤色点是离散的点,中间嵌有很多非肤色,这为肤色区域标定(人脸标定、眼睛等)带来了难题。如果把RGB转为YCrCb空间的话,可以忽略Y(亮度)的影响,因为该空间受亮度影响很小,肤色会产生很好的类聚。这样就把三维的空间将为二维的CrCb,肤色点会形成一定得形状,如:人脸的话会看到一个人脸的区域,手臂的话会看到一条手臂的形态,对处理模式识别很有好处。

YUV与RGB相互转换的公式如下(RGB取值范围均为0-255)︰   
Y = 0.299R + 0.587G + 0.114B   
U = -0.147R - 0.289G + 0.436B   
V = 0.615R - 0.515G - 0.100B   
R = Y + 1.14V   G = Y - 0.39U - 0.58V   B = Y + 2.03U  

#include "stdafx.h"
#include 
#include 

#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;



int main()
{
    VideoCapture cap(0);
    if (!cap.isOpened())
    {
        return -1;
    }
    namedWindow("result");
    namedWindow("frame");
    Mat frame;
    Mat result, tmp;
    Mat Y, Cr, Cb;
    vector channels;
    bool stop = false;
    while (!stop)
    {

        cap >> frame;                       //读取视频帧
        frame.copyTo(tmp);                  //拷贝备份
        /*转换颜色空间并分割颜色通道*/
        cvtColor(tmp, tmp, CV_BGR2YCrCb);   
        split(tmp, channels); //CV_EXPORTS void split(const Mat& m, vector& mv );
        Y = channels.at(0);
        Cr = channels.at(1);
        Cb = channels.at(2);

        result.create(frame.rows, frame.cols, CV_8UC1);  //一般的图像文件格式使用的是 Unsigned 8bits,CvMat矩阵对应的参数类型就是CV_8UC1,CV_8UC2,CV_8UC3(最后的1、2、3表示通道数,譬如RGB3通道就用CV_8UC3)


        /*遍历图像,将符合阈值范围的像素设置为255,其余为0*/
        for (int j = 1; j < Y.rows - 1; j++)
        {
            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] > 30) && (currentCr[i] < 115) && (currentCb[i] > 90) && (currentCb[i] < 240))
                    current[i] = 255;
                else
                    current[i] = 0;
            }
        }

        imshow("frame", frame);
        imshow("result", result);

        if (waitKey(30) >= 0)
            stop = true;
    }

    cv::waitKey();
    return 0;
}

识别蓝色,参数为:

for (int i = 1; i < Y.cols - 1; i++)
  {
      if ((currentCr[i] > 30) && (currentCr[i] < 115) && (currentCb[i] > 140) && (currentCb[i] < 240))
         current[i] = 255;
      else
         current[i] = 0;
  }

此时受背景的灯的边缘光影响较小,略有噪点,且离摄像头的距离的影响也较大,深色浅色也有差别。

你可能感兴趣的:(OpenCV)