基于 OpenCV-Python 实现人脸识别

基本介绍        

        项目分为3个程序,人脸照片录入、训练数据、人脸识别。获取摄像头画面,检测并保存人脸部分,用户输入人名,数据经过训练后,能够通过摄像头识别人脸,将人名显示到摄像头画面上。

模块介绍

  • opencv-python:人脸的检测、识别,控制摄像头,图像处理
  • opencv-contrib-python:opencv的扩展模块,人脸识别的模型
  • os:操作文件和目录
  • numpy:只用了转数组

人脸录入程序

  • 程序目标:为下一步训练数据提供需要的数据
  • 程序分析:训练数据的函数使用 cv.face.LBPHFaceRecognizer_create().train() 
    • 第一个参数需要一组人脸信息,我们在本程序中检测并保存人脸部分图像
    • 第二个参数是上一个参数中一组人脸对应的编号,由于最后我们显示的是人名,所以我们需要编号、人名、人脸图像三者一起存下来,给人脸图像的名字规则为:编号.人名.jpg

        cv.CascadeClassifier(CLASSIFIER_MODEL)中的CLASSIFIER_MODEL为opencv提供的人脸级联分类器,路径为:venv/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml

import cv2 as cv
import os

def img_extract_faces(img):
    """
    从图片中提取人脸部分,彩色图像转成灰度图像,减少计算量
    :return: 返回人脸位置,灰度图像
    """
    gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    return cv.CascadeClassifier(CLASSIFIER_MODEL).detectMultiScale(gray), gray


def box_faces_show(faces, img):
    """
    框出人脸并展示图像
    """
    for x, y, w, h in faces:
        cv.rectangle(
            img=img, pt1=(x, y), pt2=(x + w, y + h),
            color=(0, 255, 0), thickness=GRAPH_THICKNESS
        )
    cv.imshow(INPUT_FACE_WINDOW_NAME, img)


def get_image_name(name):
    """
    图片命名:编号.姓名.jpg。编号递增,重复录入的覆盖原照片
    """
    name_map = {f.split('.')[1]: int(f.split('.')[0]) for f in os.listdir(IMG_SAVE_PATH)}
    return IMG_SAVE_PATH + '/' + str(name_map.get(name, max(name_map.values() or [0]) + 1)) + "." + name + ".jpg"


def save_face(faces, img, name):
    """
    截取人脸部分的照片保存
    :param faces: 人脸位置数据
    :param img: 原图像
    :param name: 用户输入的名字
    :return:
    """
    if len(faces) == 0:
        print("没有检测到人脸,请调整")
        return
    if len(faces) > 1:
        print("检测到多个人脸,请调整")
        return
    x, y, w, h = faces[0]
    cv.imwrite(get_image_name(name), img[y:y + h, x:x + w])
    print("录入成功,按q键退出")

# 录入人名
name = input("请输入要录入的人名: ")
print("姓名输入完毕,请按q退出,请按c保存")

# 打开摄像头
capture = cv.VideoCapture(0)
if not capture.isOpened():
    print("摄像头打开失败")

# 循环每帧画面
while True:
    ret, frame = capture.read()
    if ret == 0:
        print("摄像头捕捉失败")
        break

    # 提取并框出人脸,展示画面
    faces, _ = img_extract_faces(frame)
    box_faces_show(faces, frame)

    # 按 q 键退出,按 c 键保存
    k = cv.waitKey(1)
    if k == ord('q'):
        break
    if k == ord('c'):
        save_face(faces, frame, name)

# 释放资源
capture.release()
cv.destroyAllWindows()

 训练数据程序

  • 程序目标:训练并保存数据,为识别人脸提供训练数据
  • 程序分析:读取上一步录入的全部人脸图像和图像的文件名,提取文件名中的编号部分
# 获取图片路径
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()
recognizer.train(faces, np.array(img_ids))
# 保存训练数据
recognizer.write(TRAIN_DATA_SAVE_PATH)

人脸识别程序

  • 程序目标:摄像头中的人脸能够标识出对应的人名
import os
import cv2 as cv

# 人脸录入程序中定义过的函数不再列出

def mark_faces_show(faces_names, img):
    for x, y, w, h, color, name in faces_names:
        cv.putText(
            img=img, org=(x, y), text=name,
            fontFace=cv.FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale=0.75,
            color=color, thickness=1
        )
        cv.circle(
            img=img, center=(x + w // 2, y + h // 2), radius=w // 2,
            color=color, thickness=1
        )
    cv.imshow(RECOGNITION_FACE_WINDOW_NAME, img)

def recognize_face(faces, recognizer, gray, number_dict):
    faces_names = []
    for x, y, w, h in faces:
        img_id, confidence = recognizer.predict(gray[y:y + h, x:x + w])
        color, name = get_color_name(confidence, number_dict[img_id])
        faces_names.append((x, y, w, h, color, name))
    return faces_names

#  加载模型和训练数据
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.read(TRAIN_DATA_PATH)

#  标签:名字
number_dict = {int(f.split('.')[0]): f.split('.')[1] for f in os.listdir(IMG_SAVE_PATH)}

#  打开摄像头
capture = cv.VideoCapture(0)
if not capture.isOpened():
    print("摄像头链接失败")

#  循环提取每帧画面
while True:
    ret, frame = capture.read()
    if not ret:
        print("读取帧率失败")
        break
    #  提取并框出人脸
    faces, gray = img_extract_faces(frame)

    # 识别并展示人脸
    faces_names = recognize_face(faces, recognizer, gray, number_dict)
    mark_faces_show(faces_names, frame)

    if cv.waitKey(1) == ord('q'):
        break

# 释放资源
capture.release()
cv.destroyAllWindows()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值