2018年五一没有出去玩,参加了我第一次数学建模,就是华中赛,当时的我屁都不懂(虽然现在也是),在组里就是端茶递水混子选手。这次建模最大的收获不是一等奖,而是认识了两个建模队友,也是我大学最好的朋友唐j和胡总。最近闲来无事,回顾一下,虽说已经做出来的东西再看意义不大了,但是代码却不是我写的,我的代码力一直是helloworld级别,正好从基础练起。也算是一种学习和生活的记录。
一起骂娘一起笑,一起挠头一起肝,这也许就是建模的魅力吧。
问题重述
随着信息时代的发展,新一代信息技术正在着力打造智慧生活,人工智能 在现代智慧生活中有着举足轻重的地位。什么是人工智能?简而言之就是,让 机器人能够学习并模仿人类行为,甚至能够像人一样思考。人工智能机器人认 识和接触这个世界最主要的途径是“看”和“听”,而第一步就是要让人工智能 机器人能够“看”。
特别地,人脸识别在人工智能中显得特别重要,机器人通 过人脸识别技术认识周围的人,和人们面对面打交道。 人脸识别除了在人工智能中有不少应用之外,这项技术走进了我们的日 常生活:美图秀秀等手机 APP 把人脸识别技术用于“一键美颜”; 有些手 机,自拍时你能看到有一个小方框框住了你的脸,你一动,小方框也会跟着 你动,在相册里,系统能够挑出照片里的各个人物,还能找到这个人物的其 他照片。比如说“How-old.Net”这个 APP,它能看脸猜年龄,曾经风靡了朋 友圈;学校和公司逐步安装了人脸识别考勤机;警方在刑事侦查时,也经常 采用人脸识别技术从海量信息中寻找犯罪嫌疑人;交互式机器人通过人脸识 别技术判断用户的心情…… 先介绍一种常用的人脸识别方法:第一步,确定人脸的位置;第二步, 对人脸做一些技术处理;第三步,提取人脸的细节特征。请建立数学模型, 解决下列三个问题:
(1)建立人脸位置判断的数学模型,判断人脸在照片中的大致位置,并在 图 1 和图 2 中用你设计的模型“框出”人脸的大致位置。
(2)在问题(1)的基础上,建立人脸精确识别的数学模型,判断图 2 中 各个人物的脸型、鼻型、眼型、唇形等。(提示:如果你在 DIY 过程中遇到了困 难,不妨降低要求,比如说鼻型可以分为“大鼻子”和“小鼻子”。)
(3)在问题(2)的基础上,建立人脸匹配的数学模型,判断图 2、图 3 中是否有人物与图 1 的人物是同一人,如果有,请在图片中框出具体是哪个人 物与图 1 的人物一样。
具体附件参见:http://www.saikr.com/vse/35651
问题一
要识别人脸,首先就要定位人脸,问题一就是这么回事。在图像处理中,要把脸部的像素和其他的像素区分开来,这是个分割问题,找阈值是关键。
查阅文献,人脸的肤色经典模型是Ycbcr色彩空间聚类模型,大致思路就是将RGB图片转换到为Ycbcr色彩空间里,分析人脸的聚类特征,从而识别出人脸。以附件一为例,转换后的情况如下:
之后就可以分析脸有什么特征了,说白了就是脸部的像素值大致在什么范围,为此我把易烊千玺的头“砍下来”了:
因为这张图大部分面积是脸部,分析这张帅脸的直方图可以发现脸部肤色的像素范围:
可以看到在Cb纬度上,脸大致分布在110左右,在Cr上集中在150左右。可以设定阈值范围了,实际操作中阈值是一个不断微调的过程,不同阈值会有不同的结果,有好有坏,不过题目中说的是“人脸的大致范围”,那我们就知道出题人的意思了:就是说阈值不用太精细了,我们也做不到绝对的精确分割。
划定阈值之后,用“与”操作就可以得到二值图了,此时的二值图是非常粗糙的:
粗糙的图有很多不连续的点,那我们必须加工一下,让脸的信息更突出,最好是一整块白色连通域表示脸,其他黑色区域不是脸。首先是开闭操作填补缝隙去除毛刺:
很好,最后的图至少没有不连续的点了,都变成一个个区域了。可以看到脸里面还有一块黑色,太丑了要抹掉,就用填充操作吧:
得到两个连通域了,左下角的手的肤色有影响,去掉就好了,连通域操作函数计算两个连通域的面积,把面积小的去掉即可:
这下就剩一张帅脸了,再用连通域操作函数求得包含连通域的最小矩形,最后在原图上画出这个矩形就ok了,连通域的一系列操作函数可以参考:https://blog.csdn.net/zhu_hongji/article/details/78703161
第一问就这么搞定了?附件2和3都是多人脸识别问题,场景更复杂,人脸更多,识别效果必定比不上单一人脸,代码也需要微调一下,根据实际选择各种参数,我们的模型只有在附件3中识别的时候有点瑕疵,不过可以写在模型改进里嘛。附件二的识别情况如下:
附件3最终定位了十一张脸,最下面那个连通域始终去除不了,不过有瑕疵在建模中是正常的:
问题一matlab代码如下:
%--------首先完成RGB空间到Ycbcr空间的转换-----------
I=imread('附件_图1.jpg');
I=imresize(I,[400 300],'nearest');
I_ycbcr=rgb2ycbcr(I);
figure(1);
subplot(121),imshow(I),title('RGB空间');
subplot(122),imshow(I_ycbcr),title('Ycbcr空间');
%将脸裁剪出来,分析肤色在cb,cr的分布情况
%-------------------------------------------------
I_2=imread('face_1.png');
I_2=rgb2ycbcr(I_2);
y=I_2(:,:,1);
cb=I_2(:,:,2);
cr=I_2(:,:,3);
figure(2);
subplot(121),imhist(cb);title('Cb分布情况');
subplot(122),imhist(cr);title('Cr分布情况');
%发现Cb大致分布在115左右,Cr大致分布在130左右
%--------------------------------------------------
I_3=(I_ycbcr(:,:,2)>=110)&(I_ycbcr(:,:,2)<=122);
figure;
subplot(121),imshow(I_3),title('Cb提取情况');
I_4=(I_ycbcr(:,:,3)>=140)&(I_ycbcr(:,:,3)<=155);
subplot(122),imshow(I_4),title('Cr提取情况');
I_5=I_4&I_3;
figure;
imshow(I_5);title('粗略二值图')
%--得到的图有不连续点,可通过膨胀腐蚀(开闭运算)去除毛刺--
SE=strel('square',7);
I_5=imclose(I_5,SE); %首先,闭运算填补缝隙
figure;
subplot(121),imshow(I_5),title('闭运算');
se=strel('disk',6)
I_6=imopen(I_5,SE); %然后开运算
subplot(122),imshow(I_6),title('开运算');
%--------------下面填充处理形成连通域---------------------
I_6=imfill(I_6,'holes');
figure;
imshow(I_6),title('填充处理');
%-------------------------------------------------------
%--------------接下来连通域处理(去除左下角手的影响)-----
[L,num]=bwlabel(I_6);%L为标注矩阵
s=regionprops(L,'Area');
%算出两个连通区域面积信息,一个为371,一个为4582,设定阈值372删除小的连通域即可
BW=bwareaopen(I_6,372);%该函数删除小于372的连通域
figure;
imshow(BW),title('最终脸部情况');
%----------------------------------------------------------
%----------最后把包含该连通域的矩形画出来即可,注意要在原图上画
s2=regionprops(BW,'BoundingBox');%该函数获取包含连通域的最小矩形
location=s2.BoundingBox;
figure;
imshow(I),title('人脸定位');
hold on
rectangle('Position',location,'LineWidth',2,'Edgecolor','g');
%----至于图二图三,多人脸识别问题需要相应调整代码--------------
问题二,三稍作修改即可,附件2如下:
%--------首先完成RGB空间到Ycbcr空间的转换-----------
I=imread('附件_图2.jpg');
I=imresize(I,[400 300],'nearest');
I_ycbcr=rgb2ycbcr(I);
figure(1);
subplot(121),imshow(I),title('RGB空间');
subplot(122),imshow(I_ycbcr),title('Ycbcr空间');
%--------------------------------------------------
I_3=(I_ycbcr(:,:,2)>=110)&(I_ycbcr(:,:,2)<=122);
figure;
subplot(121),imshow(I_3),title('Cb提取情况');
I_4=(I_ycbcr(:,:,3)>=140)&(I_ycbcr(:,:,3)<=155);
subplot(122),imshow(I_4),title('Cr提取情况');
I_5=I_4&I_3;
figure;
imshow(I_5);title('粗略二值图')
%--得到的图有不连续点,可通过膨胀腐蚀(开闭运算)去除毛刺--
SE=strel('square',7);
I_5=imclose(I_5,SE); %首先,闭运算填补缝隙
figure;
subplot(121),imshow(I_5),title('闭运算');
se=strel('disk',6)
I_6=imopen(I_5,SE); %然后开运算
subplot(122),imshow(I_6),title('开运算');
%--------------下面填充处理形成连通域---------------------
I_6=imfill(I_6,'holes');
figure;
imshow(I_6),title('填充处理');
%-------------------------------------------------------
%--------------接下来连通域处理(去除左下角手的影响)-----
[L,num]=bwlabel(I_6);%L为标注矩阵
s=regionprops(L,'Area');
%三个最大的连通域就是脸部,分别为1774,1830,1855
BW=bwareaopen(I_6,1773);%该函数删除小于1774的连通域
figure;
imshow(BW),title('最终脸部情况');
%----------------------------------------------------------
%----------最后把包含该连通域的矩形画出来即可(三个),注意要在原图上画
s2=regionprops(BW,'BoundingBox');%该函数获取包含连通域的最小矩形
location_1=s2(1).BoundingBox;
location_2=s2(2).BoundingBox;
location_3=s2(3).BoundingBox;%三个矩形信息
figure;
imshow(I),title('人脸定位');
hold on
rectangle('Position',location_1,'LineWidth',2,'Edgecolor','g');
hold on
rectangle('Position',location_2,'LineWidth',2,'Edgecolor','g');
hold on
rectangle('Position',location_3,'LineWidth',2,'Edgecolor','g');
附件3代码:
%--------首先完成RGB空间到Ycbcr空间的转换-----------
I=imread('附件_图3.jpg');
I=imresize(I,[400 300],'nearest');
I_ycbcr=rgb2ycbcr(I);
figure(1);
subplot(121),imshow(I),title('RGB空间');
subplot(122),imshow(I_ycbcr),title('Ycbcr空间');
%--------------------------------------------------
I_3=(I_ycbcr(:,:,2)>=115)&(I_ycbcr(:,:,2)<=125);
figure;
subplot(121),imshow(I_3),title('Cb提取情况');
I_4=(I_ycbcr(:,:,3)>=135)&(I_ycbcr(:,:,3)<=150);
subplot(122),imshow(I_4),title('Cr提取情况');
I_5=I_4&I_3;
figure;
imshow(I_5);title('粗略二值图')
%--得到的图有不连续点,可通过膨胀腐蚀(开闭运算)去除毛刺--
SE=strel('square',4);
I_5=imclose(I_5,SE); %首先,闭运算填补缝隙
figure;
subplot(121),imshow(I_5),title('闭运算');
se=strel('disk',4)
I_6=imopen(I_5,SE); %然后开运算
subplot(122),imshow(I_6),title('开运算');
%--------------下面填充处理形成连通域---------------------
I_6=imfill(I_6,'holes');
figure;
imshow(I_6),title('填充处理');
%-------------------------------------------------------
%--------------接下来连通域处理(去除左下角手的影响)-----
[L,num]=bwlabel(I_6);%L为标注矩阵
s=regionprops(L,'Area');
BW=bwareaopen(I_6,600);%该函数删除小于600的连通域
figure;
imshow(BW),title('最终脸部情况');
%----------------------------------------------------------
%----------最后把包含该连通域的矩形画出来即可,注意要在原图上画
s2=regionprops(BW,'BoundingBox');%该函数获取包含连通域的最小矩形
figure;
imshow(I),title('人脸定位');
%------最终识别出11个连通域,正确应该是10张脸
for i=1:1:11
rectangle('Position',s2(i).BoundingBox,'LineWidth',2,'Edgecolor','g');
hold on
end
%------第一问解决------------------------------
至此第一问圆满解决。插个分割线以后再更(以我拖沓的作风也许不会再更哈哈哈)