流程
- 人脸录入
- 打开摄像头
- 输入名字
- 检测人脸
- 保存图片
- 训练数据
- 读出全部图片
- 训练数据
- 保存数据
- 人脸识别
- 打开摄像头
- 检测人脸
- 识别人脸
用到的模块
- os:为操作系统的访问提供相关功能的支持(处理文件和目录)
- opencv-python:计算机视觉和机器学习软件库
- opencv-contrib-python:opencv 的扩展模块
练习模块
import os
print(os.name)
print(os.getcwd()) # 获取当前工作路径
print(os.path.abspath('./day1.py')) # 获取绝对路径
print(os.path.join('days', 'day3.py')) # 连接目录和文件名,不同的操作系统不一样
# print('\\'.join(['days', 'day3.py']))
print(os.path.isdir('day5'))
print(os.path.isfile('day3.py'))
print(os.path.getsize('day3.py')) # 获得文件的大小(字节)
print(os.path.split('../days/day3.py')) # 拆分目录和文件名
print(os.path.splitext('../days/day3.py')) # 拆分路径和扩展名,只是字符串,路径不需要真实存在
print(os.listdir('./')) # 以列表形式列出指定目录下的所有文件和目录
# os.mkdir('./day4') # 创建目录
# os.makedirs('./day4/day5') # 递归创建目录
# os.rmdir('./day4') # 删除目录
# os.removedirs('./day4/day5') # 递归删除目录
# os.rename('./day4', 'day5')
# os.remove('1.py')
- opencv
# -*- coding:utf-8 -*-
import cv2 as cv
# 读取图像
img = cv.imread('111.jpg') # 返回 BGR 图像
# 第二个参数:flags,读取图像的方式
# cv2.IMREAD_COLOR 1,彩色,默认
# cv2.IMREAD_GRAYSCALE:0,灰度
# cv2.IMREAD_UNCHANGED:-1,包括alpha通道(透明度通道)
# 获取图像属性
print(img.shape) # 行、列、通道数(如果是彩色的)
print(img.size) # 像素总数
print(img.dtype) # 图像数据类型,uint8:8位无符号整型,0~255
# 所有红色像素置为0?
# img[:, :, 2] = 0
# 保存图像
# cv.imwrite('222.jpg', img)
# 显示图像
cv.imshow('show image', img) # 第一个参数:窗口名
cv.waitKey(0) # 等待键盘事件
cv.destroyAllWindows() # 释放内存,销毁所有窗口
修改属性
# 改变颜色空间
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 图像缩放
img = cv.resize(img, dsize=(200, 400)) # 指定尺寸
img = cv.resize(img, None, fx=0.5, fy=0.5) # 指定比例
print(img.shape)
绘图功能
cv.line(img, (0, 0), (100, 100), color=(0, 0, 255), thickness=2)
cv.rectangle(img, (100, 200), (200, 400), color=(0, 0, 255), thickness=1)
cv.circle(img, (500, 500), 100, color=(0, 0, 255), thickness=3)
cv.putText(img, "Purr", (300, 300), fontFace=cv.FONT_HERSHEY_SIMPLEX, fontScale=2, color=(0, 255, 0), thickness=3, lineType=cv.LINE_AA)
捕捉摄像头实时画面
# -*- coding:utf-8 -*-
import cv2 as cv
cap = cv.VideoCapture(0) # 连接摄像头,0代表第一个摄像头(也可以指定视频文件)
if not cap.isOpened():
print('连接摄像头失败')
while True:
# 逐帧捕获
ret, frame = cap.read()
if not ret:
print("读帧失败")
break
cv.imshow('frame', frame)
# 按'q'键退出
if cv.waitKey(1) == ord('q'):
break
# 释放捕获器和关闭窗口
cap.release()
cv.destroyAllWindows()
人脸检测
import cv2 as cv
# 读取图像
img = cv.imread('./face.jpeg')
# 检测人脸
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转为灰度图像,减少计算量
face_classifier = cv.CascadeClassifier("../../venv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml") # 加载级联检测器,人脸特征分类器
# faces = face_classifier.detectMultiScale(gray, minNeighbors=3)
faces = face_classifier.detectMultiScale(gray, minNeighbors=1)
# scaleFactor 搜索窗口的比例系数,越小检测时间越长,默认1.1 1.3
# minNeighbors 构成目标的相邻矩形最小个数,默认3 8
# minSize maxSize 限制目标的范围
# 框出人脸
for x, y, w, h in faces:
cv.rectangle(img, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=2)
cv.imshow('face', img)
while True:
if cv.waitKey(1) == ord('q'):
break
# 释放内存,销毁所有窗口
cv.destroyAllWindows()
训练数据
import os
import cv2 as cv
import numpy as np
faces_list = []
labels = []
label = 1
# 遍历data下面的图片,检测并提取出人脸信息
for f in os.listdir('./data'):
# 读取图片
img = cv.imread(os.path.join('./data', f), 0)
# 提取人脸信息
face_classifier = cv.CascadeClassifier("../../venv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml")
faces = face_classifier.detectMultiScale(img)
if len(faces) == 0:
continue
x, y, w, h = faces[0]
faces_list.append(img[y:y + h, x:x + w])
labels.append(label)
label += 1
# 训练数据并保存
recognizer = cv.face.LBPHFaceRecognizer_create() # opencv-contrib-python
recognizer.train(faces_list, np.array(labels)) # 一组人脸信息,一组人脸对应标签
recognizer.write('train.yml')
人脸识别
import cv2 as cv
# 读取图片,并转成灰度图像
img = cv.imread('./data/james.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 提取图片中的人脸特征信息
face_classifier = cv.CascadeClassifier("../../venv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml")
faces = face_classifier.detectMultiScale(gray)
# 加载识别器和训练数据
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.read('train.yml')
# 遍历图片中的人脸
for x, y, w, h in faces:
# 识别图片中的人脸,返回标签和置信度
img_id, confidence = recognizer.predict(gray[y:y+h, x:x+w])
if confidence > 85:
name = 'unknown'
else:
name = 'james' if img_id == 1 else 'lena'
# 标出识别出的人名,用圆圈出人脸
cv.putText(
img=img, org=(x, y), text=name,
fontFace=cv.FONT_HERSHEY_SIMPLEX, fontScale=0.75,
color=(0, 255, 0), thickness=1
)
cv.circle(
img=img, center=(x + w // 2, y + h // 2), radius=w//2,
color=(255, 0, 0), thickness=1
)
# 展示标记后的图片
cv.imshow('face', img)
while True:
if cv.waitKey(1) == ord('q'):
break
# 释放内存
cv.destroyAllWindows()
代码
人脸录入
main()
def main():
"""
录入人脸是为了得到训练数据去训练
1.人脸照片(使用摄像头、只取人脸部分、框出人脸并展示实时摄像头画面、保存和退出) 2.人脸对应的名字(用户输入) 3.编号(文件名记录)
打开摄像头
输入名字
循环取每帧画面
人脸检测并取人脸部分
框出人脸并展示实时摄像头画面
通过按键保存和退出,文件名的格式为:编号.姓名.jpg
关闭摄像头和窗口
:return:
"""
# 打开摄像头
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("连接摄像头失败")
# 输入名字
name = input("请输入需要录入的名字:")
print("姓名输入完成,按 s 键保存,按 q 键退出")
# 获取摄像头的每帧画面,判断是否保存和退出
while True:
ret, frame = cap.read()
if not ret:
print("读帧失败")
break
# 检测并提取人脸信息
faces, gray = img_extract_faces(frame)
# 框出人脸
for x, y, w, h in faces:
cv.rectangle(
img=frame, pt1=(x, y), pt2=(x + w, y + h),
color=BGR_GREEN, thickness=GRAPH_THICKNESS
)
cv.imshow(INPUT_FACE_WINDOW_NAME, frame)
k = cv.waitKey(1)
if k == ord('s'):
save_face(faces, gray, name)
elif k == ord('q'):
break
# 释放内存
cap.release()
cv.destroyAllWindows()
img_extract_faces()
def img_extract_faces(img):
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 转成灰度图像
face_classifier = cv.CascadeClassifier(FACE_CLASSIFIER_PATH) # 获取人脸检测的级联分类器
return face_classifier.detectMultiScale(gray, minSize=FACE_MIN_SIZE), gray
save_face()
def get_image_name(name):
# 图片命名格式:编号.名字.jpg
name_map = {f.split('.')[1]: int(f.split('.')[0]) for f in os.listdir(IMG_SAVE_PATH)}
if not name_map:
name_number = 1
elif name in name_map:
name_number = name_map[name]
else:
name_number = max(name_map.values()) + 1
return IMG_SAVE_PATH + str(name_number) + "." + name + ".jpg"
def save_face(faces, img, name):
if len(faces) == 0:
print("没有检测到人脸,请调整")
return
if len(faces) > 1:
print("检测到多个人脸,请调整")
return
x, y, w, h = faces[0]
cv.imwrite(get_img_name(name), img[y:y + h, x:x + w])
print("录入成功,按 q 键退出")
训练数据
def main():
# 图片完整路径
image_paths = [os.path.join(IMG_SAVE_PATH, f) for f in os.listdir(IMG_SAVE_PATH)]
# 遍历列表中的图片
faces = [cv.imread(image_path, 0) for image_path in image_paths]
# 获取训练对象
img_ids = [int(f.split('.')[0]) for f in os.listdir(IMG_SAVE_PATH)]
recognizer = cv.face.LBPHFaceRecognizer_create() # opencv-contrib-python
recognizer.train(faces, np.array(img_ids))
# 保存文件
recognizer.write(TRAIN_DATA_SAVE_PATH)
人脸识别
main
def get_color_text(confidence, name):
if confidence > FACE_CONFIDENCE:
return BGR_RED, 'unknown'
return BGR_GREEN, name
def main():
"""
识别人脸:通过LBPH识别器(训练数据、当前人脸信息)得到标签,标签和人脸关系,标记人脸和名字并展示画面
创建识别器、加载训练数据
读取文件名构造标签和人脸关系
打开摄像头
循环取每帧画面
人脸检测并取人脸部分
遍历人脸进行识别
框出人脸并展示实时摄像头画面
关闭摄像头和窗口
:return:
"""
# 加载用户名和训练数据
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.read(TRAIN_DATA_SAVE_PATH)
name_map = {int(f.split('.')[0]): f.split('.')[1] for f in os.listdir(IMG_SAVE_PATH)}
# 打开摄像头
cap = cv.VideoCapture(0)
if not cap.isOpened():
print("连接摄像头失败")
while True:
# 获取每帧画面, ret为空读取失败
ret, frame = cap.read()
if not ret:
print("读帧失败")
break
# 检测并提取人脸信息
faces, gray = img_extract_faces(frame)
# 识别并圈出人脸,显示人名
for x, y, w, h in faces:
img_id, confidence = recognizer.predict(gray[y:y + h, x:x + w])
color, text = get_color_text(confidence, name_map[img_id])
cv.putText(
img=frame, text=text, org=(x, y),
fontFace=cv.FONT_HERSHEY_SIMPLEX,
fontScale=FONT_SCALE,
color=color, thickness=TEXT_THICKNESS
)
cv.circle(
img=frame, center=(x + w // 2, y + h // 2),
radius=w // 2,
color=color, thickness=GRAPH_THICKNESS
)
cv.imshow(FACE_RECOGNITION_WINDOW_NAME, frame)
if cv.waitKey(1) == ord('q'): # 退出
break
# 释放内存
cap.release()
cv.destroyAllWindows()