OpenCV原来自带的皮肤检测类CvAdaptiveSkinDetector,可以通过颜色阈值分割肤色部分,皮肤检测算法是在HSV空间进行,没什么技术含量。
OpenCV自带是算法的参考文献有网友说是An adaptive real-time skin detector based on Hue thresholding: A comparison on two motion tracking methods,主要是把皮肤阈值分割和运动检测相结合。该算法的流程图如下所示:
程序的流程图如下所示:
下面来看看CvAdaptiveSkinDetector类中的2个比较重要的函数:
CvAdaptiveSkinDetector(int samplingDivider = 1, int morphingMethod = MORPHING_METHOD_NONE);
该函数为类的构造函数,
参数1表示的是样本采样的间隔,默认情况下为1,即表示不进行降采样;
参数2为图形学操作方式,即对用皮肤检测后的图像进行图形学操作。其取值有3种可能:MORPHING_METHOD_ERODE,则表示只进行一次腐蚀操作;MORPHING_METHOD_ERODE_ERODE,则表示连续进行2次腐蚀操作;MORPHING_METHOD_ERODE_DILATE,则表示先进行一次腐蚀操作,后进行一次膨胀操作。
virtual void process(IplImage *inputBGRImage, IplImage *outputHueMask);
该函数为皮肤检测的核心函数,
参数1为需要进行皮肤检测的输入图像;
参数2为输出皮肤的掩膜图像,如果其值为1,代表该像素为皮肤,否则当其为0时,代表为非皮肤。
另外需要注意的是,这个函数只有opencv的c版本的,因为CvAdaptiveSkinDetector这个类放在opencv源码里的contrib目录里,即表示比较新的但不成熟的算法,所以暂时没有提供c++版本的opencv。因此参数1和参数2的图像数据类型都是IplImage,如果要使用Mat,就得先进行一个小小的转换。
*IplImage与Mat的转换:
src_img = &src_mat.operator IplImage(); //convert mat to IplImage;
Mat dst_mask = 255*Mat(dst_img); //convert IplImage to Mat;
关于CvAdaptiveSkinDetector类的内容具体细节可以参考:http://www.cnblogs.com/tornadomeet/archive/2012/11/28/2793532.html
代码
Mat skin(const Mat& src_mat)
{
IplImage *src_img, *dst_img;
Mat dst_mat;
CvAdaptiveSkinDetector skin_detector(1,CvAdaptiveSkinDetector::MORPHING_METHOD_NONE);//定义,初始化
src_img = &src_mat.operator IplImage();//convert mat to IplImage
dst_img = cvCreateImage(cvSize(src_img->width, src_img->height), IPL_DEPTH_8U,1);
skin_detector.process(src_img,dst_img);//操作
Mat dst_mask = 255*Mat(dst_img);
src_mat.copyTo(dst_mat,dst_mask);
return dst_mat;
}
由图像可见,实验效果实在不尽如人意。还不如以前自己写的皮肤检测函数的效果好
(学习OpenCV——hand tracking手势跟踪,学习OpenCV——肤色检测),只不过这个已经被OpenCV集成,以后可以方便的调用,而且据说跟运动的物体结合效果会好一些。