【人脸表情识别】基于matlab GUI CNN人脸表情识别【含Matlab源码 787期】

167 阅读14分钟

一、简介

1 CNN的应用领域
CNN在以下几个领域均有不同程度的应用:
图像处理领域(最主要运用领域) —— 图像识别和物体识别,图像标注,图像主题生成,图像内容生成,物体标注等。
视频处理领域 —— 视频分类,视频标准,视频预测等
自然语言处理(NLP)领域 —— 对话生成,文本生成,机器翻译等
其它方面 —— 机器人控制,游戏,参数控制等

2 CNN的网络结构
2.1 传统神经网络
在这里插入图片描述
上图为传统的神经网络的结构, 它是一种全连接的结构, 这也就造成了参数训练的难度加深. 还有BP求解中的可能出现的梯度爆炸和梯度消失的现象等.此外,深度结构(涉及多个非线性处理单元层)非凸目标代价函数中普遍存在的局部最小是训练困难的主要来源. 这些因素都造成了传统的神经网络的不适用性,所以没有较为广泛的运用.

2.2 卷积神经网络(Convolutional Neural Networks,CNN)
在这里插入图片描述
上图为CNN的网络结构,CNN可以有效的降低反馈神经网络(传统神经网络)的复杂性,常见的CNN结构有LeNet-5、AlexNet、ZFNet、VGGNet、GoogleNet、ResNet等等,其中在LVSVRC2015 冠军ResNet是AlexNet的20多倍,是VGGNet的8倍;从这些结构来讲CNN发展的一个方向就是层次的增加,通过这种方式可以利用增加的非线性得出目标函数的近似结构,同时得出更好的特征表达,但是这种方式导致了网络整体复杂性的增加,使网络更加难以优化,很容易过拟合。

CNN的网络结构和传统神经网络结构异同点有:

(1)CNN主要有数据输入层, 卷积层, RELU激励层, 池化层, 全连接层, Batch Normalization Layer(不一定存在). 传统神经网络主要有数据输入层, 一个或多个隐层以及数据输出层. 比较可以发现CNN仍然使用传统神经网络的层级结构.
(2)CNN的每一层都具有不同的功能, 而传统神经网络每一层都是对上一层特征进行线性回归, 再进行非线性变换的操作.
(3)CNN使用RELU作为激活函数(激励函数) , 传统神经网络使用sigmoid函数作为激活函数.
(4)CNN的池化层实现数据降维的作用,提取数据的高频信息.传统神经网络没有这个作用.
(5)CNN主要是在图像分类和物品识别等应用场景应用比较多

2.2.0 CNN的主要层次介绍
CNN保持了层级网络结构,不同层次使用不同的形式(运算)与功能
数据输入层:Input Layer
卷积计算层:CONV Layer
ReLU激励层:ReLU Incentive Layer
池化层:Pooling Layer
全连接层:FC Layer
备注:Batch Normalization Layer(可能有)

2.2.1 数据输入层 (Input Layer)
和神经网络/机器学习一样,需要对输入的数据需要进行预处理操作,需要进行预处理的主要原因是:
输入数据单位不一样,可能会导致神经网络收敛速度慢,训练时间长
数据范围大的输入在模式分类中的作用可能偏大,而数据范围小的作用就有可能偏小
由于神经网络中存在的激活函数是有值域限制的,因此需要将网络训练的目标数据映射到激活函数的值域
S形激活函数在(0,1)区间以外区域很平缓,区分度太小。例如S形函数f(X),f(100)与f(5)只相差0.0067
常见的数据预处理的方式有以下几种:
(1)均值化处理 — 即对于给定数据的每个特征减去该特征的均值(将数据集的数据中心化到0)
(2)归一化操作 — 在均值化的基础上再除以该特征的方差(将数据集各个维度的幅度归一化到同样的范围内)
(3)PCA降维 — 将高维数据集投影到低维的坐标轴上, 并要求投影后的数据集具有最大的方差.(去除了特征之间的相关性,用于获取低频信息)
(4)白化 — 在PCA的基础上, 对转换后的数据每个特征轴上的幅度进行归一化.用于获取高频信息.
(5) ufldl.stanford.edu/wiki/index.…

在这里插入图片描述
x = x - np.mean(x, 0) x = (x - np.mean(x, 0)) / np.std(x, 0)
在这里插入图片描述
x -= np.mean(x, axis=0) # 去均值
cov = np.dot(x.T, x) / x.shape[0] # 计算协方差
u, s, v = np.linalg.svd(cov) # 进行 svd 分解
xrot = np.dot(x, u)
x = np.dot(x, u[:, :2]) # 计算 pca
x = xrot / np.sqrt(s + 1e-5) # 白化
在这里插入图片描述
备注:虽然我们介绍了PCA去相关和白化的操作,但是实际上在卷积神经网络中,一般并不会适用PCA和白化的操作,一般去均值和归一化使用的会比较多.
建议:对数据特征进行预处理,去均值、归一化

2.2.2 卷积计算层(CONV Layer)
这一层就是卷积神经网络最重要的一层,也是“卷积神经网络”的名字由来。
人的大脑在识别图片的过程中,会由不同的皮质层处理不同方面的数据,比如:颜色、形状、光暗等,然后将不同皮质层的处理结果进行合并映射操作,得出最终的结果值,第一部分实质上是一个局部的观察结果,第二部分才是一个整体的结果合并.
还有,对于给定的一张图片, 人眼总是习惯性的先关注那些重要的点(局部), 再到全局. 局部感知是将整个图片分为多个可以有局部重叠的小窗口, 通过滑窗的方法进行图像的局部特征的识别. 也可以说每个神经元只与上一层的部分神经元相连, 只感知局部, 而不是整幅图像.
基于人脑的图片识别过程,我们可以认为图像的空间联系也是局部的像素联系比较紧密,而较远的像素相关性比较弱,所以每个神经元没有必要对全局图像进行感知,只要对局部进行感知,而在更高层次对局部的信息进行综合操作得出全局信息;即局部感知。
在这里插入图片描述
在这里插入图片描述
局部关联:每个神经元看做一个filter
窗口(receptive field)滑动,filter对局部数据进行计算
相关概念:深度:depth,步长:stride,填充值:zero-padding
CONV过程参考:cs231n.github.io/assets/conv…
一个数据输入,假设为一个RGB的图片
在神经网络中,输入是一个向量,但是在卷积神经网络中,输入是一个多通道图像(比如这个例子中有3个通道)

在这里插入图片描述

  1. 局部感知
    在进行计算的时候,将图片划分为一个个的区域进行计算/考虑;
    那么,为什么可以使用局部感知呢?
    我们发现, 越是接近的像素点之间的关联性越强, 反之则越弱. 所以我们选择先进行局部感知, 然后在更高层(FC层)将这些局部信息综合起来得到全局信息的方式.
  2. 参数共享机制
    所谓的参数共享就是就是同一个神经元使用一个固定的卷积核去卷积整个图像,也可以认为一个神经元只关注一个特征. 而不同的神经元关注多个不同的特征.(每一个神经元都可以看作一个filter)
  3. 滑动窗口的重叠
    滑动窗口重叠就是在进行滑窗的过程中对于相邻的窗口有局部重叠的部分,这主要是为了保证图像处理后的各个窗口之间的边缘的平滑度。降低窗口与窗口之间的边缘不平滑的特性。
    固定每个神经元的连接权重,可以将神经元看成一个模板;也就是每个神经元只关注一个特性
    需要计算的权重个数会大大的减少

4)) 卷积计算

卷积的计算就是: 对于每一个神经元的固定的卷积核矩阵与窗口矩阵的乘积(对应位置相乘)再求和之后再加上偏置项b的值, 就得到了代表该神经元所关注的特征在当前图像窗口的值.
如图2.4所示, 可以看出卷积计算的过程.动态图点击这里查看.
在这里插入图片描述
2.2.3 RELU激励层
这一层就是激活层, 在CNN中一般使用RELU函数作为激活函数.它的作用主要是将卷积层的输出结果做非线性映射.
在这里插入图片描述

  1. 常见的几种激活函数
    激活函数之 Sigmoid、tanh、ReLU、ReLU变形和Maxout
    sigmoid函数(S函数)
    Tanh函数(2S函数)
    RELU函数 ----> 线性修正单元 —> max{ 0, x } ==>无边界, 易出现’死神经元’
    Leaky ReLU 函数 —> 若x> 0 , 则输出x ; 若x<0,则 alphax, 其中 0< alpha <1 ==> 对RELU的改进
    ELU 函数 —> 若x> 0 , 则输出x ; 若x<0,则 alpha
    (e^x - 1), 其中 0< alpha <1 ==> 也是一种对RELU的改进
    Maxout函数 —> 相当于增加了一个激活层
  2. 激活函数的一些建议
    一般不要使用sigmoid函数作为CNN的激活函数.如果用可以在FC层使用.
    优先选择RELU作为激活函数,因为迭代速度快,但是有可能效果不佳
    如果2失效,请用Leaky ReLU或者Maxout,此时一般情况都可以解决啦
    在极少的情况下, tanh也是有不错的效果的
    2.2.4 池化层 (Poling Layer)
    在连续的卷积层中间存在的就是池化层,主要功能是:通过逐步减小表征的空间尺寸来减小参数量和网络中的计算;池化层在每个特征图上独立操作。使用池化层可以压缩数据和参数的量,减小过拟合。简而言之,如果输入是图像的话,那么池化层的最主要作用就是压缩图像。
    在这里插入图片描述
    池化层中的数据压缩的策略主要有:
    Max Pooling(最大池化)—> 选择每个小窗口中最大值作为需要的特征像素点(省略掉不重要的特征像素点)
    Average Pooling(平均池化) —> 选择每个小窗口中平均值作为需要的特征像素点
    在这里插入图片描述
    池化层选择较为重要的特征点, 可以降低维度, 能够在一定程度上防止过拟合的发生.

2.2.5 FC全连接层
类似传统神经网络中的结构,FC层中的神经元连接着之前层次的所有激活输出;换一句话来讲的话,就是两层之间所有神经元都有权重连接;通常情况下,在CNN中,FC层只会在尾部出现

通过全连接结构,将前面输出的特征重新组合成一张完整的图像.

一般的CNN结构依次为:

INPUT
[[CONV -> RELU] * N -> POOL?]M
[FC -> RELU] * K
FC
2.2.6 Batch Normalization Layer(一般用于卷积层后面,主要是使得期望结果服从高斯分布,使用较少!!)
Batch Normalization Layer(BN Layer)是期望我们的结果是服从高斯分布的,所以对神经元的输出进行一下修正,一般放到卷积层后,池化层前。
论文:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift;
论文链接:arxiv.org/pdf/1502.03…
在这里插入图片描述
如果输出的是N
D的结果,对D个维度每个维度求解均值和方差。
根据均值和方差做归一化。
在这里插入图片描述
强制的进行归一化操作可能存在一些问题,eg: 方差为0等
在这里插入图片描述
Batch Normalization优点:
梯度传递(计算)更加顺畅,不容易导致神经元饱和(防止梯度消失(梯度弥散)/梯度
爆炸)
学习率可以设置的大一点
对于初始值的依赖减少
Batch Normalization缺点:
如果网络层次比较深,加BN层的话,可能会导致模型训练速度很慢。
备注:BN Layer慎用!!!

3 CNN的优缺点
优点
① 使用局部感知和参数共享机制(共享卷积核), 对于较大的数据集处理能力较高.对高维数据的处理没有压力
② 能够提取图像的深层次的信息,模型表达效果好.
③ 不需要手动进行特征选择, 只要训练好卷积核W和偏置项b, 即可得到特征值.

缺点
① 需要进行调参, 模型训练时间较长, 需要的样本较多, 一般建议使用GPU进行模型训练.
② 物理含义不明, 每层中的结果无法解释, 这也是神经网络的共有的缺点.

二、源代码

function main
clc
close all
 
% 创建人脸检测对象
faceDetector = vision.CascadeObjectDetector;
 
% 人脸检测
FaceRecognition(faceDetector);
end
 
%% 选择图片
function I = SelectPicture()
[FileName,PathName] = uigetfile('*.jpg', '选择一张图片');
if isequal(FileName,0)
    disp('没选择图片,请重新选择!')
    I = [];
else
    I = imread(fullfile(PathName,FileName));
end
end
 
%% 人脸检测
function [I_faces, bbox] = GetFaces(faceDetector, I)
% 检测人脸
bbox = step(faceDetector, I);
 
% 创建一个形状插入对象来绘制边框圈出的检测的结果
if size(I, 3) == 1 % 灰度图像,插入白色或黑色框
    if mean(I(:)) > 128 % 图像较亮,使用黑框
        shapeInserter = vision.ShapeInserter();
    else % 图像较暗,使用白框
        shapeInserter = vision.ShapeInserter('BorderColor','White');
    end
else % 彩色图像,插入红色框
    shapeInserter = vision.ShapeInserter('BorderColor','Custom','CustomBorderColor',[255 0 0]);
end
 
% 绘制边框以圈出结果
I_faces = step(shapeInserter, I, int32(bbox));
end
 
%% 图片人脸检测
function FaceRecognition(faceDetector)
% 鼠标单击响应
    function BtnDownFcn(h, evt)
        FaceRecognition(faceDetector);
    end
 
% 选择文件
I = SelectPicture();
if isempty(I)
    return
end
 
% 人脸检测
[I_faces, bbox] = GetFaces(faceDetector, I);
 
close all
% 创建figure对象
fig1 = figure;
pos1 = get(fig1,'Position');
set(fig1,'Position',[10 pos1(2:4)]);
set(fig1,'WindowButtonDownFcn',@BtnDownFcn);
 
% 显示
figure(fig1)
imshow(I_faces)
title('单击此图片选择另一图片识别')
for i = 1:size(bbox, 1)
    text(bbox(i, 1), bbox(i, 2), mat2str(i), 'color', 'r')
end
 
% 检测
intbbox = int32(bbox);
for i = 1:size(intbbox, 1)
    xs = intbbox(i, 1);
    xe = xs + intbbox(i,3);
    ys = intbbox(i, 2);
    ye = ys + intbbox(i,4);
    
    % 创建figure
    if rem(i, 16) == 1
        fig2 = figure; %#ok
    end
    function varargout = FaceSystem(varargin)
% FACESYSTEM MATLAB code for FaceSystem.fig
%      FACESYSTEM, by itself, creates a new FACESYSTEM or raises the existing
%      singleton*.
%
%      H = FACESYSTEM returns the handle to a new FACESYSTEM or the handle to
%      the existing singleton*.
%
%      FACESYSTEM('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in FACESYSTEM.M with the given input arguments.
%
%      FACESYSTEM('Property','Value',...) creates a new FACESYSTEM or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before FaceSystem_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to FaceSystem_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help FaceSystem

% Last Modified by GUIDE v2.5 20-Apr-2018 19:18:59

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @FaceSystem_OpeningFcn, ...
                   'gui_OutputFcn',  @FaceSystem_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before FaceSystem is made visible.
function FaceSystem_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to FaceSystem (see VARARGIN)

% Choose default command line output for FaceSystem
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes FaceSystem wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = FaceSystem_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global str;
global a0;

[filename,pathname]=...
    uigetfile({'*.jpg';'*.bmp';'*.gif'},'choose');

str=[pathname filename]
if str~=0;
a0=imread(str);

% 同学在这里写上进度条的代码 等待对话框
h=waitbar(0,'Pleast waiting, reading...');
%*********
axes(handles.axes1);
axis off
imshow(a0);
title('原图像')

waitbar(1,h,'finish');
pause(0.05);
delete(h);
end
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
global a0;
global dets
global i_face;
global im
i_face=0;
faceDetector = vision.CascadeObjectDetector;
[im, dets] = GetFaces(faceDetector, a0);
DisplayDetections(im, dets);


% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global dets
global i_face;
global a0;
global A_face;
[M,N]=size(dets);
if (i_face>0)&(i_face<=M)
    i_face=i_face-1;
    i=i_face
    A_face=a0(dets(i,2):(dets(i,2)+dets(i,4)),dets(i,1):(dets(i,1)+dets(i,3)),:); 
    axes(handles.axes2);
    axis off
    imshow(A_face);
    title('待识别的人脸');
end

% --- Executes on button press in pushbutton4.
function pushbutton4_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton4 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global dets
global a0;
global i_face;
global A_face;
[M,N]=size(dets);
if (i_face>=0)&(i_face<M)
    i_face=i_face+1;
    i=i_face
    A_face=a0(dets(i,2):(dets(i,2)+dets(i,4)),dets(i,1):(dets(i,1)+dets(i,3)),:);    
    axes(handles.axes2);
    axis off
    imshow(A_face);
    title('待识别的人脸');
end

三、运行结果

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

四、备注

版本:2014a