Matlab处理图像后实现简单的人脸检测

1.人脸检测原理框图

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

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

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

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

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

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

2 步骤

2.1 均值滤波

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

采用9x9模板进行线性均值滤波,因为后面调用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('把空洞填了')

结构元素采用21x21大小的全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返回所有满足要求的像素的索引,索引长度就是黑色像素的个数。

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

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<pickshape&pickshape<3,:);%筛选掉尺寸比例不合格
[~,arealind] = max(shapeind(:,3).*shapeind(:,4));
subplot(1,2,2)
imshow(rgb)
hold on
rectangle('Position',[shapeind(arealind,1),shapeind(arealind,2),shapeind(arealind,3),shapeind(arealind,3)],...
    'EdgeColor','g','Linewidth',2)
title('人脸检测')

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

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

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

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

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

所以第二行,通过逻辑表达式从BB内筛选出尺寸比例合格的方框,存在shapeind里面。
剩下的尺寸符合要求的方框里面要选出面积最大的那个,最后一行,得到面积最大的方框对应的索引。

把方框画出来。

3 检测结果

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

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

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

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

可以看到,进行边界加粗和空洞添补之后,眼睛部分的黑块被消除了,这使得脸部连通域更大了

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

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

图 24测试样例

图 25测试样例

图 26测试样例

图 27测试样例

图 28测试样例

图 29测试样例

图 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);

%最小化背景
%细分
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<pickshape&pickshape<3,:);%筛选掉尺寸比例不合格
[~,arealind] = max(shapeind(:,3).*shapeind(:,4));
subplot(1,2,2)
imshow(rgb)
hold on
rectangle('Position',[shapeind(arealind,1),shapeind(arealind,2),shapeind(arealind,3),shapeind(arealind,3)],...
    'EdgeColor','g','Linewidth',2)
title('人脸检测')
toc

到此这篇关于MATLAB处理图像后实现简单的人脸检测的文章就介绍到这了,更多相关MATLAB实现人脸检测内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Matlab实现图像边缘检测

    为了在一幅图像 f 的(x,y)位置寻找边缘的强度和方向,所选择的工具就是梯度,梯度使用向量来表示: 该向量指出了图像 f 在位置(x,y)处的最大变化率的方向,梯度向量的大小表示为: 它是梯度向量方向变化率的值. 梯度向量的方向表示为: 梯度算子 roberts算子: sobel算子: prewitt算子: Matlab实现 function output = my_edge(input_img,method) if size(input_img,3)==3 input_img=rgb2gra

  • Matlab 数字图像的滤波及边缘检测

    目录 一.图像滤波 1.1 线性滤波器 1.1.1 均值滤波 1.1.2 高斯滤波 1.2 非线性滤波器 1.2.1 中值滤波器 1.2.2 双边滤波器 1.3 滤波器的 Matlab 代码实现 二.图像边缘检测 2.1 一阶边缘检测算子 2.1.1 Sobel 算子 2.1.2 Canny 算子 2.2 二阶边缘检测算子 2.2.1 拉普拉斯算子 2.3 边缘检测的 Matlab 代码实现 2.4 边缘检测算法总结 三.参考资料 一.图像滤波 图像滤波的主要目的就是在尽量保留图像细节特征的条件

  • 图文详解matlab原始处理图像几何变换

    目录 (一)图像几何变换理论知识 (1)图像的平移与比例 (2)关于旋转变换 (3)关于对称变换 (4)复合变换 (二)matlab编程实现变换 (1)对图像的理解 (2)比例变换 (3)对称变换 总结 (一)图像几何变换理论知识 (1)图像的平移与比例 图像的平移很简单,平移前后的坐标分别为(x,y)和(x',y'),则满足的关系式为 x'= x +Tx: y'= y +Ty: 其中Tx与Ty分别为对应的偏移量. 图像的比例也很简单,可以描述为:x'=S_x * x;  y'=S_y * y;

  • Matlab处理图像后实现简单的人脸检测

    1.人脸检测原理框图 整体思路是寻找图片中最大的连通域,将其认定为人脸. 第一个环节均值滤波,是为了减弱图像的相关细节部分,以免毛刺影响后期连通域的形成,二值化方便形态学处理,减少运算量.考虑到人脸有黑人和白人黄种人,黑人肤色较深,在二值化之后面部区域不容易形成较大的连通域,如果采取形态学边界提取的办法,就可以避免这个问题,形态学边界提取,只要结构元素够大,也可以形成较大的封闭连通域. 然后就是纵向闭合操作,这一步我选择采用竖向长条状的结构元素进行闭合运算,因为人的脸部和颈部以及头发和衣物等等都

  • 用Python实现简单的人脸识别功能步骤详解

    前言 让我的电脑认识我,我的电脑只有认识我,才配称之为我的电脑! 今天,我们用Python实现简单的人脸识别技术! Python里,简单的人脸识别有很多种方法可以实现,依赖于python胶水语言的特性,我们通过调用包可以快速准确的达成这一目的.这里介绍的是准确性比较高的一种. 一.首先 梳理一下实现人脸识别需要进行的步骤: 流程大致如此,在此之前,要先让人脸被准确的找出来,也就是能准确区分人脸的分类器,在这里我们可以用已经训练好的分类器,网上种类较全,分类准确度也比较高,我们也可以节约在这方面花

  • 使用Python实现简单的人脸识别功能(附源码)

    目录 前言 一.首先 二.接下来 1.对照人脸获取 2. 通过算法建立对照模型 3.识别 前言 今天,我们用Python实现简单的人脸识别技术! Python里,简单的人脸识别有很多种方法可以实现,依赖于python胶水语言的特性,我们通过调用包可以快速准确的达成这一目的.这里介绍的是准确性比较高的一种. 一.首先 梳理一下实现人脸识别需要进行的步骤: 流程大致如此,在此之前,要先让人脸被准确的找出来,也就是能准确区分人脸的分类器,在这里我们可以用已经训练好的分类器,网上种类较全,分类准确度也比

  • python实现人脸检测的简单实例

    目录 OpenCV 代码结果: 方法如下: 完整代码: 总结 OpenCV OpenCV 是计算机视觉领域最受欢迎的开源库,起初它由 C/C ++ 编写,现在用 Python 也能使用. OpenCV 可以使用机器学习算法搜索图像中的人脸.由于人脸比较复杂,所以并没有一种简单的测试可以告诉我们它是否发现了人脸.但是,算法能够匹配到数千个很小的模式和特征.算法会将识别人脸的任务分解为几千个非常非常小的任务,像这种很小的任务,解决起来就比较容易了.这样的微小任务就被称为分类器. 代码结果: 方法如下

  • Matlab控制电脑摄像实现实时人脸检测和识别详解

    目录 一.理论基础 二.核心程序 三.仿真测试结果 一.理论基础 人脸识别过程主要由四个阶段组成:人脸检测.图像预处理.面部特征提取和特征识别.首先系统从视频或者相机中捕获图像,检测并分割出其中的人脸区域:接下来通过归一化.对齐.滤波等方法改善图像的质量,这里的质量主要由最终的人脸识别率决定:特征提取(降维)环节尤为重要,其初衷是减少数据量从而减轻计算负担,但良好的特征选取可以降低噪音和不相关数据在识别中的贡献度,从而提高识别精度:特征识别阶段需要根据提取的特征训练一个分类器,对于给定的测试样本

  • Matlab中图像数字水印算法的原理与实现详解

    目录 一.背景意义 二.基本原理 三.算法介绍 3.1 数字水印嵌入 3.2 数字水印提取 四.程序实现 一.背景意义 数字水印技术作为信息隐藏技术的一个重要分支,是将信息(水印)隐藏于数字图像.视频.音频及文本文档等数字媒体中,从而实现隐秘传输.存储.标注.身份识别.版权保护和防篡改等目的. 随着 1996 年第一届信息隐藏国际学术研讨会的召开,数字水印技术的研究得到了迅速的发展,不少政府机构和研究部门加大了对其的研究力度,其中包括美国财政部.美国版权工作组.美国洛斯阿莫斯国家实验室.美国海陆

  • 基于Python实现简单的人脸识别系统

    目录 前言 基本原理 代码实现 创建虚拟环境 安装必要的库 前言 最近又多了不少朋友关注,先在这里谢谢大家.关注我的朋友大多数都是大学生,而且我简单看了一下,低年级的大学生居多,大多数都是为了完成课程设计,作为一个过来人,还是希望大家平时能多抽出点时间学习一下,这种临时抱佛脚的策略要少用嗷.今天我们来python实现一个人脸识别系统,主要是借助了dlib这个库,相当于我们直接调用现成的库来进行人脸识别,就省去了之前教程中的数据收集和模型训练的步骤了. B站视频:用300行代码实现人脸识别系统_哔

  • Android动态人脸检测的示例代码(脸数可调)

    人脸检测 这里的人脸检测并非人脸识别,但是却可以识别出是否有人,当有人时候,你可以将帧图进行人脸识别(这里推荐Face++的sdk),当然我写的demo中没有加入人脸识别,有兴趣的朋友可以追加.face++ android自带的人脸检测 这里我们用到了人脸检测类为 FaceDetector.这个类提供了强大的人脸检测功能,可以方便我们进行人脸的侦测,因此我们使用他来进行动态的人脸检测,实现原理,其实也挺简单,主要是通过Carmen的回调PreviewCallback 在其中对帧图进行操作,并通过

  • Python+OpenCV人脸检测原理及示例详解

    关于opencv OpenCV 是 Intel 开源计算机视觉库 (Computer Version) .它由一系列 C 函数和少量 C++ 类构成,实现了图像处理和计算机视觉方面的很多通用算法. OpenCV 拥有包括 300 多个 C 函数的跨平台的中.高层 API .它不依赖于其它的外部库 -- 尽管也可以使用某些外部库. OpenCV 对非商业应用和商业应用都是免费 的.同时 OpenCV 提供了对硬件的访问,可以直接访问摄像头,并且 opencv 还提供了一个简单的 GUI(graph

  • python利用OpenCV2实现人脸检测

    最近,带领我的学生进行一个URTP项目设计,需要进行人脸识别.由于现在的OpenCV已经到了2.X版本,因此就不想用原来的1.X版本的代码,而网上存在的代码都是1.X版本的代码,尝试自己写一段2.X版本的代码,反复查阅资料,今天终于测试成功(很明显2.X版本的代码要比1.X的代码更简单),供大家好参考,代码如下:(2017年5月12日在python3.6.1下做一简单的修改) import cv2 import numpy as np cv2.namedWindow("test")#命

随机推荐