Opencv之简单皮肤检测代码

    经过前人学者大量的皮肤统计信息可以知道,如果将皮肤信息映射到YCrCb空间,则在CrCb二维空间中这些皮肤像素点近似成一个椭圆分布。因此如果我们得到了一个CrCb的椭圆,下次来一个坐标(Cr, Cb)我们只需判断它是否在椭圆内(包括边界),如果是,则可以判断其为皮肤,否则就是非皮肤像素点。

    本文写这篇博客是参考了一个大牛的,我把自己看完总结的笔记写在这里,如有雷同也很正常。


一、前言:  

    参考小短文http://www.cnblogs.com/tornadomeet/archive/2012/12/05/2802428.html,该文章里面首先直接给出了一个比较合理的椭圆,即该椭圆能够代表大部分人的皮肤信息CrCb的分布。椭圆的分布如下:

  Opencv之简单皮肤检测代码_第1张图片

该图像是二值图像,即椭圆区域内部为白色,其它地方为黑色。所以当其需要判断其它像素点时,只需将该像素点转换成Cr,Cb两个坐标,然后在上面的椭圆中找到该坐标的值,如果大于0,则为皮肤,反之亦然。

ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);
该函数是用来在指定图片上绘制椭圆弧线的。
  参数image为需要绘制椭圆的图像;
  参数center是该椭圆的中心点坐标;
  参数axes是该椭圆的长半轴和短半轴;
  参数angle是该椭圆和水平方向上的旋转夹角;
  参数startAngle表示绘制椭圆弧线相对该椭圆自己的水平轴的起始角度;
  参数endAngel表示绘制椭圆弧线相对该椭圆自己的水平轴的终止角度;
算法过程:

    通过给出要求检测皮肤的图像A,再把A转换成YCrCb空间,通过YCrCb空间的坐标点找对应椭圆图,若此时椭圆图的像素非零,那么这一点就是皮肤的像素;然后此点(像设像素为255)赋给掩膜mask,再通过掩膜确定最后检测出的皮肤三通道区域。


二、实现

#include
#include
using namespace std;
using namespace cv;

#define WINDOW_1 "srcImage"
#define WINDOW_2 "out_maskImage"
#define WINDOW_3 "dstImage"

Mat g_srcImage, in_dstImage, map_x, map_y;
Mat skin_Ellipse;

Mat srcImage, YcrcbImage,out_maskImage, dstImage;

void  Vertical_transformation(int, void*)
{
	for (int i = 0; i < srcImage.rows; i++)
	{
		for (int j = 0; j < srcImage.cols; j++)
		{
			map_x.at(i, j) = static_cast(srcImage.cols-i);
			map_y.at(i, j) = static_cast(j-80);
		}
	}
	remap(srcImage, in_dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar::all(0));
	imshow("视频旋转", in_dstImage);
}
int main()
{
	bool stop = true;
	VideoCapture cap("D://vvoo1//me.avi");
	if (!cap.isOpened())
	{
		cout << "video is error! " << endl; return 0;
	}

	while (stop)
	{
		cap >> srcImage;
		if (srcImage.empty())return 0;
		cout << "srcImage.rows= " << srcImage.rows << endl << "srcImage.cols= " << srcImage.cols << endl<(i, j);//获得YCrCb空间每个像素的值
				if (skin_Ellipse.at(ycrcb[1], ycrcb[2])>0)//判断YCrCb空间每个像素的值在skin_Ellipse标准椭圆中是否为皮肤像素点
					out_maskImage.at(i, j) = 255;//大于零则是皮肤点,对应此像素点在掩膜out_maskImage中设为255
			}
		}
		in_dstImage.copyTo(dstImage, out_maskImage);
		imshow(WINDOW_2, out_maskImage);
		imshow(WINDOW_3, dstImage);
		dstImage.setTo(0);

		if (waitKey(30) > 0)
		stop = false;
	
	}
	return 0;
}

结果:

图片是我自己拍的,但是横屏的,所以程序里设置下编程竖屏了,因为是自拍放了张掩膜mask(二值图),实验效果很好但是比较占用CPU。

Opencv之简单皮肤检测代码_第2张图片

 实验总结: 皮肤的椭圆模型确实可以用来做皮肤检测,一旦确定好了该椭圆就可以用来做皮肤检测了。


三、资料参考

1.http://www.cnblogs.com/tornadomeet/archive/2012/12/05/2802428.html

2.http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html?highlight=ellipse#cv.Ellipse

你可能感兴趣的:(Opencv常用函数介绍,mask掩膜,皮肤检测,皮肤分割,opencv)