学习OpenCV——肤色检测:椭圆模型 (&最大连通区域)
来源:互联网 发布:淘宝网店上显示所在地 编辑:程序博客网 时间:2024/03/29 07:21
简介:
刚开始尝试利用肤色信息进行CV方面的跟踪或者检测,但总是发现肤色信息的除了实时效果比较好,其他的抗噪,鲁棒性都不尽如人意。但是正如tornadomeet所说:其实计算机视觉的最终实现是一个长期的过程,是AI领域一个经典的问题,所以在AI完全突破之前,任何对CV有用的信息都值得去深入研究,除非有一种算法能够在所有情况下都工作。
皮肤检测----肤色椭圆模型
皮肤模型中有单高斯,混合高斯,贝叶斯模型和椭圆模型等。经过前人学者大量的皮肤统计信息可以知道,如果将皮肤信息映射到YCrCb空间,则在CrCb二维空间中这些皮肤像素点近似成一个椭圆分布。因此如果我们得到了一个CrCb的椭圆,下次来一个坐标(Cr, Cb)我们只需判断它是否在椭圆内(包括边界),如果是,则可以判断其为皮肤,否则就是非皮肤像素点。
肤色区域的颜色与亮度成非线性函数关系,在低亮度条件下,YCbCr 空间中色度的聚类性会随Y 呈非线性变换降低。为了使肤色聚类不受亮度Y 的影响并将YCbCr 颜色空间中的色度Cb、Cr进行非线性变换,在研究YCbCr 颜色空间的肤色聚类情况的基础上,去掉高光阴影部分(即 Y 的最大最小值),YCbCr 空间色度非线性变换过程中,用 Cb·· Y 、 Cr·· Y 表示肤色区域的中轴线,肤色区域的宽度分别用 Vcb、Vcr 表示。
即将图像转化到YCbCr 空间并且在CbCr平面进行投影,因此我们采集了肤色的样本点,将其投影到此平面,并且投影后,我们进行了相应的非线性变换K-L变换
进而形成的的统计椭圆模型
说它比较有趣是因为我们是用一副图像来存储上面的椭圆的,而不是直接采用椭圆数学方程。该图像是二值图像,即椭圆区域内部为白色,其它地方为黑色。所以当其需要判断其它像素点时,只需将该像素点转换成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);
void ellipse(Mat& img, Point center, Size axes, double angle, double startAngle, double endAngle, const Scalar&color, int thickness=1, int lineType=8, int shift=0)
该函数是用来在指定图片上绘制椭圆弧线的。
参数image为需要绘制椭圆的图像;
参数center是该椭圆的中心点坐标;
参数axes是该椭圆的长半轴和短半轴;
参数angle是该椭圆和水平方向上的旋转夹角;
参数startAngle表示绘制椭圆弧线相对该椭圆自己的水平轴的起始角度;
参数endAngel表示绘制椭圆弧线相对该椭圆自己的水平轴的终止角度;
后面的参数比较普通就不介绍了。
绘制椭圆曲线的示意图如下所示:
实现代码(包含过滤伪区域)
#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/contrib/contrib.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iostream>#include <vector>using namespace std;using namespace cv;Mat input_image;Mat output_mask;Mat output_image;Mat mask;void main(){VideoCapture cam(0);if(!cam.isOpened())return;/*椭圆皮肤模型*/Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1) );while(true) {cam >> input_image;if(input_image.empty())return ;Mat ycrcb_image;output_mask = Mat::zeros(input_image.size(), CV_8UC1);cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间for(int i = 0; i < input_image.rows; i++) //利用椭圆皮肤模型进行皮肤检测{uchar* p = (uchar*)output_mask.ptr<uchar>(i);Vec3b* ycrcb = (Vec3b*)ycrcb_image.ptr<Vec3b>(i);for(int j = 0; j < input_image.cols; j++){if(skinCrCbHist.at<uchar>(ycrcb[j][1], ycrcb[j][2]) > 0)p[j] = 255;}}morphologyEx(output_mask,output_mask,MORPH_CLOSE,element);vector< vector<Point> > contours; // 轮廓 vector< vector<Point> > filterContours; // 筛选后的轮廓vector< Vec4i > hierarchy; // 轮廓的结构信息 contours.clear(); hierarchy.clear(); filterContours.clear();findContours(output_mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // 去除伪轮廓 for (size_t i = 0; i < contours.size(); i++) { if (fabs(contourArea(Mat(contours[i]))) > 1000/*&&fabs(arcLength(Mat(contours[i]),true))<2000*/) //判断手进入区域的阈值 filterContours.push_back(contours[i]);}output_mask.setTo(0);drawContours(output_mask, filterContours, -1, Scalar(255,0,0), CV_FILLED); //8, hierarchy); input_image.copyTo(output_image, output_mask);imshow("input image", input_image);imshow("output image", output_image);output_image.setTo(0);if(27 == waitKey(30))return;}return;}
实验总结: 皮肤的椭圆模型确实可以用来做皮肤检测,一旦确定好了该椭圆就可以用来做皮肤检测了。
ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1);
参考文献:
http://www.cnblogs.com/tornadomeet/archive/2012/12/05/2802428.html
A super-simple skin detector in OpenCV
皮肤检测与克服光线影响的连通域寻找(这哥们儿写的方法有些麻烦,我代码里写的是用轮廓)
http://docs.opencv.org/modules/core/doc/drawing_functions.html?highlight=ellipse#cv.Ellipse
- 学习OpenCV——肤色检测:椭圆模型 (&最大连通区域)
- opencv椭圆肤色模型人脸检测
- 学习OpenCV——肤色检测
- 学习OpenCV——肤色检测
- 有关opencv的学习(8)—肤色检测
- 图像处理——椭圆肤色模型
- OpenCV——肤色检测
- 基于opencv的肤色检测,并将肤色区域用矩形框标出。
- 使用OpenCV查找二值图中最大连通区域
- 肤色检测opencv
- OpenCV肤色检测
- OpenCV中的肤色检测
- OpenCV编程->肤色检测
- OpenCV肤色检测
- 利用OpenCV检测肤色
- 基于OpenCV 肤色检测
- OpenCV中的肤色检测
- OpenCV中的肤色检测
- Gnuplot的使用技巧
- Shell-检查Oracle数据库是否正常
- 编写程序,用冒泡法对10个数排序(由小到大)
- hdu 2639 Bone Collector II
- unity3d模型制作规范v1.0 .
- 学习OpenCV——肤色检测:椭圆模型 (&最大连通区域)
- 编写一个程序,用来求两个整数或三个整数中的最大数
- Windows Phone SDK 8.0安装步骤
- 递归的简单应用
- java 基于Socket 传送文件实例
- printf()简介说明
- re正则表达式
- 定义一个整形数组,把0~9共十个整数赋给数组元素a【0】~a【9】,然后按a【9】,a【8】,a【7】,...,a【0】的顺序输出
- 屏幕旋转会重启onCreate方法