OpenCV-基于YCrCb颜色空间的肤色检测

肤色YCbCr颜色空间是一种常用的肤色检测的色彩模型,其中Y代表亮度,Cr代表光源中的红色分量,Cb代表光源中的蓝色分量。人的肤色在外观上的差异是由色度引起的,不同人的肤色分布集中在较小的区域内。肤色的YCbCr颜色空间CbCr平面分布在近似的椭圆区域内,通过判断当前像素点的CbCr是否落在肤色分布的椭圆区域内,就可以很容易地确认当前像素点是否属于肤色。将图像转换到YCbCr空间并且在CbCr平面进行投影,可以采集到肤色的样本点。

将CbCr平面均分为许多小区域,将每个区域的中心点CbCr色度值作为当前区域的特征值,对肤色区域像素值进行遍历,如果当前像素值落在该区域内则替换当前区域特征值。


代码实现:

int main()
{
	cv::Mat image = cv::imread("1.jpg");
	if (image.empty()) return -1;
	cv::imshow("image", image);
	//构建椭圆模型
	cv::Mat skinMat = cv::Mat::zeros(cv::Size(256, 256), CV_8UC1);
	cv::ellipse(skinMat, cv::Point(113, 155.6), cv::Size(26, 22), 43.0, 0.0, 360, cv::Scalar(255, 255, 255), -1);
	//定义结构元素
	cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));
	cv::Mat temp = cv::Mat::zeros(image.size(), CV_8UC1);
	cv::Mat YCrCbMat;
	//颜色空间转换YCrCb
	cv::cvtColor(image, YCrCbMat, CV_BGR2YCrCb);
	//椭圆肤色模型检测
	for (int i = 0; i < image.rows; i++)
	{
		uchar *p1 = (uchar*)temp.ptr(i);
		cv::Vec3b *p2 = (cv::Vec3b*)YCrCbMat.ptr(i);
		for (int j = 0; j < image.cols; j++)
		{
			//颜色判断
			if (skinMat.at(p2[j][1], p2[j][2]) > 0) p1[j] = 255;
		}
	}
	//形态学闭操作
	cv::morphologyEx(temp, temp, cv::MORPH_CLOSE, element);
	//定义轮廓参数
	std::vector > contours;
	std::vector > tempcontours;
	std::vector hierarchy;
	//查找连通域
	//CV_RETR_EXTERNAL:只检测出最外轮廓
	cv::findContours(temp, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
	cv::Mat tmp(image.size(), CV_8UC1, cv::Scalar::all(0));
	//筛选的轮廓
	for (int i = 0; i < contours.size(); i++)
	{
		//判断区域面积
		if (fabs(cv::contourArea(contours[i])) > 1000) tempcontours.push_back(contours[i]);
		for (int j = 0; j < contours[i].size(); j++) tmp.at(contours[i][j].y, contours[i][j].x) = 255;
	}
	cv::imshow("temp", tmp);
	temp.setTo(0);
	//绘制轮廓
	cv::Mat result;
	cv::drawContours(temp, tempcontours, -1, cv::Scalar(255, 0, 0), CV_FILLED);
	image.copyTo(result, temp);
	cv::imshow("result", result);
	cv::waitKey(0);
	return 0;
}


运行结果:

OpenCV-基于YCrCb颜色空间的肤色检测_第1张图片

你可能感兴趣的:(----opencv学习)