Bootstrap

人脸识别【python-基于OpenCV】

1. 导入并显示图片

#导入模块
import cv2 as cv

#读取图片
img=cv.imread('img/wx(1).jpg')  #路径名为全英文,出现中文 图片加载失败,"D:\picture\wx.jpg"
#显示图片  (显示标题,显示图片对象)
cv.imshow('read_picture',img)

#等待键盘输入(毫秒单位) 值为0 :表示无限等待
cv.waitKey(0)

#释放内存 opencv底层由C++ 编写
cv.destroyAllWindows()

2. 将图片进行灰度处理

import cv2 as cv  #以cv 引用 cv2
img=cv.imread('img/wx(1).jpg')
cv.imshow('BGR_img',img)  #展示该图片
#等待键盘获取时间,该时间内得到键盘响应则继续向下执行;否则展示图片计时结束后自动运行
cv.waitKey(3000)

#将 img对象灰度处理后,赋予gray_img对象
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
cv.imshow('gray_img',gray_img)  #展示灰度图片
#保存转换后的图片 (’新文件名‘,原图片对象)
cv.imwrite('img/gray_wx(1).jpg', gray_img)
cv.waitKey(3000)
cv.destroyAllWindows()  #释放内存

3. 更改图片的尺寸大小

import cv2 as cv
img=cv.imread('img/wx(1).jpg')
cv.imshow('old_img',img)
print('原图尺寸为(宽、高、):',img.shape)
cv.waitKey(5000)

#改变原始图片尺寸大小
resize_img=cv.resize(img,dsize=(500,500))
print('当前图片尺寸(宽、高、):',resize_img.shape)
cv.imshow('resize_img',resize_img)

#更改waitKey等待条件 : 键盘输入 'q'
while 1:
    if ord(' ')==cv.waitKey(0):
        break

cv.destroyAllWindows()

4. 在图片中绘制图形

import cv2 as cv
img=cv.imread('img/wx(1).jpg')
img2=cv.imread('img/wx(1).jpg')
#矩形描点:左上角坐标(x,y),右下角坐标(x+w,y+h),w:宽,h:高
x,y,w,h=100,100,40,40
#绘制矩形 (图片对象,坐标(),颜色(),宽度)
cv.rectangle(img,(x,y,x+w,y+h),color=(0,255,0),thickness=2)  #color(BGR)
cv.imshow('rectangle_img',img)
cv.waitKey(2000)

#绘制圆形:(原点坐标(),半径,颜色,宽度)
cv.circle(img2,center=(100,100),radius=40,color=(0,0,255),thickness=2)
cv.imshow('circle_img',img2)
cv.waitKey(2000)
cv.destroyAllWindows()

5. 对图片进行人脸检测,对应面部区域绘制矩形

import cv2 as cv
img=cv.imread('img/wx(1).jpg')
img2=cv.imread('img/wx(1).jpg')
#矩形描点:左上角坐标(x,y),右下角坐标(x+w,y+h),w:宽,h:高
x,y,w,h=100,100,40,40
#绘制矩形 (图片对象,坐标(),颜色(),宽度)
cv.rectangle(img,(x,y,x+w,y+h),color=(0,255,0),thickness=2)  #color(BGR)
cv.imshow('rectangle_img',img)
cv.waitKey(2000)

#绘制圆形:(原点坐标(),半径,颜色,宽度)
cv.circle(img2,center=(100,100),radius=40,color=(0,0,255),thickness=2)
cv.imshow('circle_img',img2)
cv.waitKey(2000)
cv.destroyAllWindows()

6. 多人人脸检测

import cv2 as cv
def face_detact_demo(img_path):
    img=cv.imread(img_path)
    if img is None:
        print("Error:img_path error!")
        return
    # 1:灰度处理并适当更改尺寸大小
    # img=cv.resize(img,dsize=(1000,600))
    gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)

    # 2:加载特征数据,获取特征对象
    face_detector=cv.CascadeClassifier(
        'D:/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml'
    )
    if face_detector.empty():
        print("Error:Failed to load haarcascade_frontalface_default.xml")
        return
    # 3:检测人脸,获取范围坐标
    faces = face_detector.detectMultiScale(gray)
    # faces=face_detector.detectMultiScale(gray,scaleFactor=1.01,minNeighbors=3,flags=0,maxSize=(35,35),minSize=(29,29))
    # detectMultiScale(image,scaleFactor = 1.1,minNeighbors = 3,flags = 0,minSize = Size(),maxSize = Size())
    if len(faces)==0:
        print("Error:NO faces face_detected!")
        return
    else:
        # 在监测的人脸范围绘制矩形
        for (x,y,w,h) in faces:
            print(x,y,w,h)
            cv.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
            cv.circle(img,(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=2)

    cv.imshow('face_detect',img)
    cv.waitKey(10000)

img_path='img/m.jpg'
face_detact_demo(img_path)
cv.destroyAllWindows()

由特征对象获取人脸范围坐标时,因图片中人脸的精准度问题可能存在获取非人脸范围,因此需要调节函数参数,实现高效扫描

face_detector.detectMultiScale 是 OpenCV 库中用于人脸检测的一个常用函数。这个函数属于 Haar 或 LBP 特征分类器的一部分,通常用于在图像中检测不同大小的人脸

std::vector<Rect> detectMultiScale(
    InputArray image,
    double scaleFactor = 1.1,
    int minNeighbors = 3,
    int flags = 0,
    Size minSize = Size(),
    Size maxSize = Size()
);

参数介绍:

  1. image: 输入图像,通常是一个灰度图像(尽管也可以传入彩色图像,但内部会自动转换为灰度图)。
  2. scaleFactor: 图像缩放的比例因子。例如,1.1 表示每次图像尺寸变为原来的 1.1 倍。该参数决定了图像金字塔的层数,从而影响检测到的人脸的大小范围。
  3. minNeighbors: 每个候选矩形区域需要有多少个相邻的矩形区域来保留该区域,也就是扫描该范围多少次。这个参数影响检测的准确度和检测到的区域的数量。
  4. flags: 修改检测方法的标志。可以是以下值的组合:
    • CASCADE_SCALE_IMAGE: 按比例缩放图像。默认开启。
    • CASCADE_FIND_BIGGEST_OBJ: 只返回最大的对象。
    • CASCADE_DO_ROUGH_SEARCH: 只做粗略搜索。
    • CASCADE_DO_CANNY_PRUNING: 使用 Canny 边缘检测器来丢弃一些边缘太多的图像区域。
    • CASCADE_SCALE_IMAGE 和 CASCADE_DO_ROUGH_SEARCH 通常默认开启,其他标志可能需要根据具体需求来设置。
  1. minSize: 目标对象的最小可能尺寸。
  2. maxSize: 目标对象的最大可能尺寸。

返回值

该函数返回一个 Rect 对象的向量,每个 Rect 对象代表检测到的人脸的位置和大小

7. 视频人脸检测:

import cv2 as cv
def faces_detect_demo(img):
    #灰度处理
    gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    #加载特征数据
    face_detector = cv.CascadeClassifier(
        'D:/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
    if face_detector.empty():
        print("Error: failed to load face_detector!")
        return
    #检测人脸范围
    face=face_detector.detectMultiScale(gray)

    #绘制人脸矩形
    for(x,y,w,h)in face:
        print(x,y,w)
        cv.rectangle(img,(x,y),(x+w,y+h),color=(255,0,255),thickness=2)
        cv.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(255,0,0),thickness=2)
    #显示图片
    cv.imshow('vedio_detect',img)

#1:读取本地视频
# "D:\桌面\代码\video.mp4"
cap1=cv.VideoCapture('v.mp4')
#2:调用自己的摄像头
cap=cv.VideoCapture(0)

while True:
    #flag为监测标志位flag为false时退出视频监测
    #frame为视频中读取每一帧的的图片对象
    flag,frame=cap.read()
    if not flag:
        break
    #进行方法监测
    faces_detect_demo(frame)
    # 键入空格退出,否则循环检测
    if ord('q')==cv.waitKey(3000):
        break
cv.destroyAllWindows()
cap.release()

以上提供两种视频提供:

#1:读取本地视频
cap1=cv.VideoCapture('v.mp4')
#2:调用自己的摄像头
cap2=cv.VideoCapture(0)

继而循环从视频中提取图片对象:flag,frame=cap.read() 进行方法检测人脸

flag 以及 操作键入值 q 作为循环是否继续的判断

8. 人脸数据训练:

import os
import sys
import cv2
import numpy as np
from PIL import Image

def getImageAndLabels(path):
    facesSamples=[]
    ids=[]
    #将路径与文件名称结合 以列表形式存储
    imagePaths=[os.path.join(path,f) for f in os.listdir(path)]

    # 加载特征数据
    face_detector = cv2.CascadeClassifier(
        'D:/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
    if face_detector.empty():
        print("Error: failed to load face_detector!")
        return

    #遍历列表中的图片
    for imagePath in imagePaths:
        #打开图片
        PIL_img=Image.open(imagePath).convert('L')
        #将图片转为数组
        img_numpy=np.array(PIL_img,'uint8')
        # 检测人脸范围
        face = face_detector.detectMultiScale(img_numpy)
        #获取图片id
        #将路径中第二部分文件名中的数据id由‘.’进行分割,将字符串转换为整形存储
        id=int(os.path.split(imagePath)[1].split('.')[0])
        for x,y,w,h in face:
            #将人脸检测范围进行切片处理,作为图像数组
            facesSamples.append(img_numpy[y:y+h,x:x+w])
            ids.append(id)
    return facesSamples,ids

if __name__ == '__main__':
    #图片路径:
    path='./data/jm/'
    #获取图像数组以及id标签数组
    faces,ids=getImageAndLabels(path)
    #获取循环对象
    recognizer=cv2.face.LBPHFaceRecognizer_create()
    recognizer.train(faces, np.array(ids))
    #保存文件
    recognizer.write('trainer/trainer.yml')

获取训练集:

9. 人脸识别:

基于 LBPH 的人脸识别

LBPH(Local Binary Pattern Histogram)将检测到的人脸分为小单元,并将其与模型中 的对应单元进行比较,对每个区域的匹配值产生一个直方图。由于这种方法的灵活性,LBPH 是唯一允许模型样本人脸和检测到的人脸在形状、大小上可以不同的人脸识别算法。 调整后的区域中调用 predict()函数,该函数返回两个元素的数组:第一个元素是所识别 个体的标签,第二个是置信度评分。所有的算法都有一个置信度评分阈值,置信度评分用来 衡量所识别人脸与原模型的差距,0 表示完全匹配。可能有时不想保留所有的识别结果,则 需要进一步处理,因此可用自己的算法来估算识别的置信度评分。LBPH 一个好的识别参 考值要低于 50 ,任何高于 80 的参考值都会被认为是低的置信度评分。

import cv2
import os
import numpy as np

#加载训练数据文件
recognizer=cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
#准备识别的图片
img=cv2.imread('./img/10.pgm')

gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
face_detector = cv2.CascadeClassifier(
    'D:/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face=face_detector.detectMultiScale(gray)
for x,y,w,h in face:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),thickness=2)
    #人脸识别
    id,confidence=recognizer.predict(gray[y:y+h,x:x+w])
    print('标签id:',id,'置信评分:',confidence)
    print('置信评分范围低于 50,高于80为低的置信度评分')
    img2_path='data/jm/'+str(id)+'.pgm'
    img2=cv2.imread(img2_path)
#扩大图像尺寸
img=cv2.resize(img,(300,300))
img2=cv2.resize(img2,(300,300))
#face_detect 检测图像展示
cv2.imshow('face_detect',img)
#recognize_img 原始图像成功比对图片
cv2.imshow('recognize_img',img2)
cv2.waitKey(8000)

;