Python+opencv人脸识别项目
此项目的Github链接为https://github.com/gylike/python-opencv-
1.导入库文件
首先在PyCharm的Python解释器中导入以下软件包

这里使用的Python版本为3.11
1读取图片
首先先要了解如何通过opencv来读取一张图片(face1),下面代码给出了详细的说明:
1
2
3
4
5
6
7
8
9
10#导入cv模块
import cv2 as cv
#读取图片
img = cv.imread('face1.jpg')
#显示图片
cv.imshow('read_img',img)
#等待
cv.waitKey(0)
#释放内存
cv.destroyAllWindows()
2灰度转换
图像灰度变换的有以下作用:
1. 改善图像的质量,使图像能够显示更多的细节,提高图像的对比度(对比度拉伸)
2. 有选择的突出图像感兴趣的特征或者抑制图像中不需要的特征
3. 可以有效的改变图像的直方图分布,使像素的分布更为均匀
下面是将名为face1的图片进行灰度转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#导入cv模块
import cv2 as cv
#读取图片
img = cv.imread('face1.jpg')
#灰度转换
gray_img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#显示灰度
cv.imshow('gray',gray_img)
cv.imwrite('gray_face11.jpg',gray_img)
#显示图片
cv.imshow('read_img',img)
#等待
cv.waitKey(0)
#释放内存
cv.destroyAllWindows()
效果如下:


3修改尺寸
使用resize函数调整图片的尺寸
例如,将face1调整为400*400像素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#导入cv模块
import cv2 as cv
#读取图片
img = cv.imread('face1.jpg')
#修改尺寸
resize_img = cv.resize(img,dsize=(400,400))#400*400像素
#显示原图
cv.imshow('img',img)
#显示修改后的
cv.imshow('resize_img',resize_img)
#打印原图尺寸大小
print('未修改:',img.shape)
#打印修改后的尺寸大小
print('修改后:',resize_img.shape)
#等待
while True:
if ord('q') == cv.waitKey(0):
break
#释放内存
cv.destroyAllWindows()
4绘制矩形
通过像素坐标的方式在图片上绘制出一块矩形区域
设初始像素坐标为(x,y,w,h)=(100,100,100,100),则可以绘制出正方形(x,y,x+w,y+h),此图形每条边为100像素
完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#导入cv模块
import cv2 as cv
#读取图片
img = cv.imread('face1.jpg')
#坐标
x,y,w,h = 100,100,100,100
#绘制矩形
cv.rectangle(img,(x,y,x+w,y+h),color=(0,0,255),thickness=1)
#绘制圆形
cv.circle(img,center=(x+w,y+h),radius=100,color=(255,0,0),thickness=2)
#显示
cv.imshow('re_img',img)
#等待
while True:
if ord('q') == cv.waitKey(0):#按q退出程序
break
#释放内存
cv.destroyAllWindows()
效果如下:

5人脸识别
接下来就可以进行人脸识别了,使用Opencv自带的分类器haarcascade_frontalface_alt2.xml对图片进行识别人脸的存在,并用合适的矩形框将人脸框起来
主要代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#导入cv模块
import cv2 as cv
def face_detect_demo():
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) #转换为灰度
#加载分类器:做出人脸识别的关键 opencv
face_detect = cv.CascadeClassifier('D:/Develop/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')#这里是分类器的位置
face = face_detect.detectMultiScale(gray,1.01,5,0,(100,100),(1000,1000)) #gray为放置的图像 1.01为缩放倍数 5检测次数(5次都要检测到) 0 默认 (100,100)最小人脸像素 (1000,1000)最大人脸像素大小
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)
#读取图片
img = cv.imread('face1.jpg')
#检测函数
face_detect_demo()
#等待
while True:
if ord('q') == cv.waitKey(0):
break
#释放内存
cv.destroyAllWindows()
效果如下

6检测多个人脸
需要检测多个人脸时,可以使用上述代码来实现,唯一的一点不同是使用分类器默认参数,可以将face_detect.detectMultiScale(gray,1.01,5,0,(100,100),(1000,1000))改为默认参数face_detect.detectMultiScale(gray)
主要代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#导入cv模块
import cv2 as cv
def face_detect_demo():
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) #转换为灰度
#加载分类器:做出人脸识别的关键 opencv
face_detect = cv.CascadeClassifier('D:/Develop/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face = face_detect.detectMultiScale(gray) #去掉参数为使用默认配置
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)
#读取图片
img = cv.imread('face2.jpg')
#检测函数
face_detect_demo()
#等待
while True:
if ord('q') == cv.waitKey(0):
break
#释放内存
cv.destroyAllWindows()
7检测视频
当读取的为视频或者摄像头时,仍然可以用Opencv自带的分类器进行动态人脸捕捉
代码如下:
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#导入cv模块
import cv2 as cv
def face_detect_demo(img):
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) #转换为灰度
#加载分类器:做出人脸识别的关键 opencv
face_detect = cv.CascadeClassifier('D:/Develop/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face = face_detect.detectMultiScale(gray) #gray为放置的图像
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)
#读取摄像头
cap = cv.VideoCapture(0)
#cap = cv.VideoCapture('***.mp4')#读取视频
#循环
while True:
flag,frame= cap.read()
if not flag:
break
face_detect_demo(frame)
if ord('q') == cv.waitKey(0):
break
#释放内存
cv.destroyAllWindows()
#释放摄像头
cap.release()
8数据训练
将 ./data/jm/文件夹下的所有图片进行识别,生成文件名为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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49import os
import cv2
from PIL import Image
import numpy as np
def getImageAndLabels(path):
#储存人脸数据
facesSamples = []
#储存姓名数据
ids = []
#储存图片信息
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
# 加载分类器
face_detector = cv2.CascadeClassifier('D:/Develop/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
# 打印数组imagePaths
print('数据排列:', imagePaths)
# 遍历列表中的图片
for imagePath in imagePaths:
# 打开图片,灰度化 PIL有九种不同模式:1(黑白),L(灰度),P,RGB,RGBA,CMYK,YCbCr,I,F
PIL_img = Image.open(imagePath).convert('L')
# 将图像转换为数组,以黑白深浅
# PIL_img = cv2.resize(PIL_img, dsize=(400, 400))
img_numpy = np.array(PIL_img, 'uint8')
# 获取图片人脸特征
faces = face_detector.detectMultiScale(img_numpy)
# 获取每张图片的id和姓名
id = int(os.path.split(imagePath)[1].split('.')[0])
# 预防无面容照片
for x, y, w, h in faces:
ids.append(id)
facesSamples.append(img_numpy[y:y + h, x:x + w])
# 打印脸部特征和id
# print('fs:', facesSamples)
print('id:', id)
# print('fs:', facesSamples[id])
print('fs:', facesSamples)
# print('脸部例子:',facesSamples[0])
# print('身份信息:',ids[0])
return facesSamples, ids
if __name__ == '__main__':
#图片路径
path='./data/jm/'
#获取图像数组和id标签数组和姓名
faces,ids=getImageAndLabels(path)
#加载识别器
recognizer = cv2.face.LBPHFaceRecognizer_create()
#训练
recognizer.train(faces,np.array(ids))
#保存文件
recognizer.write('D:/File/python/mycodetest/opencv/trainer/trainer.yml')
生成如下图文件:

9人脸识别
将要识别训练文件trainer.yml导入,通过数据文件与摄像头检测到的人脸或视频中的人脸进行比对。如果是已存在的人脸则不会触发警报,如果是陌生人脸会触发unknown警报,并通过短信平台发送到手机
代码如下:
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86import cv2
import numpy as np
import os
# coding=utf-8
import urllib
import urllib.request
import hashlib
#加载训练数据集文件
recogizer=cv2.face.LBPHFaceRecognizer_create()
recogizer.read('D:/File/python/mycodetest/opencv/trainer/trainer.yml')
names=[]
warningtime = 0
def md5(str):
import hashlib
m = hashlib.md5()
m.update(str.encode("utf8"))
return m.hexdigest()
statusStr = {
'0': '短信发送成功',
'-1': '参数不全',
'-2': '服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间',
'30': '密码错误',
'40': '账号不存在',
'41': '余额不足',
'42': '账户已过期',
'43': 'IP地址限制',
'50': '内容含有敏感词'
}
def warning():
# 短信平台账号
smsapi = "http://api.smsbao.com/"
user = 'Orange'
# 短信平台密码
password = md5('123456789')
# 要发送的短信内容
content = '【报警】\n原因:检测到未知人员\n地点:xxx'
# 要发送短信的手机号码
phone = '13900000000'
data = urllib.parse.urlencode({'u': user, 'p': password, 'm': phone, 'c': content})
send_url = smsapi + 'sms?' + data
response = urllib.request.urlopen(send_url)
the_page = response.read().decode('utf-8')
print(statusStr[the_page])
#准备识别的图片
def face_detect_demo(img):
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度
face_detector=cv2.CascadeClassifier('D:/Develop/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
face=face_detector.detectMultiScale(gray,1.1,5,cv2.CASCADE_SCALE_IMAGE,(100,100),(300,300))
#face=face_detector.detectMultiScale(gray)
for x,y,w,h in face:
cv2.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
cv2.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=1)
# 人脸识别
ids, confidence = recogizer.predict(gray[y:y + h, x:x + w])
#print('标签id:',ids,'置信评分:', confidence)
if confidence > 80:
global warningtime
warningtime += 1
if warningtime > 100:
warning()
warningtime = 0
cv2.putText(img, 'unkonw', (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
else:
cv2.putText(img,str(names[ids-1]), (x + 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
cv2.imshow('result',img)
#print('bug:',ids)
def name():
path = './data/jm/'
#names = []
imagePaths=[os.path.join(path,f) for f in os.listdir(path)]
for imagePath in imagePaths:
name = str(os.path.split(imagePath)[1].split('.',2)[1])
names.append(name)
cap=cv2.VideoCapture(0)#读取摄像头
# cap=cv2.VideoCapture('1.mp4')#读取名为1.mp4的视频
name()
while True:
flag,frame=cap.read()
if not flag:
break
face_detect_demo(frame)
if ord(' ') == cv2.waitKey(10):
break
cv2.destroyAllWindows()
cap.release()
#print(names)
效果如下图:

