基于OpenCV和LBPH算法的人脸识别系统(附Python完整代码)

简介

        本文将介绍一种基于LBPH(Local Binary Pattern Histograms)设计方法的人脸识别系统,使用了OpenCV库和深度学习模型的集成。LBPH方法以其对纹理特征的强大提取能力而在人脸识别领域备受青睐。通过本系统,我们不仅可以实时通过摄像头采集用户信息,还可以通过导入相片的方式来添加用户数据。

        OpenCV(Open Source Computer Vision Library)是一个用于计算机视觉任务的开源库,它包含了丰富的函数和工具,可以用于图像处理、模式识别、物体检测等方面。它的跨平台性使得它在许多不同的操作系统上都能够运行,为我们提供了一个强大的工具箱来处理图像数据。

        LBPH算法是一种基于局部二值模式(Local Binary Pattern)的人脸识别方法。它通过将像素点与周围像素点进行比较,提取局部纹理特征,从而实现对人脸的准确识别。相较于其他方法,LBPH算法对于光照变化和部分遮挡具有较强的鲁棒性,因此在实际应用中得到了广泛的使用。

LBPH原理图

人脸识别一共分为四步,本文将按照以下步骤来进行讲解:

  1. 人脸采集
  2. 数据预处理
  3. 特征提取(模型训练)
  4. 匹配识别

实现流程

人脸采集

摄像头采集

首先,通过OpenCV的库打开电脑摄像头,并输入录入信息者的用户名。

# 调用笔记本内置摄像头,参数为0,如果有其他的摄像头可以调整参数为1,2
cap = cv2.VideoCapture(0)
# 调用人脸分类器,要根据实际路径调整3
face_detector = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml') # 输入自己haar模型所在地址
# sampleNum用来计数样本数目
count = 0
# 用户名
name = 'fen' # 输入你的用户名

随后,为新用户创建一个存放照片的文件夹和对应的ID。

# 创建新的用户文件夹和用户ID
def create_incremental_folder():
    folder_name = 1
    root_folder = "./data"

    while True:
        # 检查文件夹是否已存在
        folder_path = os.path.join(root_folder, f"User{folder_name}")
        if not os.path.exists(folder_path):
            os.mkdir(folder_path)
            break
        else:
            folder_name += 1

    return folder_path, folder_name

# 为即将录入的脸标记一个id
folder_path, face_id = create_incremental_folder()

随后,打开摄像头,连续捕捉50张图像,并通过haar人脸识别器框选出人脸位置图像,截取后后保存到对应的文件夹内。

while True:
    # 从摄像头读取图片
    success, img = cap.read()
    # 转为灰度图片,减少程序符合,提高识别度
    if success is True:
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    else:
        break
    # 检测人脸,将每一帧摄像头记录的数据带入OpenCv中,让Classifier判断人脸
    # 其中gray为要检测的灰度图像,1.3为每次图像尺寸减小的比例,5为minNeighbors
    faces = face_detector.detectMultiScale(gray, 1.3, 5)

    # 框选人脸,for循环保证一个能检测的实时动态视频流
    for (x, y, w, h) in faces:
        # xy为左上角的坐标,w为宽,h为高,用rectangle为人脸标记画框
        cv2.rectangle(img, (x, y), (x + w, y + w), (255, 0, 0))
        # 成功框选则样本数增加
        count += 1
        print(count)
        # 保存图像,把灰度图片看成二维数组来检测人脸区域
        # (这里是建立了data的文件夹,当然也可以设置为其他路径或者调用数据库)
        cv2.imwrite("{}/User.".format(folder_path) + str(face_id) + '.' + str(count) + '.jpg', gray[y:y + h, x:x + w])
        # 显示图片
        cv2.imshow('image', img)
        # 保持画面的连续。waitkey方法可以绑定按键保证画面的收放,通过q键退出摄像
    k = cv2.waitKey(1)
    if k == '27':
        break
        # 或者得到800个样本后退出摄像,这里可以根据实际情况修改数据量,实际测试后800张的效果是比较理想的
    elif count >= 50:
        break

图片存储完成后,将用户ID和对应的用户名写入到csv文件中。

def csv_take(face_id, name):
    csv_file = './csv/user.csv'  # CSV 文件路径
    input_data = [['{}'.format(face_id), "{}".format(name)]]  # 输入数据,示例为编号为1的数据
    # 读取 CSV 文件中已有的数据
    existing_data = []
    with open(csv_file, 'r') as file:
        reader = cs.reader(file)
        for row in reader:
            existing_data.append(row)

    # 根据编号找到对应的行索引
    row_index = -1
    for i, row in enumerate(existing_data):
        if i + 1 == int(input_data[0][0]):
            row_index = i
            break

    # 如果找到对应的行索引,则覆盖数据
    if row_index != -1:
        existing_data[row_index] = input_data[0]
    else:
        existing_data.append(input_data[0])

    # 写入更新后的数据到 CSV 文件
    with open(csv_file, 'w', newline='') as file:
        writer = cs.writer(file)
        writer.writerows(existing_data)

    print("数据已成功写入到 CSV 文件!")

照片导入

该方法与摄像头导入类似,首先选择要导入的图片,其次输入用户名。

# 为即将录入的脸标记一个id
folder_path, face_id = create_incremental_folder()
# 指定原始图像路径和目标文件夹路径
image_path ='./image/3.jpg'  # 原始图像路径
output_folder = '{}'.format(folder_path)  # 目标文件夹路径
name = 'You'
face_detector = cv2.CascadeClassifier('./haarcascade_frontalface_default.xml')  # 待更改
count = 0

将图片进行灰度化处理后再截取图像,然后再把一张图片复制到20张。

# 扩充数据集到 20 张图像
for i in range(19):
    augmented_image = random_rotate_image(img_tem)
    augmented_image = flip_image(augmented_image)
    augmented_image = adjust_contrast(augmented_image)
    augmented_image = random_scale_image(augmented_image)
    count += 1
    # 保存增强后的图像到目标文件夹
    cv2.imwrite("{}/User.".format(folder_path) + str(face_id) + '.' + '1' + '.' + '.jpg', img_tem)
    cv2.imwrite("{}/User.".format(folder_path) + str(face_id) + '.' + '{}'.format(count+1) + '.' + '.jpg', augmented_image)

然后再对20张图片进行随机的数据增强,经过处理后,就能得到同一个人20张不一样的照片,可以提高模型的拟合度,识别的时候效果更好。随后,将用户ID和用户名存储到CSV文件中,代码同上。至此,数据采集就做完了。

数据预处理

数据增强

其中数据增强包含了四种方法,分别为:

  1. 随机旋转图像
  2. 50%概率触发水平翻转图像
  3. 调整图像对比度
  4. 随机缩放图像
# 数据增强方法1:随机旋转图像
def random_rotate_image(image):
    angle = random.randint(0, 360)  # 随机生成旋转角度
    rows, cols = image.shape
    rotation_matrix = cv2.getRotationMatrix2D((cols/2, rows/2), angle, 1)
    rotated_image = cv2.warpAffine(image, rotation_matrix, (cols, rows))
    return rotated_image

# 数据增强方法2:50% 概率触发水平翻转图像
def flip_image(image):
    if random.random() < 0.5:  # 50% 的概率触发水平翻转
        flipped_image = cv2.flip(image, 1)
    else:
        flipped_image = image
    return flipped_image

# 数据增强方法3:调整图像对比度
def adjust_contrast(image):
    alpha = random.uniform(0.5, 1.5)  # 随机生成对比度调整系数
    adjusted_image = cv2.convertScaleAbs(image, alpha=alpha)
    return adjusted_image

# 数据增强方法4:随机缩放图像
def random_scale_image(image):
    scale_factor = random.uniform(0.5, 1.5)  # 随机生成缩放比例
    rows, cols = image.shape
    scaled_image = cv2.resize(image, (int(cols*scale_factor), int(rows*scale_factor)))
    return scaled_image

转换数据格式

为了能让机器能够处理数据,需要分别将图片和ID处理成一个列表。

# 创建一个函数,用于从数据集文件夹中获取训练图片,并获取id
# 注意图片的命名格式为User.id.sampleNum
def get_images_and_labels(path):
    image_paths = [os.path.join(path, f) for f in os.listdir(path)]
    # 新建连个list用于存放
    face_samples = []
    ids = []

    # 遍历图片路径,导入图片和id添加到list中
    for image_path in image_paths:

        # 通过图片路径将其转换为灰度图片
        img = Image.open(image_path).convert('L')

        # 将图片转化为数组
        img_np = np.array(img, 'uint8')

        if os.path.split(image_path)[-1].split(".")[-1] != 'jpg':
            continue

        # 为了获取id,将图片和路径分裂并获取
        id = int(os.path.split(image_path)[-1].split(".")[1])
        faces = detector.detectMultiScale(img_np)

        # 将获取的图片和id添加到list中
        for (x, y, w, h) in faces:
            face_samples.append(img_np[y:y + h, x:x + w])
            ids.append(id)
    return face_samples, ids

特征提取(模型训练)

由于OpenCV提供了已经封装好的函数,我们直接调用LBPH算法的函数即可,通过将特征值和标签值输入模型之后便可以开始训练了,训练完后的模型会保存在weigths文件夹中。

# 初始化识别的方法
recog = cv2.face.LBPHFaceRecognizer_create()
# 获取图片和ID的列表
faces, ids = get_images_and_labels(path)
# 训练模型
recog.train(faces, np.array(ids))
# 保存模型
recog.save('./weights/model.yml'.format())

匹配识别

再识别界面,我们首先需要加载我们的标签文件,就是一开始说的那个csv文件,这个文件里存放了每个ID对应的用户名,由于模型再识别到人脸后不会直接返回用户名,只会返回一个ID编号,所以我们要通过这个ID来找到对应的用户名并将它写在界面上。

# 读取 CSV 文件中指定列的数据
with open(csv_file, 'r') as file:
    reader = cs.reader(file)
    for row in reader:
        if len(row) > column_index:
            data_array.append(row[column_index])

# 设置好与ID号码对应的用户名,如下,如0对应的就是初始
new_element = 'None'  # 要添加的新元素
data_array.insert(0, new_element)  # 在数组第一位插入新元素
names = data_array

运行程序会打开电脑的摄像头,然后对人脸进行识别,识别到人脸之后会输出用户数据并且将数据写在识别框旁边,代码如下:

while True:
    ret, img = cam.read()
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 识别人脸
    faces = face_cascade.detectMultiScale(
        gray,
        scaleFactor=1.2,
        minNeighbors=5,
        minSize=(int(minW), int(minH))
    )
    # 进行校验
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
        idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])

        # 计算出一个检验结果
        if confidence < 100:
            idum = names[idnum]
            confidence = "{0}%".format(round(confidence))
        else:
            idum = "unknown"
            confidence = "{0}%".format(round(100 - confidence))

        # 输出检验结果以及用户名
        cv2img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # cv2和PIL中颜色的hex码的储存顺序不同
        pilimg = Image.fromarray(cv2img)
        draw = ImageDraw.Draw(pilimg)  # 图片上打印
        font = ImageFont.truetype("./simhei.ttf", 30, encoding="utf-8")  # 参数1:字体文件路径,参数2:字体大小
        draw.text((x + 5, y - 30), str(idum), (255, 0, 0), font=font)
        draw.text((x + 5, y + h - 30), str(confidence), (255, 0, 0), font=font)
        img = cv2.cvtColor(np.array(pilimg), cv2.COLOR_RGB2BGR)  # PIL图片转cv2 图片

        # 展示结果
        cv2.imshow('camera', img)
        k = cv2.waitKey(int(1000 / fps))
        if k == 27:
            break

也可以在此处输入视频的地址,对视频进行实时人脸识别。

# 打开视频文件或者使用摄像头
video = 0
# video = './video/test1.mp4'

效果实测(别骂了别骂了,由于博主使用电脑摄像头对着手机拍的,所以很糊Q_Q)

运行环境

以下是我的python版本以及所用的主要库的版本,文件里会有我用到的所有库,可以直接安装。

python==3.9.13
opencv-contrib-python==4.7.0.72
opencv-python==4.7.0.72
numpy==1.22.0
Pillow==9.5.0

资料链接

百度网盘链接: https://pan.baidu.com/s/1FRTg95SRnOuL2NFnaPlWfA?pwd=brxf 提取码: brxf 

感谢您阅读本文,如果对您有帮助希望能点个赞点个收藏,期待在未来的技术发展中与您共同前行!

  • 12
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
LBPH(Local Binary Patterns Histograms)算法是一种常用的人脸识别算法,它利用图像中每个像素点及其周围像素点的灰度值信息,生成一个二进制数值表示该像素点的特征值,然后通过统计这些特征值的直方图来实现人脸识别。下面给出一个基于Python人脸识别系统设计,使用LBPH算法。 1. 数据集准备 首先需要准备一个人脸图像数据集,包括多个人的头像照片。可以使用已有的数据集,也可以自己拍摄照片并手动标注人脸位置。 2. 特征提取 使用OpenCV库中的cv2.face.LBPHFaceRecognizer类提取图像的特征信息,并训练分类器。具体步骤如下: ```python import cv2 import os # 准备数据集 data_dir = 'path/to/dataset' subjects = os.listdir(data_dir) images = [] labels = [] for i, subject in enumerate(subjects): subject_dir = os.path.join(data_dir, subject) for image_name in os.listdir(subject_dir): image_path = os.path.join(subject_dir, image_name) image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) images.append(image) labels.append(i) # 训练分类器 recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.train(images, np.array(labels)) ``` 3. 人脸识别 利用训练好的分类器对测试图像进行识别。具体步骤如下: ```python # 读取测试图像 test_image = cv2.imread('path/to/test/image', cv2.IMREAD_GRAYSCALE) # 识别人脸 label, confidence = recognizer.predict(test_image) # 显示识别结果 if confidence < 100: subject = subjects[label] confidence = int(100 - confidence) print(f"Recognized subject: {subject} with confidence {confidence}%") else: print("Unknown subject") ``` 这样,一个基于Python人脸识别系统,使用LBPH算法,就可以实现了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值