Python实战项目:人脸识别

流程
  • 人脸录入
    • 打开摄像头
    • 输入名字
    • 检测人脸
    • 保存图片
  • 训练数据
    • 读出全部图片
    • 训练数据
    • 保存数据
  • 人脸识别
    • 打开摄像头
    • 检测人脸
    • 识别人脸

用到的模块

  • 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()

 

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值