- 肤色高斯概率模型,主要将颜色空间从RGB转换为YCrCb,计算肤色的相似度,确定根据概率阈值筛选出肤色区域。但高斯概率模型中肤色均值及协方差矩阵需要提前确定,并且肤色均值对检测结果影响非常大,需要根据实际情况进行调整。
#include <iostream>
#include "opencv2/opencv.hpp"
#include <ctime>
using namespace std;
using namespace cv;
void fillHole(Mat * src);//基于漫水填充的孔洞填充
#define PI 3.14156
void main ()
{
Mat src = imread("1.jpg");
if (src.empty())
{
cout << "read image error!" << endl;
return ;
}
//基于高斯肤色概率模型的人脸检测结果
const char * src_namedWindow = "src";
imshow (src_namedWindow , src);
Mat tempImg ;
cvtColor (src, tempImg,CV_RGB2YCrCb );//将颜色空间从RGB转换为YCrCb
vector <Mat> channels;
split (tempImg,channels);//分离出CrCb通道
Mat Cr_Img, Cb_Img;
Cr_Img = channels[1];
Cb_Img = channels[2];
//利用二维高斯概率模型计算每个像素点的肤色相似度
Mat pro(Cr_Img.size(), CV_32FC1 );//定义相似度矩阵
for (int i = 0; i<src.rows ; i++)
for (int j = 0; j < src.cols ; j++)
{
Mat chr = (Mat_<double>(1, 2) << Cr_Img.at<uchar>(i, j), Cb_Img.at<uchar>(i, j) );//定义色度矩阵
Mat m = (Mat_<double>(1, 2) << 120.4316, 148.5599);//肤色均值,即定义高斯分布的期望值。
Mat cov = (Mat_<double>(2, 2)<< 97.0946, 24.4700, 24.4700, 141.9966);//协方差矩阵
Mat ss=(-0.5)*(chr-m)*cov.inv()*(chr-m).t();
pro.at<float>(i,j)=exp(ss.at<double>(0))/(2*PI *sqrt(determinant (cov)));//计算相似度
//cout << exp(ss.at<double>(0))/(2*PI*sqrt(determinant (cov)))<< endl;
}
//imshow ("相似度矩阵", pro );
//相似度矩阵归一化
//double min1=0, max1=0;
//minMaxIdx (pro, &min1, &max1);
//cout << max1 << endl;
//Mat nor = pro/max1;
Mat nor;
normalize (pro, nor,0,1,NORM_MINMAX );
//imshow("归一化矩阵", nor);
Mat mask1 = Mat :: zeros (pro.size(), CV_32FC1 );//肤色区模板
Mat mask2 (mask1.size(), CV_8UC1 );
double thresh_face = 0.5;//肤色阈值
for (int i = 0; i < nor.rows; i++ )
for ( int j = 0; j < nor.cols ; j++)
{
if (nor.at<float>(i,j) > thresh_face )
mask1.at<float>(i,j) = 1;
else
mask1.at<float>(i,j) = 0;
}
imshow("人脸模板", mask1);
Mat element1 = getStructuringElement (MORPH_RECT,Size(3,3));
erode(mask1, mask1,element1, Point(-1,-1), 2);
Mat element2 = getStructuringElement (MORPH_ELLIPSE, Size(5,5));
dilate (mask1, mask1,element2);
threshold(mask1, mask2, 0,255,CV_THRESH_BINARY );//将mask1转为二值图
mask2.convertTo (mask2, CV_8UC1 );//将矩阵转为图片
//二值化图孔洞填充
fillHole(&mask2);
imshow ("填充后", mask2);
//轮廓查找
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours (mask2, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
//筛选轮廓
vector<int> label;
int add_lable = 0;
vector<Rect> boundRect(contours.size());//定义外接矩形集合
for (int i =0; i < contours.size(); i++)
{
double con_area = contourArea (contours[i]);
double con_length = arcLength (contours[i], true);
int x0 =0, y0 =0, w0 =0, h0 =0;
boundRect[i] = boundingRect (contours[i]);
x0 = boundRect[i].x;
y0 = boundRect[i].y;
w0 = boundRect[i].width;
h0 = boundRect[i].height;
if (con_area > 400 && w0 > 20 && h0 > 20 && (h0/w0)>0.6 && (h0/w0)<2 )
{
drawContours (mask2, contours,i, Scalar (255, 0, 0), 1, 8);
rectangle (src, Point(x0, y0), Point(x0+w0, y0+h0), Scalar (0, 255, 0), 2, 8);
putText (src, "Face", Point(x0+w0/4, y0), CV_FONT_HERSHEY_SIMPLEX,0.5,Scalar(0,255,0), 2 );
label.push_back (i);
}
}
imshow("mask2", mask2);
imshow("人脸区",src);
waitKey(0);
//system ("pause");
}
void fillHole2(Mat *src)//利用漫水填充进行孔洞填充
{
Mat temp = Mat::zeros((src->size().height ) + 2, (src->size().width)+2, src->type());
src->copyTo (temp(Range (1,(src->size().height ) + 1),Range (1,(src->size().width)+1)));
floodFill (temp, Point(0,0),Scalar (255));
//imshow("floodFill", temp);
Mat cutImg;//将图像还原为原来大小
temp(Range (1,(src->size().height ) + 1),Range (1,(src->size().width)+1)).copyTo (cutImg );
*src = (*src) | (~ cutImg );
}
参考文献
孔洞填充
https://bbs.youkuaiyun.com/topics/391542633?page=1
https://blog.youkuaiyun.com/qq_20823641/article/details/52186629
https://blog.youkuaiyun.com/wxplol/article/details/73137397
图像计算
https://blog.youkuaiyun.com/fengbingchun/article/details/72357082
https://blog.youkuaiyun.com/qq_29796317/article/details/73136083
人脸检测—基于肤色高斯概率的检测实现
https://wenku.baidu.com/view/0478da5d4431b90d6c85c7aa.html
https://blog.youkuaiyun.com/mao19931004/article/details/48933435
https://blog.youkuaiyun.com/tiemaxiaosu/article/details/51741486
http://blog.sina.com.cn/s/blog_4a540be60102uwcr.html
https://blog.youkuaiyun.com/zdx19880830/article/details/45892739
https://blog.youkuaiyun.com/wj080211140/article/details/23384927