一、概要
基于肤色的人脸分割主要分为三大部分:(1)预处理,针对噪声,光照带来的影响进行消除。(2)基于肤色模型的肤色分割。(3)连通域分析,人脸区域定位。
预处理主要使用高斯滤波和直方图均衡,这些原理比较基础,网上可以很容易找到,不是重点。
通过比较RGB,HSV,Ycbcr空间,发现Ycbcr和HSV空间在进行人脸肤色分割方面由于肤色范围紧密,不易受光照其他物体干扰(基于肤色模型的,如果背景中有与人脸颜色类似的物体,且距离较近很容易产生干扰,影响人脸区域定位的准确性,这也是这一算法不能解决的问题)。但是RGB与HSV空间的转换相比RGB到Ycbcr空间转换来说较为复杂些,所以我们采用Ycbcr空间进行人脸肤色的建模与分割。
二、肤色模型
(1)Ycbcr空间
图(1)Cb空间肤色分布
图(2)Cr空间肤色分布
由上面的结果,我们可以根据肤色的均值和方差建立肤色的高斯模型。
其中Cb,Cr的均值和协方差如下:
Mean = [117.4316 148.5599]';%肤色均值
C = [97.0946 24.4700;
24.4700 141.9966];%肤色方差
得到人脸概率图之后,使用二值化得到人脸肤色二值图像,如下:
(3)人脸区域定位,使用连通区域分析,获取二值图像最小外接矩形,即为人脸区域。具体算法如下:
对输入图像进行连通域分析的主要目的是获取人脸在图像中的准确位置。连通域分析先要对连通区域进行标记,首先对二值图像中符合某种连通规则(四邻域,八邻域)的像素用相同的标号表示出来。连通域标记的方法有,像素标记法,线标记法,区域增长法等。这里我们介绍下八邻域像素标记法。
1) 判断此点八邻域中的最左,左上,最上,上右点的情况。
如果都没有点,则表示一个新的区域的开始。
2) 如果此点八邻域中的最左有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
3) 如果此点八邻域中的左上有点,上右都有点,则标记此点为这两个中的最小的标记点,并修改大标记为小标记。
4) 否则按照最左,左上,最上,上右的顺序,标记此点为四个中的一个。
这样我们就得到了二值图像的连通区域轮廓,求取连通区域的最小外接矩形,因为人脸在图像中尺寸较大,且内部连续,类似椭圆,我们可以根据外接矩形的长宽比,人脸矩形区域二值图像占空比滤除一些孤立小目标或者形状与人脸差异较大的目标。得到较为准确的人脸区域定位结果。
算法代码如下:
function BinImg = GetFaceBin(rgb)
Ycbcr = rgb2ycbcr(rgb);
%人脸分割阈值
fThreshold = 0.22;
%获取图像宽度,高度和维度。
[M,N,D]=size(Ycbcr);
FaceProbImg = zeros(M,N,1);%肤色后验概率矩阵
BinImg = uint8(zeros(M,N,1));%二值图像
Mean = [117.4316 148.5599]';%肤色均值
C = [97.0946 24.4700;
24.4700 141.9966];%肤色方差
cbcr = zeros(2,1);%颜色分量,Y分量差异较大,只用CbCr分量。
for i=1:M
for
j=1:N
cbcr(1) = Ycbcr(i,j,2);
cbcr(2) = Ycbcr(i,j,3);
FaceProbImg(i,j)=exp(-0.5*(cbcr-Mean)'*inv(C)*(cbcr-Mean));%计算肤色高斯后验概率 if
FaceProbImg(i,j)>fThreshold%如果大于阈值认为是人脸区域 BinImg(i,j) = 1;%生成二值图像
end end
end
se=strel('disk',3');
BinImg = imopen(BinImg,se); %使用3*3圆盘,进行图像开操作(先腐蚀后膨胀,滤除孤立点)
imdilate(BinImg,se);
% subplot(122);imshow(BinImg*255);title('腐蚀膨胀');
CC = bwconncomp(BinImg);%获取联通区域
numPixels = cellfun(@numel,CC.PixelIdxList);%计算联通区域面积。
[biggest,idx] = max(numPixels);%获取最大的联通区域坐标
for i=1:CC.NumObjects%只留最大的联通区域,去除其他的联通区域
if i~=idx
BinImg(CC.PixelIdxList{i}) = 0;
end
end
%
figure(2);imshow(uint8(BinImg*255));%显示二值化图像
end