概述

本篇记录了利用基于HSV颜色模型的肤色提取与连通区域过滤实现图片的人脸定位,附带知识的介绍略烦多,附带Matlab相关程序代码。


开幕雷击:本文只是鄙人几年前接触数学建模初期时关于人脸识别题目的一些碎片记录,最终整合起来的效果并不好,不具备实际可用性,因此不要对本文模型效果抱有太大期待。此外几点补充说明见文末。

一、预备知识

图像预处理

  • 1.1 灰度化  在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。一般有分量法 最大值法平均值法加权平均法四种方法对彩色图像进行灰度化。
I = imread('img.jpg');
I2 = rgb2gray(I);
subpolt(1,2,1),imshow(I),title('原图');
subpolt(1,2,2),imshow(I2),title('灰度化');

图像的灰度化

  • 1.2 锐化滤波  应用锐化可以快速聚焦模糊边缘,提高图像中某一部位的清晰度或者焦距程度,使图像特定区域的色彩更加 鲜明。 $Matlab:$
I = imread('img.jpg');
I2 = double(rgb2gray(I));
H = [0 1 0,1 -41,0 1 0];
J = conv2(I2,H,'same');
K = I2-J;
subplot(1,2,1),imshow(rgb2gray(I)),title('原图灰度化');
subplot(1,2,2),imshow(K,[]),title('锐化滤波');

锐化滤波

  • 1.3 中值滤波  中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。  中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。 $Matlab:$
I = imread('img.jpg');
I2 = medfilt2(rgb2gray(I),[9 9]); 	%9×9中值滤波
subplot(1,2,1),imshow(rgb2gray(I)),title('原图灰度化');
subplot(1,2,2),imshow(I2,[]),title('9×9中值滤波');

中值滤波

  • 1.4 二值化  图像的二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。 $Matlab:$
I = imread('img.jpg');
I2 = rgb2gray(I);	%灰度化
thresh = graythresh(I2);     %从原图确定二值化阈值;
I3 = im2bw(I2,thresh);	%二值化
subplot(1,2,1),imshow(I2),title('原图灰度化');
subplot(1,2,2),imshow(I3),title('二值化');

二值化

几种颜色模型

  • 2.1 RGB模型  最典型、最常用的面向硬件设备的彩色模型是三基色模型,即RGB模型。电视、摄像机和彩色扫描仪都是根据RGB模型工作的。RGB颜色模型建立在笛卡尔坐标系统里,其中三个坐标轴分别代表R、G、B,如图1所示,RGB模型是一个立方体,原点对应黑色,离原点最远的顶点对应白色。RGB是加色,是基于光的叠加的,红光加绿光加蓝光等于白光。应用于显示器这样的设备。 RGB模型  RGB颜色空间的主要缺点是不直观,从R、G、B的值中很难知道该值所代表颜色的认知属性,因此RGB颜色空间不符合人对颜色的感知心理。另外,RGB颜色空间是最不均匀的颜色空间之一,两种颜色之间的知觉差异不能采用该颜色空间中两个颜色点之间的距离来表示。

  • 2.2 YCrCb模型 YCbCr模型中,Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。YCbCr模型常用与肤色检测中。 RGB转换YCbCr公式: $$Y=0.299R+0.587G+0.114B$$ $$Cb=0.564(B-Y)$$ $$Cr=0.713(R-Y)$$ YCbCr转换RGB公式: $$R=Y+1.402Cr$$ $$G=Y-0.344Cb-0.714Cr$$ $$B=Y+1.772Cb$$

  • 2.3 HSV模型

 HSV模型比HSI模型更与人类对颜色的感知接近。H代表色调,S代表饱和度,V代表亮度值。HSV模型的坐标系统可以是圆柱坐标系统,但一般用六棱锥来表示,如图3所示,与HSI模型比较相似。可以通过比较HSI、HSV与RGB空间的转换公式,来比较HSI与HSV的区别。

 HSV模型

 RGB空间转换HSV空间: $$ \begin{equation} F=\left{ \begin{array}{rcl} \arccos{\frac{(R-G)+(R-B)}{2\sqrt{(R-G)^2+(R-B)(G-B)}}} & & {B \leq G}\\ 2\pi-\arccos{\frac{(R-G)+(R-B)}{2\sqrt{(R-G)^2+(R-B)(G-B)}}} & & {B > G}\\ \end{array} \right. \end{equation} $$

$$ \begin{equation} S=\frac{\max(R,G,B)-\min(R,G,B)}{\max(R,G,B)} \end{equation} $$

$$ \begin{equation} V=\frac{\max(R,G,B)}{255} \end{equation} $$

连通区域

在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接。4邻接一共4个点,即上下左右,如下左图所示。8邻接的点一共有8个,包括了对角线位置的点,如下右图所示。

连通区域

如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论:   如果A与B连通,B与C连通,则A与C连通。

在视觉上看来,彼此连通的点形成了一个区域,而不连通的点形成了不同的区域。这样的一个所有的点彼此连通点构成的集合,我们称为一个连通区域。   下面这符图中,如果考虑4邻接,则有3个连通区域;如果考虑8邻接,则有2个连通区域。(注:图像是被放大的效果,图像正方形实际只有4个像素)。 连通区域


二、图像人脸粗提取

1) HSV空间的肤色分割

彩色图像在RGB空间中描述,三基色不仅代表颜色,还代表了亮度,由于周围环境光照的改变。进行处理时,先把图像在RGB空间转换成HSV空间,在HSV空间进行阈值分割。 设: $$I=I{R,G,B}$$ 是一幅彩色人脸图像点阵,经过HSV肤色分割得到分割图 $$I_2=I{H,S,V}$$

HSV肤色分割

$Matlab: skin.m$

% 根据当前点的Cb Cr值判断是否为肤色  
function result = skin(Y,Cb,Cr)  
% 参数  
a = 25.39;  
b = 14.03;  
ecx = 1.60;  
ecy = 2.41;  
sita = 2.53;  
cx = 109.38;  
cy = 152.02;  
xishu = [cos(sita) sin(sita);-sin(sita) cos(sita)];  
% 如果亮度大于230,则将长短轴同时扩大为原来的1.1倍  
if(Y > 230)  
    a = 1.1*a;  
    b = 1.1*b;  
end  
% 根据公式进行计算  
Cb = double(Cb);  
Cr = double(Cr);  
t = [(Cb-cx);(Cr-cy)];  
temp = xishu*t;  
value = (temp(1) - ecx)^2/a^2 + (temp(2) - ecy)^2/b^2;  
% 大于1则不是肤色,返回0;否则为肤色,返回1  
if value > 1  
    result = 0;  
else  
    result = 1;  
end  

2) 边缘强化

在彩色测试图的R、G、B通道中,人脸肤色的像素多数集中在B通道,而且B通道含的背景像素最少,所以单选择在B通道进行边缘强化处理. 彩色人脸图像点阵$I$的$B$通道:

$$I_1=I{0,0,B}$$

用一种高频增强算子 $$ H=\left[ \begin{array}{ccc} 0&-1&0\\ -1&2&-1\\ 0&-1&0 \end{array} \right] $$

与$B$通道分量$I_1$进行卷积锐化出边界图$I_3$

边缘强化

用锐化后的边界图$I_3$和HSV肤色分割图$I_2$逻辑上相与得到边缘强化图$I_4$。

$$ I_4=I_3∧I_2 $$

4)中值滤波

中值滤波能够快速滤除一些细小的、零散的区域,对边缘强化图$I_4$进行中值滤波处理能够清除图中细碎的背景得到$I_5$。 中值滤波

三、连通区初步过滤条件

连通区的相关介绍和连通区的提起在上文已经有所介绍,下图是提取连通区的效果:

连通区

脸区域形状上大体与椭圆相似,而中值滤波后的边缘强化图中除了人脸的椭圆区域外,还有一些其它形状的区域,这些其它的形状基本上是非人脸区域。这些区域基本可以分为三角区域、矩形区域、细长的和弯曲的区域和面积相对较小的区域等4种。

针对这4种区域,分别采用面积密度、长宽比、致密度和面积滤波等4种几何形状特征的方法进行背景清除。

1) 面积密度

区域的面积与其最小外接矩形的面积的比值:

$$ \begin{equation} M=\frac{area(i)}{A_{MER}^{(i)}} \end{equation} $$

当区域为矩形时,比值(M)最大为1;当区域为圆形区域时,比值为$\frac{\pi}{4}$;当区域为细长的、弯曲的物体时,比例变小。 当选取比值(M)= 0.4时,即可除去细长弯曲的区域和细长倾斜的区域。其中

$$ \begin{equation} area(i)=\sum_{x=1}^{row}\sum_{y=1}^{col}l(x,y) \end{equation} $$

$$ \begin{equation} A_{MER}=(low_i-top_i)(right_i-left_i) \end{equation} $$

对于二值图而言,1表示物体,0表示背景,面积就是统计每一个连通区域$L(x,y)= 1$的个数。

2) 长宽比

利用区域最小外接矩形长和宽的比例清除一些不符合正常的人脸比例的区域。

$$ \begin{equation} N=\frac{low_i-top_i}{right_i-left_i} \end{equation} $$

3) 致密度

利用致密度可以除去一些近似矩形和三角形的区域,保留与人脸椭圆有相似性的区域。

$$ \begin{equation} N=\frac{c_i^2}{area_i} \end{equation} $$

通过实验资料,r设定阈值小于4或大于16就可以滤除一些矩形和三角区域。

4) 面积滤波

采用相对重要性滤波的方法来滤除较小的面积区域。用肤色最大的面积与整幅图的面积相比,然后设定一个阈值(R),当面积比小于某个值,就把某些面积较小的区域滤除。

$$ \begin{equation} S=row \times col \end{equation} $$

$$ \begin{equation} R=\frac{Max(area)}{S} \end{equation} $$

根据测试资料,将阈值R设为0.1,当R≥10%时,把面积小于95的区域滤除;当R≤10%时,把面积小于70的区域滤除。

连通区提取效果:

连通区提取

应用粗过滤条件后的人脸区域定位效果如图:

粗过滤

$Matab: facedetection.m$

function facedetection(img_name)  
% 读取RGB图像  
I = imread(img_name);  
% 转换为灰度图像  
gray = rgb2gray(I);  
% 将图像转化为YCbCr颜色空间  
YCbCr = rgb2ycbcr(I);  
% 获得图像宽度和高度  
heigth = size(gray,1);  
width = size(gray,2);  
% 根据肤色模型将图像二值化  
for i = 1:heigth  
    for j = 1:width  
        Y = YCbCr(i,j,1);  
        Cb = YCbCr(i,j,2);  
        Cr = YCbCr(i,j,3);  
        if(Y < 80)  
            gray(i,j) = 0;  
        else  
            if(skin(Y,Cb,Cr) == 1)  
                gray(i,j) = 255;  
            else  
                gray(i,j) = 0;  
            end  
        end  
    end  
end  
% 二值图像形态学处理  
SE=strel('arbitrary',eye(5));    
%gray = bwmorph(gray,'erode');  
% imopen先腐蚀再膨胀  
gray = imopen(gray,SE);  
% imclose先膨胀再腐蚀  
%gray = imclose(gray,SE);  
imshow(gray);  
% 取出图片中所有包含白色区域的最小矩形  
[L,num] = bwlabel(gray,8);  
STATS = regionprops(L,'BoundingBox');  
% 存放经过筛选以后得到的所有矩形块  
n = 1;  
result = zeros(n,4);  
figure,imshow(I);  
hold on;  
for i = 1:num  
    box = STATS(i).BoundingBox;  
    x = box(1);    %矩形坐标x  
    y = box(2);    %矩形坐标y  
    w = box(3);    %矩形宽度w  
    h = box(4);    %矩形高度h  
    % 宽度和高度的比例  
    ratio = h/w;  
    ux = uint8(x);  
    uy = uint8(y);  
    if ux > 1  
        ux = ux - 1;  
    end  
    if uy > 1  
        uy = uy - 1;  
    end  
    % 可能是人脸区域的矩形应满足以下条件:  
    %   1、高度和宽度必须都大于20,且矩形面积大于400  
    %   2、高度和宽度比率应该在范围(0.6,2)内  
    %   3、函数findeye返回值为1  
    if w < 20 || h < 20 || w*h < 400  
        continue  
    elseif ratio < 2 && ratio > 0.6 && findeye(gray,ux,uy,w,h) == 1  
        % 记录可能为人脸的矩形区域  
        result(n,:) = [ux uy w h];  
        n = n+1;  
    end  
end  
% 对可能是人脸的区域进行标记  
if  size(result,1) == 1 && result(1,1) > 0  
    rectangle('Position',[result(1,1),result(1,2),result(1,3),result(1,4)],'EdgeColor','r');  
else  
    % 如果满足条件的矩形区域大于1则再根据其他信息进行筛选  
    for m = 1:size(result,1)  
        m1 = result(m,1);  
        m2 = result(m,2);  
        m3 = result(m,3);  
        m4 = result(m,4);  
        % 标记最终的人脸区域  
        if m1 + m3 < width && m2 + m4 < heigth  
            rectangle('Position',[m1,m2,m3,m4],'EdgeColor','r');  
        end  
    end  
end  

四、连通区深度过滤

对于上图可以看出,经过上述的背景消除算法滤除背景时,发现中间人物的手部区域与脸部特征近似,使用简单的粗过滤方法可能难以过滤完全。容易出现将手部误认定为脸部的可能,为了消除手部的干扰,在此定位结果的基础上采用几何匹配算法,将找不到眼睛的区域进行过滤,这样便可消除手部的影响,从而精确的将人脸定位。

  • 基于几何匹配算法的眼部搜索
  1. 将一对连通区从图像区域中提取出来(设为X和Y)
  2. 规定X在Y的左边;X与Y连线倾角在$[-\frac{\pi}{4},\frac{\pi}{4}]$之间
  3. 设评价函数为$E$,计算它们作为一对眼睛的评价函数$E$,如果$E$超过一定的阈值, 那么认为这一对连通区所框选的对象很可能是一对眼睛。 定义评价函数: \begin{equation} E=exp{-4.8[0.4(S_1-S_2)^2+0.2(S_1+S_2-1)^2+0.2(\theta_1-\theta)^2+0.2(\theta_2-\theta)^2]} \end{equation} 类似的,可以探索嘴部的评价函数,最终有三个连通区提取到了眼嘴特征,定位如下:

嘴眼

不难得到经过深度过滤后的人脸定位结果:

结果

$Matlab: findeye.m$

% 判断二值图像中是否含有可能是眼睛的块  
%   bImage----二值图像  
%   x---------矩形左上角顶点X坐标  
%   y---------矩形左上角顶点Y坐标  
%   w---------矩形宽度  
%   h---------矩形长度  
% 如果有则返回值eye等于1,否则为0  
function eye = findeye(bImage,x,y,w,h)  
% 根据矩形相关属性得到二值图像中矩形区域中的数据  
% 存放矩形区域二值图像信息  
part = zeros(h,w);  
% 二值化  
for i = y:(y+h)  
    for j = x:(x+w)  
        if bImage(i,j) == 0  
            part(i-y+1,j-x+1) = 255;  
        else  
            part(i-y+1,j-x+1) = 0;  
        end  
    end  
end  
[L,num] = bwlabel(part,8);  
% 如果区域中有两个以上的矩形则认为有眼睛  
if num < 2  
    eye = 0;  
else  
    eye = 1;  
end  

五、参考文章

[1] 形态学-腐蚀、膨胀、开操作、闭操作 [2] 图像处理中常用的彩色模型 [3] OpenCV:二值图像连通区域分析与标记算法实现

六、深入阅读

[1] 张朝阳,潘保昌,郑胜林,彭绍湖. 基于消除背景的人脸定位方法. 广东工业大学学报.24(2):91-106,2007 [2] 倪健,董强,管国栋. 基于几何特征的人脸定位算法的改进.《微计算机信息》(测 控 自 动 化).22(5-1):241-242,2006

七、2021.05.26 补充说明

对于评论区中反馈的问题此处统一作补充说明,本文只是鄙人几年前接触数学建模初期时关于人脸识别题目快餐化学习后的一些碎片记录,最终整合起来的效果并不好,因此不要对本文模型效果抱有太大期待

  1. 本文HSV在肤色分割中起到辅助分割的作用,肤色分割由Cb、Cr和Hue共同完成,若去除hue条件则例图会出现错误识别(见下图)。该模型关于肤色和背景环境色的鲁棒性均较差,本例中的人物图片肤色正、环境色干扰小,故均能正确框选人脸,但换用其它图片不能保证可用性。
  2. 本文眼睛识别是基于连通区配对的,与HSV、YCbCr均无关,识别效果不好,在本模型中仅起到辅助筛选,并不能够很可靠地定位眼睛,有眼睛的部分不一定能正确地标注,一些没有眼睛的区域也可能被错误的标记为有眼睛,因此只能辅助性地筛掉一些无人脸区域,筛除成功率并不高。
  3. 本文文中代码不全,我将把完整代码和示例图片打包上传百度网盘,有需要的朋友请在文末自取。模型入口函数为main_findFace('imgName', 0.5),参数一为图片相对路径,参数二为图片缩放比例。附件图片较大,为了更好的识别效果和速度请合理设置缩放运行。
  4. 本文不再更新,不再回复评论。

Matlab代码及测试图片打包:

链接: https://pan.baidu.com/s/1m8_cPKAyBaMGtCzjA7cFUQ

提取码: 2naa