肤色检测算法

您所在的位置:网站首页 cr的优缺点 肤色检测算法

肤色检测算法

2023-08-14 04:34| 来源: 网络整理| 查看: 265

由于能力有限,算法层面的东西自己去创新的很少,很多都是从现有的论文中学习,然后实践的。

首先列一些现在主流的皮肤检测的方法都有哪些:

RGB color spaceYcrcb之cr分量+otsu阈值化YCrCb中13320 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B

在侧光拍摄环境下:

R>220 AND G>210 AND B>170 AND ABS(R-G)B AND G>B

算法非常之简单,同样主要把复杂的判断条件放到后面去判断,能有效的降低程序的执行时间,参考代码:

/*基于RGB范围的皮肤检测*/ Mat RGB_detect(Mat& img) { /* R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B OR R>220 AND G>210 AND B>170 AND ABS(R-G)B AND G>B */ Mat detect = img.clone(); detect.setTo(0); if (img.empty() || img.channels() != 3) { return detect; } for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { uchar *p_detect = detect.ptr(i, j); uchar *p_img = img.ptr(i, j); if ((p_img[2] > 95 && p_img[1]>40 && p_img[0] > 20 && (MAX(p_img[0], MAX(p_img[1], p_img[2])) - MIN(p_img[0], MIN(p_img[1], p_img[2])) > 15) && abs(p_img[2] - p_img[1]) > 15 && p_img[2] > p_img[1] && p_img[1] > p_img[0]) || (p_img[2] > 200 && p_img[1] > 210 && p_img[0] > 170 && abs(p_img[2] - p_img[1]) p_img[0] && p_img[1] > p_img[0])) { p_detect[0] = p_img[0]; p_detect[1] = p_img[1]; p_detect[2] = p_img[2]; } } } return detect; }

效果如下:

 

从检测结果可以看出,皮肤的检测效果并不好,首先皮肤检测的完整性并不高,一些稍微光线不好的区域也没法检测出皮肤来。第二,这种基于RBG范围来判定皮肤的算法太受光线的影响了,鲁棒性确实不好。

2.基于椭圆皮肤模型的皮肤检测

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

 

这种基于肤色椭圆模型的算法的皮肤检测较上面算法在效果上有着较大的提升。

3.YCrCb颜色空间Cr分量+Otsu法阈值分割

这里先简单介绍YCrCb颜色空间。 YCrCb即YUV,其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面─色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异。而Cb反映的是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。

该方法的原理也很简单:

a.将RGB图像转换到YCrCb颜色空间,提取Cr分量图像

b.对Cr做自二值化阈值分割处理(Otsu法)

效果:

可以看出这种方法效果也还不错。

4.基于YCrCb颜色空间Cr,Cb范围筛选法

这个方法跟法一其实大同小异,只是颜色空间不同而已。据资料显示,正常黄种人的Cr分量大约在133至173之间,Cb分量大约在77至127之间。大家可以根据自己项目需求放大或缩小这两个分量的范围,会有不同的效果。

 

5.HSV颜色空间H范围筛选法

同样地,也是在不同的颜色空间下采取相应的颜色范围将皮肤分割出来。

 

6.opencv自带肤色检测类AdaptiveSkinDetector

opencv提供了下面这个好用的皮肤检测函数:

CvAdaptiveSkinDetector(int samplingDivider = 1, int morphingMethod = MORPHING_METHOD_NONE);

这个函数的第二个参数表示皮肤检测过程时所采用的图形学操作方式,其取值有3种可能:

如果为MORPHING_METHOD_ERODE,则表示只进行一次腐蚀操作;如果为MORPHING_METHOD_ERODE_ERODE,则表示连续进行2次腐蚀操作;如果为MORPHING_METHOD_ERODE_DILATE,则表示先进行一次腐蚀操作,后进行一次膨胀操作。

从效果图看来,背景多了很多白色的杂质,单从直观效果来看,貌似还不如上面写的几个算法。

 

完整算法代码如下:

#include "stdafx.h" #include #include #include #include #include #include using namespace cv; #if 1 class skin_detector { public: /*基于RGB范围的皮肤检测*/ Mat RGB_detect(Mat& img) { /* R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B OR R>220 AND G>210 AND B>170 AND ABS(R-G)B AND G>B */ Mat detect = img.clone(); detect.setTo(0); if (img.empty() || img.channels() != 3) { return detect; } for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { uchar *p_detect = detect.ptr(i, j); uchar *p_img = img.ptr(i, j); if ((p_img[2] > 95 && p_img[1]>40 && p_img[0] > 20 && (MAX(p_img[0], MAX(p_img[1], p_img[2])) - MIN(p_img[0], MIN(p_img[1], p_img[2])) > 15) && abs(p_img[2] - p_img[1]) > 15 && p_img[2] > p_img[1] && p_img[1] > p_img[0]) || (p_img[2] > 200 && p_img[1] > 210 && p_img[0] > 170 && abs(p_img[2] - p_img[1]) p_img[0] && p_img[1] > p_img[0])) { p_detect[0] = p_img[0]; p_detect[1] = p_img[1]; p_detect[2] = p_img[2]; } } } return detect; } /*HSV颜色空间H范围筛选法*/ Mat HSV_detector(Mat& src) { Mat hsv_image; int h = 0; int s = 1; int v = 2; cvtColor(src, hsv_image, CV_BGR2HSV); //首先转换成到YCrCb空间 Mat output_mask = Mat::zeros(src.size(), CV_8UC1); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { uchar *p_mask = output_mask.ptr(i, j); uchar *p_src = hsv_image.ptr(i, j); if (p_src[h] >= 0 && p_src[h] =48 && p_src[v] >=50) { p_mask[0] = 255; } } } Mat detect; src.copyTo(detect, output_mask);; return detect; } /*YCrCb颜色空间Cr,Cb范围筛选法*/ Mat YCrCb_detect(Mat & src) { Mat ycrcb_image; int Cr = 1; int Cb = 2; cvtColor(src, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间 Mat output_mask = Mat::zeros(src.size(), CV_8UC1); for (int i = 0; i < src.rows; i++) { for (int j = 0; j < src.cols; j++) { uchar *p_mask = output_mask.ptr(i, j); uchar *p_src = ycrcb_image.ptr(i, j); if (p_src[Cr] >= 133 && p_src[Cr] = 77 && p_src[Cb] 0) //如果该落在皮肤模型椭圆区域内,该点就是皮肤像素点 output_mask.at(j, i) = 255; } Mat detect; img.copyTo(detect,output_mask); //返回肤色图 return detect; } /*opencv自带肤色检测类AdaptiveSkinDetector*/ Mat AdaptiveSkinDetector_detect(Mat& src) { IplImage *frame; frame = &IplImage(src); //Mat -> IplImage CvAdaptiveSkinDetector filter(1, CvAdaptiveSkinDetector::MORPHING_METHOD_ERODE_DILATE); IplImage *maskImg = cvCreateImage(cvSize(src.cols, src.rows), IPL_DEPTH_8U, 1); IplImage *skinImg = cvCreateImage(cvSize(src.cols, src.rows), IPL_DEPTH_8U, 3); cvZero(skinImg); filter.process(frame, maskImg); // process the frame cvCopy(frame, skinImg, maskImg); Mat tmp(skinImg); //IplImage -> Mat Mat detect = tmp.clone(); cvReleaseImage(&skinImg); cvReleaseImage(&maskImg); return detect; } }; #endif

 

测试代码:

int main(int argc, char** argv) { VideoCapture cap(0); if (!cap.isOpened()) { printf("fail to open camera!\n"); return -1; } Mat frame; skin_detector detector; while (1) { cap >> frame; if (frame.empty()) { continue; } Mat skin = detector.AdaptiveSkinDetector_detect(frame);//AdaptiveSkinDetector_detect imshow("AdaptiveSkinDetector capture skin", skin); imshow("capture src",frame); if (waitKey(1) == 27) { break; } } return 0; }

 

 文章参考:

1.https://www.cnblogs.com/Imageshop/p/3264238.html

2.https://www.cnblogs.com/skyfsm/p/7868877.html



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3