MATLAB 图像处理 简单人脸检测(详细,你上你也行)

MATLAB 图像处理 简单人脸检测(详细,你上你也行)1 人脸检测原理框图整体思路是寻找图片中最大的连通域 将其认定为人脸 第一个环节均值滤波 是为了减弱图像的相关细节部分 以免毛刺影响后期连通域的形成 二值化方便形态学处理 减少运算量 考虑到人脸有黑人和白人黄种人 黑人肤色较深 在二值化之后面部区域不容易形成较大的连通域 如果采取形态学边界提取的办法 就可以避免这个问题 形态学边界提取 只要结构元素够大 也可以形成较大的封闭连通域

1.人脸检测原理框图

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

整体思路是寻找图片中最大的连通域,将其认定为人脸。

第一个环节均值滤波,是为了减弱图像的相关细节部分,以免毛刺影响后期连通域的形成,二值化方便形态学处理,减少运算量。考虑到人脸有黑人和白人黄种人,黑人肤色较深,在二值化之后面部区域不容易形成较大的连通域,如果采取形态学边界提取的办法,就可以避免这个问题,形态学边界提取,只要结构元素够大,也可以形成较大的封闭连通域。

然后就是纵向闭合操作,这一步我选择采用竖向长条状的结构元素进行闭合运算,因为人的脸部和颈部以及头发和衣物等等都是纵向分布的,在进行形态学边界提取的时候,容易将这些靠近的成分割裂开来,这对连通域的判断极为不利,所以用竖向长条状的结构元素在在纵向进行闭合运算,将脸部上下部的区域重新连接起来。

紧接着我又用横向长条状结构元素进行横向腐蚀运算,这是因为,人的头部以下的身体部分存在有大量连通域的时候,容易对最大连通域的判决产生干扰,又因为下半部分,多半呈纵向分布,通过横向腐蚀可以将这些大块的连通域割裂开来,但是要注意的是,割裂程度不应太大,否则会使得上一步闭合操作丧失意义。

接着,由于背景杂物等因素,同样也会产生大量连通域,这会对最后结果的判决产生干扰,因此要予以剔除。

进行了层层筛选之后,在剩下的连通域里面挑一个最大的连通域,并且尺寸形状满足要求的用矩形框框起来作为人脸检测结果。

2 步骤

2.1 均值滤波

h = ones(9)/81; I = uint8(conv2(I,h)); figure,imshow(I),title('线性均值滤波')

采用9×9模板进行线性均值滤波,因为后面调用gpuArray()函数转换对输入数据有要求,所以在进行了二维卷积之后重新将数据格式转换成8位无符号整形数据。

2.2 二值化

BW = imbinarize(I); figure,imshow(BW),title('二值化')

直接调用imbinarize对图像进行二值化

2.3.形态学边界提取

B = ones(21);%结构元素 BW = -imerode(BW,B) + BW; figure,imshow(BW),title('形态学边界提取') BW = bwmorph(BW,'thicken'); figure,imshow(BW),title('加粗边界') BW = not(bwareaopen(not(BW), 300)); figure,imshow(BW),title('把空洞填了')

结构元素采用21×21大小的全1矩阵,先调用imrode()进行腐蚀,再用原图减去腐蚀结果,得到边界。为了让边界更加明显,调用bmworph函数,传入’thicken’参数,意在将边界加粗加厚。最后为了把空洞就是连续的小黑色块填满,调用bwareaopen()函数,该函数是去除面积小于300的白块,为了去除黑块,先调用not(BW)给原来的二值图像取反,去掉取反后面积小于300的白块,再次取反,达到去掉面积小于300的黑块的目的。

2.4 纵向闭合与横向腐蚀

%进行形态学运算 B = strel('line',50,90); BW = imdilate(BW,B); BW = imerode(BW,B); figure,imshow(BW),title('再闭操作之后') B = strel('line',10,0); BW = imerode(BW,B); figure,imshow(BW),title('闭操作之后再腐蚀') BW = gpuArray(BW);

调用strel()函数生成特定的结构元素,第一步调用strel(‘line’,50,90),意思是调用直线型结构元素,长度为50,角度90度,也就是竖直的长条形结构元素。接着利用B调用imdilate和imerode,先进行膨胀再进行腐蚀完成闭操作运算。下一步,继续生成横向长条形结构元素,进行腐蚀操作,注意这里的结构元素不宜面积太大,长度太长,否则会过度影响上一步的结果

最后为了循环过程中提升运算速度,将数据类型更改为gpuArray(),可以在GPU上进行计算,节省时间。

2.5 消除边界多余连通域

%最小化背景 %细分 div = 10; r = floor(n1/div);%分成10块 行 c = floor(n2/div);%分成10块 列 x1 = 1;x2 = r;%对应行初始化 s = r*c;%块面积 %判断人脸是否处于图片四周,如果不是就全部弄黑 %figure for i=1:div y1 = 1;y2 = c;%对应列初始化 for j=1:div loc = find(BW(x1:x2,y1:y2)==0);%统计这一块黑色像素的位置 num = length(loc); rate = num*100/s;%统计黑色像素占比 if (y2<=0.2*div*c||y2>=0.8*div*c)||(x1<=r||x2>=r*div) if rate <=100 BW(x1:x2,y1:y2) = 0; end %imshow(BW) else if rate <=25 BW(x1:x2,y1:y2) = 1; end %imshow(BW) end%下一列 y1 = y1 + c; y2 = y2 + c; end%下一行 x1 = x1 + r; x2 = x2 + r; end

对于周围多余的杂物产生的连通域,我选择先将整幅图像划分为很多小块,对一部分在图像边缘的小块全部置成黑色,对不在边缘的通过计算其中黑色像素比例来判定是否应该全部给成白色。因为图片中央可能还会存在一些细小空洞,这些空洞在每一小块占比不是很大但有可能影响连通性,如果一个小块里面大部分是白色就全部给成白色,方便后期判定最大连通域。

Div是均分比例,我这里设置成10,也就是将整个图像划分成100个小块。r就是在行方向上一个小块占多少像素,c就是在列方向上一个小块有多少像素。用两层循环来遍历每个小块,通过find(x1:x2,y1:y2)==0返回所有满足要求的像素的索引,索引长度就是黑色像素的个数。

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

通过条件判断是否在边界。

2.6 寻找最大连通域并画框

figure subplot(1,2,1) imshow(BW) title('最终处理') L = bwlabel(BW,8);%利用belabel函数对8连通域区间进行标号 BB = regionprops(L,'BoundingBox');%得到矩形框,框柱每一个连通域 BB = cell2mat(struct2cell(BB)); [s1,s2] = size(BB); BB = reshape(BB,4,s1*s2/4)'; pickshape = BB(:,3)./BB(:,4);% shapeind = BB(0.3 
  

经过消除边界多余连通域后得到的BW中剩下的连通域内存在着我们需要的那个对应人脸的连通域。一般情况下,对应人脸的那个连通域会是最大的连通域。

调用bwlabel(BW,8)函数给所有连通域标记,其中邻域规则采用8邻域,返回一个被标记过连通域的图像,第k个被标记的连通域所有像素值为k。

调用regionprops(L,’BoundingBox’)函数,传入参数L和’BoundingBox’,该函数用于获取图像的各种属性,传入’BoundingBox’返回的是一个结构体,每一个结构体内都包含了一个能框柱其对应连通域的最小方框。一个方框,用一个序列来描述[x,y,width,height],这个序列包含了方框左上角像素的坐标以及长和宽。

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

这三条语句,第一条用来将结构体转换成矩阵向量,方便计算。第二行获取这个矩阵的维度。由于BB刚转换成向量的时候,是一个行向量,每4个元素1组对应一个方框。为了后续计算方便,使用reshape()函数,将BB重构成一个矩阵,这个矩阵有4列,每一列对应方框的一个参数,比如坐标,长宽等等。每一行对应一个方框。

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

第一行计算长宽比,得到的pickshape向量的每一行对应每个方框的长宽比。由于有的方框明显过于扁平或者过于狭长,这种方框应该是要扔掉的。

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

把方框画出来。

3 检测结果

MATLAB 图像处理 简单人脸检测(详细,你上你也行)MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 15rgb图像转换成灰度图像                 图 16线性均值滤波结果

可以看到,均值滤波使得图像变模糊了细节减少

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 17二值化结果                                    图 18形态学边界提取结果

以看到边界被成功提取了出来,在人脸部形成了一个比较大的连通域

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

注意观察图片左边的相分离的白块,在纵向闭操作之后连在了一起,同时脸部连通域进一步扩大,然后横向腐蚀在尽量维持脸部连通域大小的情况下减小了图片下方连通域。

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

可以看到效果还可以。还有其他的测试结果

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 24测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 25测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 26测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 27测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 28测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 29测试样例

MATLAB 图像处理 简单人脸检测(详细,你上你也行)

图 30测试样例

这里注意到,黑人同样也被检测到了

---%%%完整代码 rgb = imread('f.jpg'); I = rgb2gray(rgb); [n1,n2] = size(I); %灰度图 figure,imshow(I),title('灰度图') tic h = ones(9)/81; I = uint8(conv2(I,h)); figure,imshow(I),title('线性均值滤波') BW = imbinarize(I); figure,imshow(BW),title('二值化') B = ones(21);%结构元素 BW = -imerode(BW,B) + BW; figure,imshow(BW),title('形态学边界提取') BW = bwmorph(BW,'thicken'); figure,imshow(BW),title('加粗边界') BW = not(bwareaopen(not(BW), 300)); figure,imshow(BW),title('把空洞填了') %进行形态学运算 B = strel('line',50,90); BW = imdilate(BW,B); BW = imerode(BW,B); figure,imshow(BW),title('再闭操作之后') B = strel('line',10,0); BW = imerode(BW,B); figure,imshow(BW),title('闭操作之后再腐蚀') %%BW = gpuArray(BW);%%将数据载入gpu可以加速,电脑不一定支持 %最小化背景 %细分 div = 10; r = floor(n1/div);%分成10块 行 c = floor(n2/div);%分成10块 列 x1 = 1;x2 = r;%对应行初始化 s = r*c;%块面积 %判断人脸是否处于图片四周,如果不是就全部弄黑 %figure for i=1:div y1 = 1;y2 = c;%对应列初始化 for j=1:div loc = find(BW(x1:x2,y1:y2)==0);%统计这一块黑色像素的位置 num = length(loc); rate = num*100/s;%统计黑色像素占比 if (y2<=0.2*div*c||y2>=0.8*div*c)||(x1<=r||x2>=r*div) if rate <=100 BW(x1:x2,y1:y2) = 0; end %imshow(BW) else if rate <=25 BW(x1:x2,y1:y2) = 1; end %imshow(BW) end%下一列 y1 = y1 + c; y2 = y2 + c; end%下一行 x1 = x1 + r; x2 = x2 + r; end figure subplot(1,2,1) imshow(BW) title('最终处理') L = bwlabel(BW,8);%利用belabel函数对8连通域区间进行标号 BB = regionprops(L,'BoundingBox');%得到矩形框,框柱每一个连通域 BB = cell2mat(struct2cell(BB)); [s1,s2] = size(BB); BB = reshape(BB,4,s1*s2/4)'; pickshape = BB(:,3)./BB(:,4);% shapeind = BB(0.3 
  

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209645.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午8:45
下一篇 2026年3月19日 上午8:45


相关推荐

  • 深入理解Java虚拟机–javac命令[通俗易懂]

    深入理解Java虚拟机–javac命令[通俗易懂]目录指定编译源文件命令选项非标准选项-Xjavac命令用于将.java源文件编译成.class字节码文件,在windows命令行中使用”javac-help”命令查看其用法:语法格式:javac<options><sourcefiles>options#命令行选项,可指定多个…

    2022年5月28日
    43
  • linux查看80端口占用情况_centos查看端口命令

    linux查看80端口占用情况_centos查看端口命令前言平常使用linux,我们经常需要查看哪个服务占用了哪个端口,接下来就为大家介绍了2种Linux查看端口占用情况可以使用lsof和netstat命令。1.lsof-i:端口号用

    2022年7月31日
    5
  • 极影AI剪辑教程

    极影AI剪辑教程

    2026年3月12日
    2
  • hashmap线程安全吗 什么解决方案_HashMap的底层实现原理

    hashmap线程安全吗 什么解决方案_HashMap的底层实现原理我们都知道HashMap是线程不安全的,在多线程环境中不建议使用,应该使用ConcurrentHashMap,但是其线程不安全体现在什么地方,可能并没有深入理解,本文将对该问题进行解密。

    2025年7月1日
    6
  • OLAP组件选型[通俗易懂]

    OLAP组件选型[通俗易懂]OLAP组件选型一、OLAP简介1、olap准则2、OLAP场景的关键特征3、与oltp比较二、开源引擎1、Hive2、sparkSQL3、presto4、kylin5、impala6、druid7、Greeplum8、clickhouse三、选型要求1、实时性要求较高,对接kafka,实时查询数据2、可以接入hive数据3、单表查询数据较多,较少的join,在数仓中完成宽表构建一、OLAP简介说起OLAP要追溯到1993年。1、olap准则准则1OLAP模型必须提供多维概念视图准则

    2025年6月8日
    4
  • linux重启网卡的命令行,linux系统怎么重启网卡?linux重启网卡的三种教程

    linux重启网卡的命令行,linux系统怎么重启网卡?linux重启网卡的三种教程在实际工作中,经常会遇到Linux系统进行重启网卡的操作。在这里整理一下,进行多种方法的网卡重启。一、servicenetworkrestart1、首先用CRT工具连接到Linux命令行界面。或者进入操作系统界面,选择终端输入。2、如果我们对所有的网卡进行重启操作。可以尝试输入:servicenetworkrestart命令进行操作。3、样就完成了用servicenetworkr…

    2026年2月17日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号