写在论文提交结束之后:
才开始建模不久举行的一次校赛。
感觉团队的想法很好,但是自己的程序实现一直有问题,所以就想在结束后认真弄懂问题。
这篇文章主要是在介绍代码,并且有可以成功运行的代码。
原题:
(1)建立人脸位置判断的数学模型,判断人脸在照片中的大致位置,并在图 1 和 图 2 中用你设计的模型框出人脸的大致位置。
(2) 在问题(1)的基础上,建立人脸精确识别的数学模型,判断图 2 中各个人物 的脸型、鼻型、眼型、唇形等。(提示:如果你在 DIY 过程中遇到了困难,不妨降低要 求,比如说鼻型可以分为“大鼻子”和“小鼻子”。)
(3)在问题(2)的基础上,建立人脸匹配的数学模型,判断图 2、图 3 中是否有 人物与图 1 的人物是同一人,如果有,请在图片中框出具体是哪个人物与图 1 的人物一 样。
预处理的作用:
所有图片可以均经过问题一得到相应的人脸图;
准备使用Viola-Jones 级联分类器人脸检测方法;
对于此题所给图片经测试这种方法精确度较高;
操作流程:
使用Harris角点检测,基于图像像素灰度值的变化梯度,即通过一个矩形窗口在图像上移动已检测该区域的图像灰度值变化。
提取特征点,定位五官具体位置,再根据长宽比,面积占比等特征辨别形状;
操作流程:
VJ算法直接调用系统已封装好的vision.CascadeObjectDetector
详细说明地址:
https://ww2.mathworks.cn/help/vision/ref/vision.cascadeobjectdetector-system-object.html
在这个部分经过所给图片的尝试,选择FrontalFaceLBP,即根据局部二进制模式(LBP)来编码面部特征
第一题完整代码如下:
function question_1()
clear;
clc;
%% 读取图像
I=imread('1.jpg');
Ori=I;
%% 预处理(输出为Img)
%光线补偿
Img=imadjust(I,[],[]); %注意imadjust函数的用法
%灰度
Img=rgb2gray(Img);
%% 中值滤波(去噪,输出为 I,入口需灰度)
I=medfilt2(Img); %中值滤波的函数,第二个参数为二维矩阵,代表选取的 平滑窗口,一般为 3*3,可以进行调整(如果为灰度图像可不要第二个参数)
%% 灰度变换增强(选择后决定最佳,输出为 H)
%灰度 (可选择)
judge=0;
while (judge==0)
judge=1;
disp('基本的灰度变换(2-伽马变换;3-分段线性;4-直方图均衡)');
choosen=input('请输入你的选择:');
switch choosen
%3.伽马变换
case 2
x=0:255;
a=80;
b=1.8;
c=0.009;
H=b.^(c.*(double(I)-a)-1);
y=b.^(c.*(x-a))-1;
% figure
% subplot(2,2,1),imshow(I);
% subplot(2,2,3),imshow(H),title('伽马变换后的图像');
% figure,plot(x,y),title('伽马变换折线图');
%4.分段线性变换(入口需灰度)
case 3
f0=0;g0=0;
f1=10;g1=30;
f2=220;g2=255;
f3=255;g3=255;
% figure,plot([f0,f1,f2,f3],[g0,g1,g2,g3]),title('分段线性折线图');
r1=(g1-g0)/(f1-f0);
b1=r1*f0+g0;
r2=(g2-g1)/(f2-f1);
b2=r2*f1+g1;
r3=(g3-g2)/(f3-f2);
b3=r3*f2+g2;
% axis([0 225 0 225]);
[m,n]=size(I);
h=double(I);
for i=1:m
for j=1:n
t=h(i,j);
g(i,j)=0;
if((t>=f0)&&(t<=f1))
g(i,j)=r1*t+b1;
else
if((t>=f1)&&(t<=f2))
g(i,j)=r2*t+b2;
else
if((t>=f2)&&(t<=f3))
g(i,j)=r3*t+b3;
end
end
end
end
end
H=mat2gray(g); %归一化,使矩阵的每个元素的值都在 0 和 1 之间(其 源图像要求为二维的灰度图像)
% figure,imshow(H),title('分段线性变换后的图像');
%5.直方图均衡(入口需灰度)
case 4
H=histeq(I);
%输入为二维图,要先灰度;
% figure
% subplot(121),imshow(I);
% subplot(122),imshow(H);
otherwise
disp('无效!请重新输入!');
judge=0;
end
end
%% 小波增强(低频系数增强,高频系数衰减,输出为 HH)(可选择)
judge=0;
while(judge==0)
judge=1;
choosen=input('是否进行小波增强(1.是;0.否):');
switch choosen
case 1
HH=double(H); %转换成 double,避免精度丢失
[c,s]=wavedec2(HH,2,'db3'); %多尺度一维小波分级(利用小波'db3'对信号 HH 进行 2 层分解)
cs=size(c);
for i=1:cs(2) %对图像的分解系数做处理,以突出所需部分并弱化不需要的部分
if(c(i)>350)
c(i)=2*c(i);
else
c(i)=0.5*c(i);
end
end
H=waverec2(c,s,'db3'); %对图像进行小波重构(小波逆变换)
% figure,imshow(H),title('小波重构后的图像');
case 0
break;
otherwise
disp('无效!请重新输入!');
jugde=0;
end
end
%% 正式处理:VJ/Adaboost算法
detector=vision.CascadeObjectDetector; %使用Viola-Jones算法创建一个检测器来检测对象
%检测面部
detector.ClassificationModel='FrontalFaceLBP';
bboxes=step(detector,H); %直接把detector当作函数使用
%处理bboxes(因为不处理bboxes,即直接VJ算法算出来的坐标值,原图会在脸的范围之内,即没有全脸,不能判断脸型)
for i=1:size(bboxes,1)
bboxes(i,1)=bboxes(i,1)+9;
bboxes(i,2)=bboxes(i,2)+9;
end
%%画框
Face=insertObjectAnnotation(Ori,'rectangle',bboxes,'Face','Font','Comic Sans MS','TextBoxOpacity',0,'FontSize',25,'LineWidth',3,'Color','red','TextColor','white');
figure,imshow(Face),title('检测到的人脸');
%% 提取已检测到的人脸图像
for i=1:size(bboxes,1)
pic=imcrop(I,[bboxes(i,:)]);
imwrite(pic,[num2str(i),'.png']); %注意imwrite的用法
end
end
值得注意的是,vision.CascadeObjectDetector算法的入口为RGB图像或者灰度图像,可以根据需要增加或者修改预处理部分,只需要能连接上vision.CascadeObjectDetector的接口即可。
寻找特征点时直接调用系统函数concer;
此处主要指第一题中所用的vision.CascadeObjectDetector的扩展部分;
因为题目所需,我们可以直接使用已训练好的vision.CascadeObjectDetector系统中的分类器,但在多数时候比如说对车牌号等的检测,需要我们重新寻找训练集取训练分类器,而在matlab中有已经写好的算法,可以直接导入训练集和数据
详细说明地址:https://ww2.mathworks.cn/help/vision/ug/train-a-cascade-object-detector.html
这次因为时间关系直接调用matlab中的自带函数,希望后面自己能写出类似深度学习的函数。
本来准备用基于肤色建立的高斯模型和VJ算法结合的形式,但由于当前只能调用vision.CascadeObjectDetector实现VJ算法,而
vision.CascadeObjectDetector入口只能是RGB图像或者灰度化后的图像
肤色高斯模型大多输出二值化后的图像
两个函数的衔接有问题,所以只能采用精度更高的VJ算法。
还有基于肤色建立的高斯模型:
本题选用的是通过调用concer()函数实现Haar角点检测;
下面将介绍通过高斯卷积函数进行卷积滤波,提取特征,寻找特征点的方式实现Haar角点检测: