Matlab人脸检测算法详解

1,528 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

这是一个Matlab人脸检测算法详解

前言

目前主流的人脸检测与人脸识别算法主要基于人工神经网络进行训练与检测,本文基于数字图像处理解析一个非人工神经网络的有趣人脸检测算法。图片与源码可以从下文获取或点击这里获取:百度云下载材料点这里,提取码2333

人脸检测结果

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

算法详解

该算法主要通过识别二值图像下的最大连通区域来检测人脸,定义二值图像中宽长比小于1.8的最大连通区域(mx)为人脸区域。再将P的左上角坐标作为识别框的左上角坐标,以mx在X轴的延伸长度作为识别框在X与Y的延伸长度,从而绘制出一个黄色2像素宽度的正方形识别框。框中的区域即为该算法所识别的人脸区域。

源代码解析

clear all  %清除工作台中所有参数与数据
clc    %清除界面

i=imread('5.jpg');         %读取所需预测的图像
I=rgb2gray(i);             %将该图像转换为灰度图
BW=im2bw(I);             %将灰度图像转换为二值图像
figure(1);
imshow(BW);

%将背景最小化处理
[n1, n2]=size(BW);
r=floor(n1/10);  
c=floor(n2/10);
x1=1;x2=r;
s=r*c;

for i=1:10
    y1=1;y2=c;
    for j=1:10
        if(y2<=c || y2>=9*c) || (x1==1 || x2==r*10)
            loc=find(BW(x1:x2,y1:y2)==0);
            [o,p]=size(loc);
            pr=o*100/s;
            if pr<=100
                BW(x1:x2,y1:y2)=0;
                r1=x1;r2=x2;s1=y1;s2=y2;
                pr1=0;
            end
            imshow(BW);
        end
        y1=y1+c;
        y2=y2+c;
    end
    x1=x1+r;
    x2=x2+c;
end
figure(2)
subplot(1,2,1);
imshow(BW)
title('二值图像');

L=bwlabel(BW,8);   %找到连通区域,定义为8连通
BB=regionprops(L,'BoundingBox');%联通区用边界框框取包含连通区域的最小矩形
BB1=struct2cell(BB);  %把结构体数组转换成元胞数组,每个元胞中含有4个数据
BB2=cell2mat(BB1);   %将元胞展开为行数为一的矩阵,BB2中元素的个数为BB1的4倍

[s1,s2]=size(BB2);
mx=0;     %mx为最大连通区域,初值为0
for k=3:4:s2-1    %k=3的取值为连通区域的X方向扩展长度,逐级加4,即遍历每个连通区域的X长度
    p=BB2(1,k)*BB2(1,k+1);  %p为连通区域的面积
    if p>mx && (BB2(1,k+1)/BB2(1,k))<1.8  %选区宽长比大于1.8的最大连通区域
        mx=p;
        j=k;
    end
end

subplot(1,2,2);
title('人脸检测');
imshow(I);
hold on;
rectangle('Position',[BB2(1,j-2),BB2(1,j-1),BB2(1,j),BB2(1,j)],'EdgeColor','y','LineWidth',2);
%rectangle各参数为:起点坐标,颜色,宽度

所调用函数解析

imread('5.jpg'); 读取图像

rgb2gray(i) 将该图像转换为灰度图,参数i为读取的图像

im2bw(I) 将灰度图像转换为二值图像,参数I为灰度图像

floor(n); 朝负无穷大方向取整,参数n为任意数,对于复数,分别对实部和虚部取整

figure(1); 定义绘制图像的名称

imshow(I); 绘制图像,参数I为图像名称

subplot(m,n,p); 将多个图画到一个平面上的工具。其中,m表示是图排成m行,n表示图排成n列,p表示图所在的位置,p=1表示从左到右从上到下的第一个位置,p也可以为矩阵以表示其他行列

bwlabel(BW,n)

L=bwlabel(BW,n);
定义一个与BW大小相同的L矩阵,其中n的值为4或8,表示定义4连通或8连通 4连通:一个像素的上下左右4个方向有相邻的像素,则认为他们是连接的,这些像素的组成区域为4连通区域。 8连通:一个像素的上下左右,上左上右下左下右8个方向有相邻的像素,则认为他们是连接的,这些像素的组成区域为8连通区域。 例如: BW = 1 1 1 0 0  1 1  0 0 1 1 1 0 0  1 1  0 0 1 1 1 0 1  1 1  1 0 1 1 1 0 0  1 1  0 0 0 0 0 0 0  1 1  0 0 1 1 1 0 0  0 0  1 1 1 1 1 0 0  0 0  1 1 1 1 1 0 0  0 0  1 1 1 1 1 1 1  0 0  1 1 则L=bwlabel(BW,4)为(相同数字表示在同一个连通区域): L = 1 1 1 0 0  2 2  0 0 1 1 1 0 0  2 2  0 0 1 1 1 0 2  2 2  2 0 1 1 1 0 0  2 2  0 0 0 0 0 0 0  2 2  0 0 3 3 3 0 0  0 0  4 4 3 3 3 0 0  0 0  4 4 3 3 3 0 0  0 0  4 4 3 3 3 3 3  0 0  4 4

例如: L=bwlabel(BW,8)为(相同数字表示在同一个连通区域): L = 1 1 1 0 0  2 2  0 0 1 1 1 0 0  2 2  0 0 1 1 1 0 2  2 2  2 0 1 1 1 0 0  2 2  0 0 0 0 0 0 0  2 2  0 0 3 3 3 0 0  0 0  2 2 3 3 3 0 0  0 0  2 2 3 3 3 0 0  0 0  2 2 3 3 3 3 3  0 0  2 2

regionprops

BB=regionprops(L,'BoundingBox'); regionprops可以带有多种参数,BoundingBox表示为选区取包含连通区域的最小矩形 返回的结果为【x,y,w,h】,其中x与y为该矩形的左上角坐标,w与h为x与y方向上的延伸长度即矩形的长与宽。此外,其他参数及意义为: Area:各区域像素总和 Centroid: 各区域重心 ConvexHull:包含该区域的最小凸多边形 EquivDiameter:与该区域具有相同面积的圆的直径

Image:与某区域具有相同大小的逻辑矩阵 FilledImage:与某区域具有相同大小的填充逻辑矩阵 FilledArea:填充区域图像中的on像素个数

ConvexArea: 填充区域凸多边形图像中的on像素个数 EulerNumber:几何拓扑中的一个拓扑不变量——欧拉数 Extrema:八方向区域极值点'

Solidity: 同时在区域和其最小凸多边形中的像素比例' Extent:同时在区域和其最小边界矩形中的像素比例 PixelIdxList: 存储区域像素的索引下标 PixelList: 存储上述索引对应的像素坐标

BB1=struct2cell(BB);
把结构体数组转换成元胞数组,每个元胞元胞的元素为【x,y,w,h】

BB2=cell2mat(BB1);
将元胞展开为行数为一的矩阵,BB2中元素的个数为BB1的4倍

rectangle

rectangle('Position',[x,y,w,h],'EdgeColor','y','LineWidth',2) 该函数为选取框绘制函数,【x,y,w,h】与上述参数含义相同 EdgeColor为颜色参数 LineWidth为边框线宽度参数 'Curvature',[1,1]表示x,y方向上的曲率都为1,即为圆弧 Facecolor为内填充颜色参数 等等

总结

这个算法虽然只是通过玩弄这些像素来实现人脸检测,精度有限,但是如果想要进行后续的人脸识别,这或许的一个减少手工标注数据集的好方法