内容提要
- 项目分析
- 预备知识
- 项目实战
一、项目分析
1、提出问题
随着人民生活水平的提高和手机照相功能的日趋完美,我们不经意中拍摄了很多值得回忆的时刻,一场说走就走的旅行途中也记录下许多令人心动的瞬间,不知不觉之中,我们身边保存了大量的生活相片。
然而,每当你想重温你或者他的系列照片时,或者想分享一张你特别满意的靓照,从众多的照片中一遍遍翻找这些照片的确是一件费时费力的事情。
既然AI无时不在我们身边,能否借助AI的人脸识别技术来帮助我自动整理出我想要的照片,实现照片的智能搜索呢?答案无疑是肯定的。
下面,我们就利用人脸识别技术和OpenCV工具,对相册中的照片进行自动挑选以解决上述问题。
2、解决方法
帮助人们从相册中找出指定人物的系列照片,对于人工操作而言,并不是一件困难的事情,但整理的效率可能不尽人意,毕竟手动翻阅每张照片是个耗时费力的事。
让计算机替代人来完成这个事,难点在于如何从被检照片中识别与目标人脸高度相似的人脸,如果被检照片中有此人,说明该照片就是你想要的那一张,否则,该照片被忽视。
因此,一种可行的方案是:首先训练计算机认识不同式样的同一系列人脸,让它知道其实这些照片上的人物是同为一个人,从而得到目标人脸训练模型。
其次,遍历相册中的每张照片,检测出该照片上所有的人脸,提取人脸特征值,然后用目标人脸训练模型依次对人脸特征值进行预测比对,如果两者之间只要有一次高度匹配,就保留该照片,立即进入下一张照片的搜索,如果均不匹配,则忽视该照片,进行下一张搜索,直至搜索完所有的照片。
最后,得到的所有保留照片就是智能搜索的结果,至此,整个智能搜索照片过程结束。
问题的解决方案如下图所示。
二、预备知识
利用OpenCV来智能搜索相片,有两个重要的环节:
一是人脸区域的检测,这要用到前面提到的人脸检测器;
二是基于人脸区域数据的人脸识别,这要用到人脸识别模型。
下面分别来了解OpenCV中人类检测器和人脸识别模型的使用。
1、人脸检测器
我们可以从网络资源上下载别人训练好的人脸分类器,也可以自己训练。在此我们使用表中默认的级联分类器来检测照片中的人脸。
案例1:检测照片中的所有人脸,并用矩形框出人脸区域。
文件case1.ipynb代码如下:
1 import cv2
2 import numpy as np
3 faceCascade=cv2.CascadeClassifier('data/haarcascade_frontalface_default.xml')
4 img=cv2.imread('data/pic1.JPG')
5 gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
6 faces=faceCascade.detectMultiScale(gray,1.3,5)
7 for (x,y,w,h)in faces:
8 cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,0),1)
9 cv2.imshow('pic',img)
10 cv2.waitKey(0)
11 cv2.destroyAllWindows()
为方便调用默认的级联人脸分类模型,将文件haarcascade_frontalface_default.xml拷贝到源程序所在位置的data文件夹下,通过代码行3来构建人脸分类器faceCascade。
代码行4读取照片文件pic1.jpg,在代码行5将其转换成灰度图像。
代码行6对灰度图像gray按搜索窗口比例系数为1.3、相邻矩形最小个数为5的扫描方式检测人脸,并返回检测到的人脸矩形框向量数组。
代码行7-8遍历该向量数组,在图像img中人脸的相应位置绘制出一个个的矩形框。
代码行9显示绘制有人脸矩形框的照片。
代码行10一直等待用户的按键响应,按任意键继续,并通过代码行11关闭所有的窗口。
程序的运行效果如下:
由上可以看出,照片中的两个人脸被成功检测出来,人脸的位置及大小数据如下所示:
2、人脸识别算法
目前OpenCV支持:特征脸EigenFace、线性判别分析脸FisherFace与直方图脸LBPHFace三种人脸识别方法。
OpenCV的扩展包opencv-contrib-python提供了相应的函数以方便构建上述三种人脸识别方法的模型,因此在使用人脸识别模型前,要执行以下命令安装OpenCV扩展包。
pip3 install opencv-contrib-python
扩展包提供的模型函数如下表所示:
由于LBPHFace算法不会受到光照、缩放、旋转和平移的影响,且执行性能高,通用性较好,是OpenCV中首选的人脸识别方案。
案例2:识别指定照片中的人是谁。
编写如下代码(case2.ipynb),以识别上图中的照片who.jpg人物是huangshuai还是limu
1 import cv2
2 import os
3 import numpy as np
4 images=[]
5 labels=[]
6 whoPath=''
7 name2num={'huangshuai':1,'limu':2}
8 num2name={1:'huangshuai',2:'limu'}
9 faceCascade=cv2.CascadeClassifier('data/haarcascade_frontalface_default.xml')
10 for root,dirs,filenames in os.walk('data\\case8-2\\'):
11 for filename in filenames:
12 if filename!='who.jpg':
13 filePath=os.path.join(root,filename)
14 img=cv2.imread(filePath,0)
15 faces=faceCascade.detectMultiScale(img,1.3,3)
16 name=filePath.split('\\')[-2]
17 for (x,y,w,h) in faces:
18 images.append(img[y:y+h,x:x+w])
19 labels.append(name2num[name])
20 else:
21 whoPath=os.path.join(root,filename)
22 faceRecognizer=cv2.face.LBPHFaceRecognizer_create()
23 faceRecognizer.train(images,np.array(labels))
24 whoimg=cv2.imread(whoPath,0)
25 whoFace=faceCascade.detectMultiScale(whoimg,1.3,3)
26 for(x,y,w,h) in whoFace:
27 pred_index,conf_score=faceRecognizer.predict(whoimg[y:y+h,x:x+w])
28 print('待识别照片中的人是:',num2name[pred_index])
29 print('置信度评分=',conf_score)
代码行4-5分别用列表images、labels保存用于训练人脸识别模型的人脸数据和标签数据。
在代码行7-8定义人物“huangshuai、limu”对应的标签号为“1、2”。
代码行9构建一个人脸分类器faceCascade。
代码行10-21对指定目录data\case8-2\下的文件夹及文件进行遍历,如果文件不是待识别照片who.jpg,则将它们作为训练集。
在代码行15检测出人脸,并在代码行18-19将人脸数据和标签值分别保存到列表images和labels中;若是待识别照片,则在代码行21保存其路径。
代码行22构建一个LBPHFace类型的人脸识别模型,并在代码行23利用人脸数据集images和标签集labels对该模型进行训练。
代码行26-29对照片who.jpg中的人脸进行识别。
在代码行27用训练好的模型对该照片的面部进行预测,返回人物标签值pred_index和置信度评分conf_score,并在代码行28-29分别打印出识别的人物姓名和置信度评分。
程序的运行效果如下所示:
需要指出的是,对人脸识别模型的训练,训练集越多,预测效果越好。
模型一旦训练好后,可以以XML文件的形式将其保存起来,以便下次直接读取调用,以避免每次预测前都要训练一次的麻烦。
三、项目实战
3.1 训练目标人脸识别模型
文件夹persons中有目标人物的几张照片,用照片中的人脸集去训练人脸识别模型,让模型“认识”该人脸,并保存该模型,以便后续利用该模型去“辨认”照片集中的面相。
新建文件task1.ipynb,根据任务目标,按照以下步骤和操作,完成任务一。
任务目标:
提取照片中的人脸数据构成训练集,使用训练集对LBPHFace人脸模型进行训练,将训练好的模型保存起来。
完成步骤:
(1)构建一个人脸检测器
(2)生成目标人脸数据的训练集
(3)训练人脸识别模型
1、构建一个人脸检测器
为方便代码重用,在文件task1.ipynb中定义函数get_face_cascade,以构建一个人脸检测器,代码如下。
1 import cv2
2 import os
3 import numpy as np
4 def get_face_cascade(model_file):
5 faceCascade=cv2.CascadeClassifier(model_file)
#利用cv2中已训练好的人脸检测文件model_file来构建一个人脸检测器faceCascade。
6 return faceCascade
2、生成目标人脸数据训练集
根据前面的解决方案,需要获取目标对象的人脸数据和标签值,作为人脸识别模型的训练集。
编写代码如下,得到训练集。
1 def get_faces_trains(file_path,model_file):
2 images=[]
3 labels=[]
4 faceCascade=get_face_cascade(model_file)
5 for file in os.listdir(file_path):
6 filePath=os.path.join(file_path,file)
7 img=cv2.imread(filePath,0)
8 faces=faceCascade.detectMultiScale(img,1.3,3)
9 x,y,w,h=faces[0]
10 images.append(img[y:y+h,x:x+w])
11 labels.append(1)
12 return images,labels
13 images,labels=get_faces_trains('data/persons/','data/haarcascade_frontalface_default.xml')
代码行2-3定义的变量分别保存人脸数据和人脸标签。
代码行5-11遍历文件目录file_path下所有的目标人物照片文件,在代码行7读入灰度图。
在代码行8利用人脸分类器对灰度图检测人脸,然后在代码行10-11分别保存人脸数据和标签值,因为已知训练照片属于同一个人,所以标签值相同。
代码行13利用定义好的函数get_faces_trains来获取data/persons目录下目标人脸的训练数据。
3、训练人脸识别模型
有了步骤2的训练数据,就可以对LBPHFace模型进行训练,代码如下:
1 faceRecognizer=cv2.face.LBPHFaceRecognizer_create()
2 faceRecognizer.train(images,np.array(labels))
3 faceRecognizer.save('data/models/my_LBPHfaceRec.xml')
因为标签集labels是列表类型,需要转换成向量类型,然后在代码行2对人脸识别模型进行训练,并在代码行3将训练好的模型保存起来,以备后续随时调用。
至此,我们就得到了一个可用于搜索照片的人脸识别模型。
3.2 找到与某个用户最相似的n个用户
任务一已经按照指定的人物照片训练好了人脸识别模型,那么下一步我们就可以利用该模型,去照片集中帮我们找到想要的照片。
根据任务目标,按照以下步骤和操作,完成任务二。
任务目标:
搜索照片集中与目标人脸高度相似的照片,并显示搜索结果。
完成步骤:
(1)加载训练好的模型
(2)搜索照片集中要找的照片
1、加载训练好的模型
初始化人脸识别方法,读取训练好的模型文件,将其作为预测照片的人脸识别器。代码如下:
1 faceRecognizer1=cv2.face.LBPHFaceRecognizer_create()
2 faceRecognizer1.read('data/models/my_LBPHfaceRec.xml')
2、搜索照片集中要找的照片
有了人脸识别器faceRecognizer1,就定义如下方法search_photos,用它去寻找与目标人脸相似的照片,代码如下:
1 def search_photos(file_path,model_file):
2 faceCascade=get_face_cascade(model_file)
3 i=0
4 for file in os.listdir(file_path):
5 filePath=os.path.join(file_path,file)
6 pred_img=cv2.imread(filePath)
7 gray=cv2.cvtColor(pred_img,cv2.COLOR_BGR2GRAY)
8 faces=faceCascade.detectMultiScale(gray,1.3,3)
9 x,y,w,h=faces[0]
10 pred_index,conf_score=faceRecognizer1.predict(gray[y:y+h,x:x+w])
11 if conf_score<50:
12 i+=1
13 cv2.putText(pred_img,str(i),(x+int(w/2),y+int(h/2)),
cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),3)
14 cv2.imshow('foundImage',pred_img)
15 cv2.waitKey(0)
16 cv2.destroyAllWindows()
17 search_photos('data/photos/','data/haarcascade_frontalface_default.xml')
代码行4-16是遍历目录file_path下的照片集,代码行7将读取的彩色图转换成灰度图。
代码行10用人脸识别器faceRecognizer1去预测当前人脸数据应归属于那一类、置信度如何。
其中代码行11-16是判断如果置信度分数<50,则说明当前照片与目标人脸高度相似,通过代码行13在人脸中间部位写上序号i,然后通过代码行14显示该图像。
代码行17是调用定义的函数search_photos,完成照片的搜索任务。
上述代码的运行效果如下图所示:
可以看出,找出的6张照片上的人物与原目标人脸是一个人,说明本次智能搜索是有效的。
当然,在实际应用过程中,不排除漏搜和多搜的情况,这时候就要考虑通过调参、甚至更改人脸检测器和识别模型来改善搜索效果。
更多精彩内容请持续关注本站!