#学习笔记 #OpenCV #人脸识别 #Python
开始
开始识别人脸了,记得准备几个有人脸的图
识别人脸
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import cv2 as cv
if __name__ == '__main__': img = cv.imread('rickroll3.png') gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) face_detect = cv.CascadeClassifier('C:/Users/1/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') face = face_detect.detectMultiScale(gray, 1.01, 5, 0, (105,105), (120,120)) for x, y, w, h in face: cv.rectangle(img, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2) cv.imshow('result', img) while True: if ord('q') == cv.waitKey(0): break cv.destroyAllWindows() print(face)
|
里面提到一个 Classifier 分类器,这里选择用一个现成的分类器
下载 OpenCV 的文件
官网
下载 Windows 版本,双击解压操作
注意 OpenCV 这个解压后路径不要有中文,保证全英文路径
打开 opencv\sources\data\haarcascades
寻找其中的 haarcascade_frontalface_alt2.xml
填入
1
| cv.CascadeClassifier('C:/Users/1/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
|
调用到这个分类器
注意:Windows 用户请注意,Windows 的路径是 \ 斜杠,而我们需要的是 / 斜杠,记得全改过来(或者考虑拿 Linux 做这个?)
具体识别流程
具体的人脸识别流程:
- 读取图像(或者是视频)
- 将图像转化为灰度图像
- 设置分类器
- 分类器识别人脸的信息
- 人脸位置上画矩形
- 显示图片
获得人脸位置
1 2
| face = face_detect.detectMultiScale(gray, 1.01, 5, 0, (105,105), (120,120))
|
gray 图像,1,01 每次遍历的缩放倍数,5 检测几次再确定,0 默认不管,最小有多小,最大有多大
返回 face 是所有人脸的位置以及方框的长宽,即 x,y,w,h
的值
其实可以试着拿 print (face) 打印出来看看里面都是啥~,都是数值的
1 2
| for x, y, w, h in face: cv.rectangle(img, (x, y), (x + w, y + h), color=(0, 0, 255), thickness=2)
|
遍历所有人脸的位置信息,画方框,两个点分别是 (x, y)
和 (x + w, y + h)
,读取到几个脸就画几个方框
记得是在灰度图像里找坐标,在原图里标记矩形
执行效果如下:

给诈骗犯锁个头~
训练
下面就是给每个人头做一个标记了
比如看见 Rick 就在图片上显示 Rick,看到昊京就显示昊京
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import cv2 as cv import os from PIL import Image import numpy as np def getImageAndLables(path): faceSample = [] ids = [] imagePath = [os.path.join(path, filename) for filename in os.listdir(path)] face_detector = cv.CascadeClassifier('C:/Users/1/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') for singlePath in imagePath: PIL_img = Image.open(singlePath).convert('L') img_np = np.array(PIL_img, 'uint8') faces = face_detector.detectMultiScale(img_np) id = int(os.path.split(singlePath)[1].split('.')[0]) for x,y,w,h in faces: ids.append(id) faceSample.append(img_np[y:y+h, x:x+h]) print('id: ', id) print('face: ', faces) return faceSample, ids if __name__ == '__main__': path = './Images/' faces, ids = getImageAndLables(path) recognizer = cv.face.LBPHFaceRecognizer_create() recognizer.train(faces, np.array(ids)) recognizer.write('trainer/trainer.yml')
|
工作流程
- 将人脸的图片放进一个文件夹里,这里放的是
'./Images/'
- 把每一个图片的脸都识别一下,放进一个列表里,再识别每个图片的 ID 也放到一个列表里
- 加载识别器进行训练
- 把识别器的文件保存
遍历文件
这里创建了三个列表
1 2 3 4 5 6
| faceSample = []
ids = []
imagePath = [os.path.join(path, filename) for filename in os.listdir(path)]
|
faceSample = []
放置人脸的数据,也就是上一节里面识别人脸返回的那个 face
ids = []
放置每个人脸的 id,用来识别谁是什么样的脸
imagePath = [os.path.join(path, filename) for filename in os.listdir(path)]
放置每个图片的路径信息,方便读取
其中:
os.path.join(path, filename)
用来拼接文件的路径
- path 就是文件名之前的一大长串
- filename 就是文件名
for filename in os.listdir(path)
就是遍历 path 这个路径的文件夹里每一个文件的文件名
os.listdir(path)
就是显示路径当中的所有文件名,返回一个列表
- 利用 for 循环遍历这个列表
关于 PIL
为了把图像灰度化处理需要用到 PIL
但是都什么年代了还在用传统 PIL,现在都开始用 pillow,想睡觉来枕头,利用之前说的安装 pillow 这个包,import 一个叫 Image 的
1
| PIL_img = Image.open(singlePath).convert('L')
|
singlePath
是单个文件的路径,打开文件并转换,用 L 模式进行
PIL 有九种模式分别为 1 L P RGB RGBA CMYK YCbCr I F
光灰度处理还不够,还需要转化为 OpenCV 能看懂的格式
1 2
| img_np = np.array(PIL_img, 'uint8')
|
将 PIL_img 转化为 uint8 格式
uint8 格式在 OpenCV 还挺常用的~
识别人脸存入列表
1 2 3 4 5 6 7 8 9 10
| faces = face_detector.detectMultiScale(img_np)
id = int(os.path.split(singlePath)[1].split('.')[0])
for x,y,w,h in faces: ids.append(id) faceSample.append(img_np[y:y+h, x:x+h]) print('id: ', id) print('face: ', faces)
|
获取人脸 faces
没必要再说
我们每一个需要训练的图片都有这样一种命名规则,那就是 ID.姓名序号.png
id = int(os.path.split(singlePath)[1].split('.')[0])
获取单个 id
其中:
int(os.path.split(singlePath)[1]
是之前 os.path.join(path, filename)
相反的操作
- 第一个
split
是分离文件夹的路径和文件名的,分离为两部分,[0]就是路径,同理[1]就是文件名,[2]就是……不存在的,会报错
- 第二个
.split('.')[0]
是分离文件名,按照 '.'
分离,以 ID.姓名序号.png
文件为例, 总共能分三部分
- 第一部分是 ID
- 第二部分是姓名序号
- 第三部分就是剩下的 png
1 2
| print('id: ', id) print('face: ', faces)
|
控制台打印 id 和面部信息
所有信息准备好之后 return faceSample, ids
返回人脸和 id 的列表,进行训练。
训练开始
1 2 3 4 5 6
| recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.train(faces, np.array(ids))
recognizer.write('trainer/trainer.yml')
|
进行识别器的训练,需要注意的点是 id 的列表需要更改为 array 才可以正常进行
保存到 ./trainer/
文件夹当中命名为 trainer.yml
进行识别
下面就是把以上的内容进行整合
首先确立一下我们要识别的人脸,训练的人脸

- Rick——国际诈骗犯
- HaoJing——战狠的主角昊京
- WuJing——战狼的主角吴京
训练好的保存为 trainer.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import cv2 as cv import os if __name__ == '__main__': name = ['Rick Astley', 'Hao Jing', 'Wu Jing'] recognizer = cv.face.LBPHFaceRecognizer_create() recognizer.read('./trainer/trainer.yml') originalImg = cv.imread('PinTu2.png') grayImg = cv.cvtColor(originalImg, cv.COLOR_BGR2GRAY) face_detector = cv.CascadeClassifier('C:/Users/1/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml') face = face_detector.detectMultiScale(grayImg, 1.1, 5, cv.CASCADE_SCALE_IMAGE, (80, 80)) for x,y,w,h in face: cv.rectangle(originalImg, (x, y),(x+w,y+h), color=(0,255,0),thickness=2) ids, confidence = recognizer.predict(grayImg[y:y+h,x:x+w]) if confidence > 80: cv.putText(originalImg, 'unknown', (x+10,y-10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,255), 1) else: cv.putText(originalImg, name[ids-1], (x+10,y-10), cv.FONT_HERSHEY_SIMPLEX, 0.75, (0,0,255), 2) cv.imshow('result', originalImg) cv.waitKey(0) cv.destroyAllWindows()
|
总体流程
- 创建名称列表
- 创建 recognizer,也就是之前训练好的那个
- 导入图像并转化为灰度
- 加载 Classifier,寻找人脸为 face
- 遍历找到的人脸 face,为每一个人脸画框框
- 用之前设置好的 recognizer,和找到的人脸比对得出 id 和 confidence
- 判断 confidence
- 如果 confidence 大于 80,在人脸位置的 (x+10, y-10) 写上 unknown
- 否则拿着识别出的 id 寻找列表 name 里的名字,把名字给写上去
- 显示图像
结果:

总结
OpenCV 速通人脸识别这件事情结束了吗?还没呢,这只算入门,还有更进阶的内容需要学习,只算是做出个东西而已~
- 开摄像头实时的人脸识别
- 识别物体而不是人脸该怎么办
- 识别人脸总出毛病该怎么优化
等等都需要进行考虑