系列文章目录
第二章:基于深度学习的学生课堂专注度检测系统设计与实现之基于OpenCV的人脸识别。
文章目录
前言
通过实现人脸识别功能,辅助课堂签到。这里使用的是一种较为普通的办法,基于OpenCV Haar级联进行人脸识别。此前,我也做过一个基于face_recognition的人脸识别,但是效果太差。后续我也将继续完善,使用Dlib去进行人脸识别。
一、OpenCV介绍及安装
1.1 OpenCV简介
OpenCV 的全称是OpenSourceComputerVision Library,是一个跨平台的计算机视觉库。OpenCV 是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。OpenCV可用于开发实时的图像处理、计算机视觉以及模式识别程序。该程序库也可以使用英特尔公司的IPP进行加速处理。
OpenCV 用C++语言编写,它的主要接口也是C++语言,但是依然保留了大量的C语
言接口。该库也有大量的Python、JavaandMATLAB/OCTAVE(版本2.5)的接口。这些语言的API接口函数可以通过在线文档获得。如今也提供对于C#、Ch、Ruby、GO的支持。
1.2 安装OpenCV模块
OpenCV 已经支持python的模块了,直接使用pip就可以进行安装,命令如下:
pip install opencv-python
二、OpenCV的基本使用
2.1 读取图片
显示图像是OpenCV最基本的操作之一,imshow()函数可以实现该操作。如果使用过其他GUI框架背景,就会很自然第调用imshow()来显示一幅图像。
imshow()函数有两个参数:显示图像的帧名称以及要显示的图像本身。直接调用imshow()函数图像确实会显示,但随即会消失。要保证图片一直在窗口上显示,要通过waitKey()函数。waitKey()函数的参数为等待键盘触发的时间,单位为毫秒,其返回值是-1(表示没有键被按下)
import cv2 as cv
img=cv.imread('lena.jpg') #注意读取图片的路径不能有中文,不然数据读取不出来
cv.imshow('input image',img)
cv.waitKey(0) #等待键盘的输入 单位是毫秒 传入0 无限等待
cv.destroyAllWindows() #C++语言 使用完内存必须释放
2.2 图片灰度转换
OpenCV 中有数百种关于在不同色彩空间之间转换的方法。当前,在计算机视觉中有三种常用的色彩空间:灰度、BGR、以及HSV(Hue,Saturation,Value)。
(1)灰度色彩空间是通过去除彩色信息来将其转换成灰阶,灰度色彩空间对中间处理特别有效,比如人脸识别。
(2)BGR及蓝、绿、红色彩空间,每一个像素点都由一个三元数组来表示,分别代表蓝、绿、红三种颜色。网页开发者可能熟悉另一个与之相似的颜色空间:RGB它们只是颜色顺序上不同。
(3)HSV,H(Hue)是色调,S(Saturation)是饱和度,V(Value)表示黑暗的程度(或光谱另一端的明亮程度)。
灰度转换的作用就是:转换成灰度的图片的计算强度得以降低。示例如下:
import cv2 as cv
src=cv.imread('lena.jpg')
cv.imshow('inputimage',src)
#cv2读取图片的通道是BGR(蓝绿红)
#PIL读取图片的通道是RGB
gray_img=cv.cvtColor(src,code=cv.COLOR_BGR2GRAY)
cv.imshow('gray_image',gray_img)
cv.waitKey(0)
cv.destroyAllWindows()
#保存图片
cv.imwrite('gray_lena.jpg',gray_img)
2.3 修改图片尺寸
import cv2 as cv
img=cv.imread('lena.jpg')
cv.imshow('inputimage',img)
#修改图片的尺寸
#resize_img=cv.resize(img,dsize=(110,160))
resize_img=cv.resize(img,dsize=(400,360))
print(resize_img.shape)
cv.imshow('resize_img',resize_img)
#如果键盘输入的是q时候退出
whileTrue:
if ord('q')==cv.waitKey(0):
break
cv.destroyAllWindows()
2.4 画图
OpenCV 的强大之处的一个体现就是其可以对图片进行任意编辑,处理。 下面的这个函数最后一个参数指定的就是画笔的大小。
import cv2 as cv
img=cv.imread('lena.jpg')
#画矩形
x,y,w,h=50,50,80,80
cv.rectangle(img,(x,y,x+w,y+h),color=(0,255,0),thickness=2) #color=BGR
cv.imshow('result image',img)
cv.waitKey(0)
cv.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,0,255),thickness=2)
cv.destroyAllWindows()
三、Haar级联介绍及获取
3.1Haar级联概念
Haar级联是一种基于机器学习的对象检测方法,由Paul Viola和Michael Jones在2001年提出。它通过训练大量的正样本(包含目标对象的图像)和负样本(不包含目标对象的图像)来创建分类器。Haar级联检测器在OpenCV中非常流行,主要优点是速度快,适用于资源受限的设备。
基本原理:
Haar级联检测器使用Haar特征来检测对象。Haar特征类似于卷积核,通过计算黑色矩形区域下的像素总和与白色矩形区域下的像素总和的差值来获得特征值。为了加速计算,使用了积分图像(也称为求和面积表),使得计算类似Haar的特征非常快。
使用预训练模型:
OpenCV提供了多种预训练的Haar级联模型,包括面部、眼睛和嘴部检测等。可以使用cv2.CascadeClassifier类从磁盘加载预训练的Haar级联检测器,并使用detectMultiScale方法进行检测
3.2 获取Haar级联数据
首先我们要进入OpenCV官网:https://opencv.org/releases/,由于OpenCV支持好多平台,比如Windows,Android,Maemo,FreeBSD, OpenBSD, iOS,Linux 和 Mac OS,一般初学者都是用windows,点击Windows。如下图所示:
点击Windows下载文件,然后双击下载的文件,进行安装,实质就是解压一下,解压完出来一个文件夹,其他什
么也没发生。安装完后的目录结构如下。其中build是OpenCV使用时要用到的一些库文件,而sources 中则是OpenCV官方为我们提供的一些demo示例源码。
在sources 的一个文件夹data/haarcascades。该文件夹包含了所有OpenCV的人脸检测的XML文件,这些可用于检测静止图像、视频和摄像头所得到图像中的人脸。
人脸检测器(默认):haarcascade_frontalface_default.xml
人脸检测器(快速Harr):haarcascade_frontalface_alt2.xml
人脸检测器(侧视):haarcascade_profileface.xml
眼部检测器(左眼):haarcascade_lefteye_2splits.xml
眼部检测器(右眼):haarcascade_righteye_2splits.xml
嘴部检测器:haarcascade_mcs_mouth.xml
鼻子检测器:haarcascade_mcs_nose.xml
身体检测器:haarcascade_fullbody.xml
人脸检测器(快速LBP):lbpcascade_frontalface.xm
四、使用OpenCV进行人脸检测
4.1 静态图像中单张人脸检测
人脸检测首先是加载图像并检测人脸,这也是最基本的一步。为了使所得到的结果有意义,可在原始图像的人脸周围绘制矩形框。
示例代码:
# @Time : 2025/1/10 0010 10:49
# @Author :sjsflyqy
import cv2 as cv
def face_detect_demo():
# 将图片灰度
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 加载特征数据
face_detector = cv.CascadeClassifier('D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml')
faces = face_detector.detectMultiScale(gray)
for x, y, w, h in faces:
cv.rectangle(img, (x, y), (x+w, y+h), color=(0, 255, 0), thickness=2)
cv.imshow('result', img)
# 加载图片
img = cv.imread('face01.jpg')
# 人脸检测
face_detect_demo()
cv.waitKey(0)
cv.destroyAllWindows()
效果:
4.2 静态图像中多张人脸检测
示例代码:
# @Time : 2025/1/10 0010 11:04
# @Author :sjsflyqy
import cv2 as cv
def face_detect_demo():
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 加载特征数据
face_detector = cv.CascadeClassifier('D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml')
# detectMultiScale()中有很多参数用于调整框选范围。
faces = face_detector.detectMultiScale(gray)
for x, y, w, h in faces:
cv.rectangle(img, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=2)
cv.circle(img, center=(x+w//2, y+h//2), radius=w//2, color=(0, 255, 0), thickness=2)
cv.imshow('result', img)
# 加载图片
img = cv.imread('face3.jpg')
# 调用人脸检测方法
face_detect_demo()
cv.waitKey(0)
cv.destroyAllWindows()
效果:
4.3 视频中的人脸检测
视频是一张一张图片组成的,在视频的帧上重复这个过程就能完成视频中的人脸检测。
示例代码:
# @Time : 2025/1/10 0010 15:48
# @Author :sjsflyqy
import cv2 as cv
def face_detect_demo(img):
# 将图片灰度
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 加载特征数据
face_detector = cv.CascadeClassifier('D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml')
# detectMultiScale()中有很多参数用于调整框选范围。
faces = face_detector.detectMultiScale(gray)
for x, y, w, h in faces:
cv.rectangle(img, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=2)
cv.imshow('result', img)
cap = cv.VideoCapture(0)
while True:
flag, frame = cap.read()
if not flag:
break
face_detect_demo(frame)
if ord('q') == cv.waitKey(10):
break
# cv.imshow('video', frame)
cv.destroyAllWindows()
cap.release()
五、人脸识别
5.1 介绍
人脸检测是OpenCV的一个很不错的功能,它是人脸识别的基础。什么是人脸识别呢?
其实就是一个程序能识别给定图像或视频中的人脸。实现这一目标的方法之一是用一系列分好类的图像来“训练”程序,并基于这些图像来进行识别。这就是OpenCV及其人脸识别模块进行人脸识别的过程。人脸识别模块的另外一个重要特征是:每个识别都具有转置信(confidence)评分,因此可在实际应用中通过对其设置阈值来进行筛选。人脸识别所需要的人脸可以通过两种方式来得到:自己获得图像或从人脸数据库免费获得可用的人脸图像。互联网上有许多人脸数据库:https://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
为了对这些样本进行人脸识别,必须要在包含人脸的样本图像上进行人脸识别。这是一个学习的过程,但并不像自己提供的图像那样令人满意。
5.2 训练数据
有了数据,需要将这些样本图像加载到人脸识别算法中。所有的人脸识别算法在它们的train()函数中都有两个参数:图像数组和标签数组。这些标签表示进行识别时候某人人脸的ID,因此根据ID可以知道被识别的人是谁。要做到这一点,将在「trainer/」目录中保存为.yml文件。
在使用Python3&OpenCV3.0.0 进行人脸识别训练时发现异常:
AttributeError: ‘module’ object has no attribute ‘LBPHFaceRecognizer_create’OpenCV
需要安装opencv-contrib-python 模块,直接使用 pip就可以进行安装,命令如下:
pip install opencv-contrib-python
示例代码:
# @Time : 2025/1/10 0010 17:56
# @Author :sjsflyqy
import os
import cv2
import numpy as np
import sys
from PIL import Image
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier('D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml')
def getImagesAndLabels(path):
imagePaths = [os.path.join(path,f) for f in os.listdir(path)]
faceSamples=[]
ids = []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') # convert it to grayscale
img_numpy = np.array(PIL_img,'uint8')
id = int(os.path.split(imagePath)[-1].split(".")[0])
faces = detector.detectMultiScale(img_numpy)
for (x, y, w, h) in faces:
faceSamples.append(img_numpy[y:y + h, x:x + w])
ids.append(id)
return faceSamples, ids
if __name__=='__main__':
path='./data/jm/'
faces,ids=getImagesAndLabels(path)
recognizer.train(faces,np.array(ids))
#Savethemodelintotrainer/trainer.yml
recognizer.write('trainer/trainer.yml')
5.3 基于LBPH模型的人脸识别
LBPH(LocalBinaryPatternHistogram)将检测到的人脸分为小单元,并将其与模型中的对应单元进行比较,对每个区域的匹配值产生一个直方图。由于这种方法的灵活性,LBPH是唯一允许模型样本人脸和检测到的人脸在形状、大小上可以不同的人脸识别算法。调整后的区域中调用predict()函数,该函数返回两个元素的数组:第一个元素是所识别个体的标签,第二个是置信度评分。所有的算法都有一个置信度评分阈值,置信度评分用来衡量所识别人脸与原模型的差距,0表示完全匹配。可能有时不想保留所有的识别结果,则需要进一步处理,因此可用自己的算法来估算识别的置信度评分。LBPH一个好的识别参考值要低于50,任何高于80的参考值都会被认为是低的置信度评分。
示例代码:
import cv2
import numpy as np
import os
recognizer=cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
def face_detect_demo(img):
# 将图片灰度
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 加载特征数据
face_detector = cv2.CascadeClassifier('D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml')
# detectMultiScale()中有很多参数用于调整框选范围。
faces = face_detector.detectMultiScale(gray)
for x, y, w, h in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), color=(0, 0, 255), thickness=2)
id, confidence = recognizer.predict(gray[y:y + h, x:x + w])
font = cv2.FONT_HERSHEY_DUPLEX
color = (0, 255, 0)
cv2.putText(frame, str(id), (x, y - 10), font, 0.5, color, 1)
print(id, confidence)
cv2.imshow('result', img)
cap = cv2.VideoCapture(0)
while True:
flag, frame = cap.read()
if not flag:
break
face_detect_demo(frame)
if ord('q') == cv2.waitKey(10):
break
# cv.imshow('video', frame)
cv2.destroyAllWindows()
cap.release()
六、DeepSeek对上述代码的解析与修改建议
6.1 第一部分:训练模型代码
1.导入库
import os
import cv2
import numpy as np
import sys
from PIL import Image
- 作用:导入必要的库,包括文件操作(
os
)、图像处理(cv2
,PIL
)、数值计算(numpy
)等。
2. 初始化识别器和检测器
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier('D:\\opencv\\..._frontalface_default.xml')
- 作用:
LBPHFaceRecognizer
:基于局部二值模式直方图(LBPH)的人脸识别模型。CascadeClassifier
:Haar级联分类器,用于检测人脸位置。
3. 数据加载函数 getImagesAndLabels
def getImagesAndLabels(path):
imagePaths = [os.path.join(path, f) for f in os.listdir(path)]
faceSamples, ids = [], []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') # 转为灰度图
img_numpy = np.array(PIL_img, 'uint8')
id = int(os.path.split(imagePath)[-1].split(".")[0]) # 从文件名提取ID
faces = detector.detectMultiScale(img_numpy)
for (x, y, w, h) in faces:
faceSamples.append(img_numpy[y:y+h, x:x+w])
ids.append(id) # 修正:每检测到一个人脸添加一次ID
return faceSamples, ids
- 作用:遍历指定路径下的所有图像,检测人脸并提取对应ID。
- 问题:
- 原代码中
ids.append(id)
的位置错误,会导致标签数量与样本数量不匹配(已修正)。 - 假设每个图像仅包含单个人脸,否则需确保文件名与多个人脸对应。
- 原代码中
4. 主程序
if __name__ == '__main__':
path = './data/jm/'
faces, ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
recognizer.write('trainer/trainer.yml')
- 作用:加载数据、训练模型并保存到
trainer.yml
。
6.2 第二部分:实时检测代码
1. 加载模型和检测器
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
face_detector = cv2.CascadeClassifier('D:\\opencv\\..._frontalface_default.xml')
- 作用:加载训练好的模型和人脸检测器。
2. 检测函数 face_detect_demo
def face_detect_demo(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 修正变量名错误
faces = face_detector.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)
for x, y, w, h in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2)
id, confidence = recognizer.predict(gray[y:y+h, x:x+w])
label = str(id) if confidence < 70 else "Unknown" # 添加置信度阈值
cv2.putText(img, label, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
cv2.imshow('result', img)
- 改进:
- 修正了
frame
到img
的变量名错误。 - 添加了置信度阈值判断,避免误识别未知人脸。
- 修正了
3. 摄像头实时检测
cap = cv2.VideoCapture(0)
while True:
flag, frame = cap.read()
if not flag:
break
face_detect_demo(frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
- 作用:打开摄像头,逐帧处理并显示结果,按
q
退出。
潜在问题与改进建议
-
训练数据标签错误(已修正):
- 每个检测到的人脸需对应一个ID标签。
-
变量名错误(已修正):
- 实时检测函数中的
frame
应改为img
。
- 实时检测函数中的
-
未知人脸处理(已改进):
- 通过置信度阈值过滤低置信度识别结果。
-
路径硬编码:
- 建议将
haarcascade_frontalface_default.xml
放在项目目录中,使用相对路径。
- 建议将
-
多张人脸的处理:
- 训练时需确保每张图像仅包含单个人脸,或文件名与多张人脸对应。
总结
- 训练代码:从指定路径加载图像,检测人脸并训练LBPH模型。
- 实时检测代码:调用摄像头实时检测人脸,并用训练好的模型识别。
- 关键改进:修正标签匹配、变量名错误,添加置信度阈值提升鲁棒性。
七、总结
以上就是今天要讲的内容,本文仅仅简单介绍了借助OpenCV的Haar级联进行简单的人脸检测并训练LBPH模型,还有许多需要完善,希望大家多多指点。另外,希望大家不要吝啬点赞 收藏(●’◡’●)!