2.1. 项目简介
人脸识别是基于人的脸部特征信息进行身份识别的一种图像识别技术。使用0PenCV 进行人脸识别的过程如下。
(1) 针对每个识别对象收集大量的人脸图傣作为样本。
(2) 将样本送给识别器进行学习,在训练完成之后得到一个人脸数据模型。
(3) 利用这个模型对新的人脸图像进行身份识别,预测人脸的所有者。
简单地说就是收集训练数据、训练识别器、识别目标对象3个步骤,其工作过程如原书图33_1所示。
使用OpenCV提供的人脸检测分类器,能够做到检测图像中的人脸并定位目标区域。如果想识别图像中的人脸是谁的,还需要训练专门的人脸识别器。这也不难,功能强大的0penCV提供简单易用的人脸识别接口,编程者不需要深人了解人脸识别理论知识,就可以轻松编写出人脸识别程序。
本节将介绍对“钢铁侠”和“蜘蛛侠“进行人脸识别。
2.2. 准备工作
- 安装依赖模块 opencv-contrib
opencv-contrib是OpenCV的扩展模块,在进行人脸识别时要用到 OpenCv 的识别器,有他提供。在python中,需要安装opencv-contrib-python库。
在julia中,用Conda安装opencv-contrib时会提示该包不存在,其实在julia中用Conda安装OpenCV库时,已经包含了这个扩展包。
2.准备项目目录和数据
在本地磁盘上建立一个名为“face-recogniz”的文件夹作为项目目录,用于存放本项目的数据、源程序、图像等文件,然后从原书“资源包/第 33 课”文件夹中把两个文件夹(testing和training) 以及一个人脸特征文件 (lbpcascade_frontalface_improved.xml) 复制到 “face-recogniz”文件夹中。
training 文件夹中提供了用于训练识别器使用的图像文件,testing文件夹中提供了进行人脸识别测试时使用的图像文件。
2.3. 收集训练数据
在这个项目中,巳经准备好了用于训练人脸识别器的人脸图像文件。也可以通过互联网搜索一些自己感兴趣的人脸图像作为训练数据,然后将其存放在 testing 文件夹中的一个子文件夹内即可。每一个人的人脸图像文件放在一个单独的文件夹中。
此外,在使用摄像头的人脸识别项目中,可 以通过摄像头采集人脸图作为训练数据。
2.4. 训练识别器
在收集人脸图像的工作完成后,就可以开始编写程序训练人脸识别器。如原书图 33-2 所示,这是使用0PEnCV 的 FaceRecognizer 进行人脸识别器的训练并生成数据模型的过程。
- 编程实现:
新建一个空白源文件,以face_training.jl作为文件名保存到“face-recogniz”项目文件夹中 ,然后编写程序进行人脸识别器的训练,具体过程如下。
(1) 导人cv2、numpy和os模块。
using PyCall cv2=pyimport("cv2") numpy=pyimport("numpy") os=pyimport("os")
说明:在这个程序中需要使用python的os模块读取磁盘目录和文件列表。事实上julia中内置函数readdir()读取磁盘目录和文件也极为方便,这里只是偷懒,直接采用原来python的代码。
(2) 创建训练识别器时使用的标签(整数 id 值)列表和人脸图像列表,及创建人脸检测器和人脸识别器的实。
#创建人脸检测器和识别器 labels, faces = [], [] file = "lbpcascade_frontalface_improved.xml" face_cascade = cv2.CascadeClassifier(file) recognizer = cv2.face.LBPHFaceRecognizer_create()
(3) 编写detect_face()函数, 用于从图像中检测人脸并返回人脸区域。
function detect_face(image) #'''检测人脸区域''' gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.2, 5, minSize=(20, 20)) if (length(faces) == 0) return nothing end (x, y, w, h) = faces[1,:] return gray[y:y+w, x:x+h] end
说明: 调用 detectMultiScale()方法能够检测并返回图像的多个人脸区域,这里只使用其中的一个作为detect_face() 函数的返回值。原书python代码是这样的。
(x, y, w, h) = faces[0]
但是julia的数组是列主数组,如果用faces[1]只能返回数组的第一个元素,因此这里改为这样:
(x, y, w, h) = faces[1,:]
(4) 编写 read_face()函数于读取训练识别器使用的图像文件,并将检测出的人脸图像数据和id加人到faces列表和labels列表中 。
1 function read_face(label, images_path) 2 #'''读取人脸图像''' 3 println("trainning:", label, images_path) 4 files = os.listdir(images_path) 5 for file in files 6 if startswith(file,'.') 7 continue 8 end 9 #从文件中读取图像 10 image = cv2.imread(images_path * "/" * file) 11 #检测图像中的人脸区域 12 face = detect_face(image) 13 14 if face !==nothing 15 ce = cv2.resize(face, (256, 256)) 16 #faces.append(face) 17 #labels.append(label) 18 push!(faces,face) 19 push!(labels,label) 20 end 21 end 22 end
说明: 在 faces 和 labels 这两个列表中的元素一一对应 ,即人脸图像和 id要匹配。
(5) 训练人脸识别器,生成人脸特 征模型数据文件。这里使用蜘蛛侠和钢铁侠的图像进行训练。
#读取人脸图像 read_face(1, "training/spider_man/") read_face(2, "training/iron_man/") #训练人脸识别器 recognizer.train(faces, numpy.array(labels)) #保存人脸特征数据 recognizer.save("trainner.yml")
说明:人脸识别器的train()将读取的人脸图像生成特征数据,第1个参数是图像列表,第2个参数是标签(整数的 id 值)数组,需要用 numpy.array()方法将列表(List)类型转换为 numpy 的数纽。 人脸识别器的save()方法将生成的人脸特征模型数据保存到一个文件中。
至此训练人脸识别器的程序编写完毕。运行程序,将会读取 training 文件夹中的人脸图像,然后调用人脸识别器的 train()方法进行训练,最终在项 目目录下生成一个人脸特征模型的数据文件trainner.yml。
2.5. 人脸检测与识别
在训练好识别器之后,使用生成的人脸特征模型文件trainner.yml 就可以对testing目录下的人脸图像进行测试,看看是否能够识别出图像中的人脸是谁的。如原书图33-3所示,这是使用训练好的人脸识别器对图像中的人脸进行身份识别的过程。
- 编程实现
新建一个空白源文件,以face_detection.jl作为文件名保存到“face-recogniz”项目文件夹中 ,然后编写程序对测试图像进行人脸识别,具体过程如下。
(1) 导人CV2 库。
cv2=pyimport("cv2")
(2) 创建一个元组,存放人脸所有者的名字。 其中,第一个元素不使用。
names = ("None", "Spider Man", "Iron Man")
(3) 创建人脸检测器和识别。
file = "lbpcascade_frontalface_improved.xml" face_cascade = cv2.CascadeClassifier(file) recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read("trainner.yml")
说明:通过人脸识别器的read()方法,读取人脸特征模型数据文件 trainner. yml。
(4) 从文件中读取用于测试的人脸图像
#读取测试的人脸图像 test_img = cv2.imread("testing/test1.jpg") gray_img = cv2.cvtColor(test_img, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray_img, 1.2, 5)
(5) 在循环结构中对检测出的一组人脸图像进行预测。取出人脸图像改变大小。
#Julia数组是列主数组,而cv需要行主数组。 #反转维度,然后使用PyReverseDims数组 rimg = permutedims(test_img, ndims(test_img):-1:1) pyimg = PyReverseDims(rimg) #对检测出的每一个人脸图像进行测试 for i in 1:size(faces,1) (x,y,w,h)=faces[i,:] face = gray_img[y:y+w, x:x+h] face = cv2.resize(face, (256, 256)) …… end
(6) 使用前面训练的人脸识别器预测图像中的人脸所有者。
#使用人脸识别器预测图像 label, confidence = recognizer.predict(face) confidence = 100 - confidence ……
说明:LBPHFaceRecognizer 预测产生0~100 的评分,低于50是可靠的,高于80是不可靠的。这里把评分转换一下,以符合正常的阅读习惯。
(7) 当信任度大于50时,标注出图像中的人脸所有者
#取最大值 if label > 0 && confidence > 50 cv2.rectangle(pyimg, (x, y), (x+w, y+h), (255, 0, 0), 2) text =@sprintf("%s:%d", names[label], confidence) print(text) font = cv2.FONT_HERSHEY_PLAIN cv2.putText(pyimg, text, (x, y), font, 2.5, (0, 255, 0), 2) end
(8) 所有人脸处理完毕,显示到窗口。
#显示图像并等待 cv2.namedWindow("Image", cv2.WINDOW_NORMAL) cv2.imshow("Image", pyimg) cv2.waitKey(0) cv2.destroyAllWindows()
至此,人脸识别程序编写完毕。运行程序,对同时含有蜘蛛侠和钢铁侠的图像进行预测。从结果来看,能够正确识别出蜘蛛侠和钢铁侠,如下图所示:
源码下载:https://files.cnblogs.com/files/zjzkiss/face-recogniz.zip