Python+OpenCV 实现人脸识别

所需库

import cv2				# 用于获取视频、图像变换、标记
# cv2.face模块		用于人脸数据训练,人脸匹配
"""
注意1:cv2有两个包
	一个为opencv-python,# opencv主仓库的模块
	一个为opencv-contrib-python,# main模块和contrib模块

注意2:face模块在opencv-contrib-python中,需要单独安装。
注意3:import cv2.face 时显示 没有名为face的模块!!!
	这可能是pycharm的bug,实际上已经安装了opencv-contrib-python包,
	有趣的是,在确保安装opencv-contrib-python包后,这个bug并不会影响程序的运行。可以忽略不计
"""
# qt5制作显示界面
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *

1、openCV获取视频图像

OpenCV自带获取视频(也可是图片)的函数 VideoCapture(),该函数既可以采集视频,也可以获取图片。
使用方法:

第1步:
self.cap = cv2.VideoCapture(0)  
# 参数为数字,调用摄像头获取视频流。‘0’一般是打开电脑自带摄像头,其他值是打开外部摄像头(只有一个摄像头的情况)
# 参数为路径,获取本地存储的图片或视频
 
 第2步:(可选)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)  # 设置图像宽度
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)  # 设置图像高度
 
 第3步:(可选)       
self.cap.set(cv2.CAP_PROP_FPS, 5)  # 设置帧率
	
第4步:
# 可以放在线程中运行,即:主动轮询方式 获取图像
ret, frame = self.cap.read()  # 获取图像

# 返回值1:ret 为pybool类型,表示获取是否成功
# 返回值2:frame 为一帧图像数据, 注意:opencv 的默认色彩系为BGR;

if ret:  		# True
	# 转换色彩类型 BGR -> RGB
	cv_show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  
    # QT类型的图像(彩色)
    qt_show = QImage(cv_show.data, cv_show.shape[1], cv_show.shape[0], QImage.Format_RGB888)
    # 在QT界面显示图像(彩色)
    self.main_ui.show_camera_picture(qt_show)

完整代码

'''
文件名:main.py
说明:
使用openCV获取视频,让后在qt5设计的界面中显示(label控件)
'''

import sys
import cv2							# openCV库
import threading					# 线程模块
import time							# 时间模块  用于获取系统时间等操作

sys.path.append('./qtuiDesigner')    # pyqt5设计的界面文件夹
sys.path.append('./MvImport')		 # 海康工业相机API文件夹 **此处没有用到
# from PyQt5.QtWidgets import QApplication      # 因为runMainWindow模块中包含了QApplication导入语句
from qtuiDesigner.runMainWindow import *  # qt5 主界面

'''
重点笔记:
说明:我在工程中创建了qtuiDesigner文件夹

sys.path.append('./qtuiDesigner')        	  # 这句是必须的   
from qtuiDesigner.runMainWindow import *      # 要使用qtuiDesigner.前缀

注意:没有sys.path.append('./qtuiDesigner'),将导致下一句中 qtuiDesigner.runMainWindow的无法识别。
这说明如果不在sys中添加新的文件夹路径,即使在同一个工厂中,pycharm也无法找到该文件夹下的文件(模块)。

对包的导入操作需要加强理解,导入包可以分为包内有__init__.py文件 和 没有__init__.py文件两种情况。

__init__.py 主要用于初始化该包模块

注意1:在包(文件夹)内没有__init__文件,也可以导入该包模块。
注意2:from qtuiDesigner.runMainWindow import * 该语句最后的“ * ”表示导入该模块(.py文件)中的全部内容,包括该模块内的import语句。
        因此,上面的导入可以省略 from PyQt5.QtWidgets import QApplication,就是因为qtuiDesigner.runMainWindow模块中已经导入了。
操作步骤:
1、必须要将包(文件夹)名添加到sys.path地址中
2、导入该包内模块时,也需要将包(文件夹)名写在模块(文件)名称前,例如:from qtuiDesigner.runMainWindow import * 
上述另个步骤少一不可。
例如:没有添加sys.path地址,那么,在from qtuiDesigner.runMainWindow import * 这句中就会出错!!
3、采用这种方法导入,包内也会生成__pycache__文件夹。
'''

class MainEntry:
    """
    入口类
    """
    def __init__(self)
        self.cap = None  # 全局相机
        self.b_is_open = False  # 相机开启标记
        self.b_exit_grabbing = False  # 停止抓取标记
        self.thread_handle = None  # 线程句柄
        self.main_ui = None  # 界面UI
        self.app = None

    def start(self):
        # 重点笔记:
        # cv2.VideoCapture()方法可以用于读取摄像头,也可以用于读取视频
        # 当参数为数字时,就是读取摄像头
        # 当参数为视频文件路径时,就是读取视频文件
        self.cap = cv2.VideoCapture(0)  # 调用摄像头‘0’一般是打开电脑自带摄像头,其他值是打开外部摄像头(只有一个摄像头的情况)
        print("start().self.cap type:", type(self.cap))

        # TODO 显示主界面
        self.app = QApplication(sys.argv)  # 重点1:QApplication()类需要参数sys.argv。注意:sys.argv本程序的路径
        print("start().self.app type:", type(self.app))

		# qt5 界面类
        self.main_ui = RunMainWindow(main_obj=self, name="测试1主界面")
        print("start().self.main_ui type:", type(self.main_ui))

		# qt5 界面显示
        self.main_ui.show()

		# qt5 运行,且qt5界面运行结束后,程序退出
        sys.exit(self.app.exec_())

    def open_camera(self):
        """
        打开相机 函数
        笔记:起始OpenCV不存在打开相机的函数;
              self.cap = cv2.VideoCapture(0)该语句应该就包含了打开相机的动作;
              在此函数里,主要是设置相机的采集频率(帧频)和获取一帧图像的尺寸。
        :return:
        """
        if self.cap is None:
            print("open_camera().", "Error: self.cap is None.")
            self.b_is_open = False
            return

		# opencv 打开摄像头
		# 提示:self.cap = cv2.VideoCapture(0)
        if not self.cap.isOpened():
            self.b_is_open = False
            print("Warning: 本机相机打开失败.")
        else:
            self.b_is_open = True
            print("Info: 本机相机打开成功.")
            # 设置获取图像的参数;频率,尺寸等
            # 笔记:视频图像可以理解为一组联系的图片;过多的图片将导致处理量过大,可以采用控制帧频的方式抽帧抓取图片进行处理。
            # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)  # 设置图像宽度
            # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)  # 设置图像高度
            self.cap.set(cv2.CAP_PROP_FPS, 5)  # 设置帧率

    def close_camera(self):
        print("close_camera().", "self.cap type:", type(self.cap))  # self.cap在这里为空,说明之前的赋值没有执行
        self.b_exit_grabbing = True
        self.b_is_open = False
        time.sleep(1)  # 睡眠 1 秒
        # 笔记:释放视频流
        self.cap.release()  # 释放摄像头

    def start_grabbing(self):
        print("run start_grabbing()")
        self.b_exit_grabbing = False
        # 笔记:创建线程 与 运行线程
        # 用线程的实现 主动轮询获取图像
        self.thread_handle = threading.Thread(target=self.work_thread)  # 创建线程
        self.thread_handle.start()  # 运行线程

    def stop_grabbing(self):
        print("stop_grabbing")
        self.b_exit_grabbing = True
        time.sleep(1)  # 睡眠 1
        
    def work_thread(self) -> None:
    	'''
    	工作线程
    	主动轮询的方式获取视频(OpenCV)
    	'''
        print("This is work_thread()")
        if not self.b_is_open:
            print("Warning: 相机未开启.")
            return

        total_time = 0  # 总时间
        total_frames = 0  # 总帧数

        # 显示图像
        while True:
        	# openCV 获取图片(视频的一帧)
            ret, frame = self.cap.read()  # 获取图像
            if ret:  # True
                total_frames += 1  # 计算总帧数
                start_time = time.time()  # 开始时间
                
                # 笔记:获取一帧图像后,可以改变图像的尺寸,即:对原始图像进行缩放
                # frame_image = cv2.resize(frame, (640, 512))
                # 笔记:opencv自带了显示框,该示例中没有使用,而是显示在pyqt5的label控件中
                # cv2.imshow("frame", frame_1)   # OpentCV 图像显示框
                # 重点笔记:OpenCV采用的色彩体系为BGR,pyqt采用的为RGB,必须将会才能使用。
                cv_show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 转换色彩类型 BGR -> RGB
                # 重点笔记:QImage为pyqt5的图像类,将数据装载进该类对象中,才能用于显示
                # *****QImage类不熟悉,需要单独学习
                # QT类型的图像(彩色)
                qt_show = QImage(cv_show.data, cv_show.shape[1], cv_show.shape[0], QImage.Format_RGB888)
                # 在QT界面显示图像(彩色)
                self.main_ui.show_camera_picture(qt_show)

                # 处理图像
                # 重点笔记:灰度处理
                cv_show_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

                # 重点笔记:画图形
                # 注意:OpenCV 的颜色采用的是RGB
                # cv2.rectangle(cv_show_gray, (100, 100, 150, 150), color=(255, 0, 0), thickness=1)

                # 人脸检测
                # 1、人脸检测在灰度图下进行
                # 2、加载分类器
                #    自带分类器路径:C:\ProgramData\Anaconda3\Lib\site-packages\cv2\data
                #    注意:选择分类器路径时,路径内反斜杠应该改为双反斜杠 或者 单斜杠
                face_detect = cv2.CascadeClassifier(
                    'C:/ProgramData/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
                # 3、使用分类器
                face = face_detect.detectMultiScale(cv_show_gray, 1.1, 3, 0, (100, 100), (400, 400))
                # 4、获得人脸位置矩形 并绘制
                for x, y, w, h in face:
                    cv2.rectangle(cv_show_gray, (x, y), (x+w, y+h), color=(255, 0, 0), thickness=2)
                # 识别效果:在正脸且面部图像较大的情况下,效果较好。头部左右旋转,会造成识别失败。

                # 笔记:保存图像
                #       路径错误会导致存储失败。
                # cv2.imwrite("D:/testImage.jpg", frame)

                # pyqt5显示处理后的图像
                qt_show_processing = QImage(cv_show_gray.data, cv_show_gray.shape[1], cv_show_gray.shape[0],
                                            QImage.Format_Grayscale8)  # 显示类型与图像类型要匹配
                self.main_ui.show_picture_processing(qt_show_processing)

				# 计算耗时
                end_time = time.time()  # 结束时间
                total_time += end_time - start_time
                print("运算耗时:", end_time - start_time)
            else:  # False
                print("Error: self.cap.read() is failed.")

            if self.b_exit_grabbing:
                print("Exit thread")
                break

        print("共采集{}帧,总运算耗时{}秒,平均耗时{}毫秒".format(total_frames, total_time, total_time / total_frames * 1000))
        return


# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':
    # print(dir(cv2))
    # print(cv2.face)  # 显示找不到face模块,但是可以使用
    """
	重点笔记  关于cv2.face模块
	注意1:cv2有两个包
		一个为opencv-python,# opencv主仓库的模块 (不包含face模块)
		一个为opencv-contrib-python,# main模块和contrib模块  (包含face模块)
		
	注意2:一般默认安装opencv-python,opencv-contrib-python则需要单独安装。都安装上并不冲突!
	注意3:import cv2.face 时显示 没有名为face的模块!!!
		这可能是pycharm的bug,实际上已经安装了opencv-contrib-python包,
		有趣的是,在确保安装opencv-contrib-python包后,这个bug并不会影响程序的运行。可以忽略不计
	"""

    m_entry = MainEntry()
    m_entry.start()

2、人脸识别并标记

# openCV 获取图片(视频的一帧)
ret, frame = self.cap.read()  # 获取图像
if ret:  # True
	# 处理图像
    # 第1步: 获得灰度图像
    cv_show_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 第2步:加载分类器
    #    自带分类器路径:C:\ProgramData\Anaconda3\Lib\site-packages\cv2\data
    #    注意:选择分类器路径时,路径内反斜杠应该改为双反斜杠 或者 单斜杠
    face_detect = cv2.CascadeClassifier(
                    'C:/ProgramData/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
    # 第3步:使用分类器 获得人脸位置数组
    # 		该函数获得的为一张图片内全部人脸信息
    face = face_detect.detectMultiScale(cv_show_gray, 1.1, 3, 0, (100, 100), (400, 400))
    # 第4步:获得人脸位置矩形 并绘制
    for x, y, w, h in face:
        cv2.rectangle(cv_show_gray, (x, y), (x+w, y+h), color=(255, 0, 0), thickness=2)
    # 识别效果:在正脸且面部图像较大的情况下,效果较好。头部左右旋转,会造成识别失败。

    # pyqt5显示处理后的图像
    qt_show_processing = QImage(cv_show_gray.data, cv_show_gray.shape[1], cv_show_gray.shape[0],
                                            QImage.Format_Grayscale8)  # 显示类型与图像类型要匹配
    self.main_ui.show_picture_processing(qt_show_processing)

3、人脸数据训练

第一步:获取面部图像和ID

faces, ids = get_image_and_labels()

第二步:加载识别器

recongnizer = cv2.face.LBPHFaceRecognizer_create()

第三步:训练

recongnizer.train(faces, np.array(ids))

第四步:保存文件

recongnizer.write('trainer/trainer.yml')
# 源代码
import cv2
import numpy as np
from PIL import Image   # 图像类


def get_image_and_labels(folder_path=""):
    # 存储人脸数据
    faces_samples = []
    # 存储姓名数据
    names = []
    # 笔记:我用了一张图片最为训练对象,也可以采用视频
    image_paths = ["me.jpg", ]
    # 加载分类器   与人脸识别部分相同
    face_detector = cv2.CascadeClassifier(
        'C:/ProgramData/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
    # 遍历图片列表(其实只有一张)
    for image_path in image_paths:
        # 打开图片,灰度化PIL有九种不同类型:1,L,P,RGB,RGBA,CMYK,YCbCr,I,F
        '''
         PIL模式简介
			图像的模式定义了图像的类型和像素的位宽。当前支持如下模式:
			1:1位像素,表示黑和白,但是存储的时候每个像素存储为8bit。
			L:8位像素,表示黑和白。
			P:8位像素,使用调色板映射到其他模式。
			RGB:3x8位像素,为真彩色。
			RGBA:4x8位像素,有透明通道的真彩色。
			CMYK:4x8位像素,颜色分离。
			YCbCr:3x8位像素,彩色视频格式。
			I:32位整型像素。
			F:32位浮点型像素。
		PIL也支持一些特殊的模式,包括RGBX(有padding的真彩色)和RGBa(有自左乘alpha的真彩色)。
		可以通过mode属性读取图像的模式。其返回值是包括上述模式的字符串。
        '''
        pil_image = Image.open(image_path).convert('L')
        # 将图像转换为数组,灰度(黑白深浅)
        img_numpy = np.array(pil_image, 'uint8')
        # 笔记:
        # 也可以使用cv2.VideoCapture("me.jpg")来获取图片
        # 1、cv2.VideoCapture("me.jpg")
        # 2、ret, frame = self.cap.read()  # 获取图像
        # 3、cv_show_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 4、faces = face_detector.detectMultiScale(cv_show_gray)
        # 可以看出 cv_show_gray 与 img_numpy 是等价的
        
        # 获得图片人脸特征列表 faces
        faces = face_detector.detectMultiScale(img_numpy)
        # 获取每张图片的id和名称
        # id = int(os.path.split(image_path)[1].split('.')[0])
        # 笔记:没有从图像名称中查分名字,设置了一个固定命名
        name = 1
        # 预防无脸图片
        for x, y, w, h in faces:
            names.append(name)
            faces_samples.append(img_numpy[y:y+h, x:x+w])   # 获得面部矩阵的切片
            # Python获取切片的写法非常方便

    # print("ids: ", names)
    # print("fs: ", faces_samples)
    return faces_samples, names   # Python函数可以返回多个返回值


if __name__ == '__main__':
    # image path
    #path = './'
    # 笔记: 面部样本训练 并保存模板
    # 第一步:获取面部图像和ID
    # 获取图像数组和id
    faces, ids = get_image_and_labels()
    # 第二步:加载识别器  LBPH人脸识别器
    recongnizer = cv2.face.LBPHFaceRecognizer_create()
    # 第三步:样本训练 
    # 注意!!! np.array(ids)中ids列表的项必须是int类型。字符类型会报错。
    # 也就是说,没有过面部图像对应一个int类型的id
    recongnizer.train(faces, np.array(ids))
    # 第四步:保存模板文件
    recongnizer.write('trainer/trainer.yml')

4、人脸匹配

第一步:创建LBPH人脸识别器

recogizer = cv2.face.LBPHFaceRecognizer_create()

第二步:加载训练模板

recogizer.read('trainer/trainer.yml')

第三步:获取图像或者视频

cap = cv2.VideoCapture('1.mp4')  
while True:
	ret,frame = cap.read()
if ret:
	第四步:处理图像
	face_datect _demo(frame)
else:
	break

第四步:检测面部(定位面部矩形)

gray = cv2.cvtColor(imag, cv2.COLOR_BGR2GRAY) # 转换为灰度
# 加载分类器
face_detector = cv2.CascadeClassifier(
    'C:/ProgramData/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
# 使用分类器
face = face_detector.detectMultiScale(gray, 1.1, 5, cv2.CASCADE_SCALE_IMAGE, (100, 100), (400, 400))

第五步:匹配面部

# 处理面部列表
for x,y,w,h in face:
	# 画面部矩形
	cv2.rectangle(img, (x, y), (x+w, y+h), color=(0,0,255), thickness=2)
	
	# 人脸匹配
	# 笔记:recogizer LBPH人脸识别器对象
	ids, confidence = recogizer.predict(gray[y:y+h, x:x+w])
	
	# 根据评分判断匹配是否成功
	# confidence该值越小越可信
	if confidence > 80: 
		global warning_time   # 停留计时器
		warning_time += 1
		if warning_time > 100: # 未知人员停留时间超过100
			# 省略报警操作
			# 停留计时器 复位
			warning_time = 0  
		# 标记未匹配人员
		cv2.putText(img, 'unkown', (x + 10, y -10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0,255,0), 1)
	else:
		# 匹配成功
		cv2.putText(img, str(names[ids-1]), (x + 10, y -10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0,255,0), 1)
cv2.imshow('result', img)
# 源代码 main

# 这是一个示例 Python 脚本。

# 按 Shift+F10 执行或将其替换为您的代码。
# 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。

import sys
import cv2
import threading
import time

sys.path.append('./qtuiDesigner')
sys.path.append('./MvImport')
# from PyQt5.QtWidgets import QApplication      # 因为runMainWindow模块中包含了QApplication导入语句
from qtuiDesigner.runMainWindow import *  # qt5 主界面

'''
sys.path.append('./qtuiDesigner')           
from qtuiDesigner.runMainWindow import *

重点2: 对包的导入操作需要加强理解,导入包可以分为包内有__init__.py文件,和没有该文件。__init__.py主要用于初始化该包模块
注意1:在包(文件夹)内没有__init__文件,也可以导入该包模块
注意2:from qtuiDesigner.runMainWindow import * 该语句最后的“*”表示导入该模块(.py文件)中的全部内容,包括该模块内的import语句。
        因此,上面的导入可以省略 from PyQt5.QtWidgets import QApplication,就是因为qtuiDesigner.runMainWindow模块中已经导入了。
操作步骤:
1、必须要将包(文件夹)名添加到sys.path地址中
2、导入该包内模块时,也需要将包(文件夹)名写在模块(文件)名称前,例如:from qtuiDesigner.runMainWindow import * 
上述另个步骤少一不可。
例如:没有添加sys.path地址,那么,在from qtuiDesigner.runMainWindow import * 这句中就会出错!!
3、采用这种方法导入,包内也会生成__pycache__文件夹。
'''


def print_hi(name):
    # 在下面的代码行中使用断点来调试脚本。
    print(f'Hi, {name}')  # 按 Ctrl+F8 切换断点。


class MainEntry:
    """
    入口类
    """

    def __init__(self):
        self.cap = None  # 全局相机
        self.b_is_open = False  # 相机开启标记
        self.b_exit_grabbing = False  # 停止抓取标记
        self.thread_handle = None  # 线程句柄
        self.main_ui = None  # 界面UI
        self.app = None

    def start(self):
        # 注意:cv2.VideoCapture()方法可以用于读取摄像头,也可以用于读取视频
        # 当参数为数字时,就是读取摄像头
        # 当参数为视频文件路径时,就是读取视频文件
        self.cap = cv2.VideoCapture(0)  # 调用摄像头‘0’一般是打开电脑自带摄像头,其他值是打开外部摄像头(只有一个摄像头的情况)
        print("start().self.cap type:", type(self.cap))

        # TODO 显示主界面
        self.app = QApplication(sys.argv)  # 重点1:QApplication()类需要参数sys.argv。注意:sys.argv本程序的路径
        print("start().self.app type:", type(self.app))

        self.main_ui = RunMainWindow(main_obj=self, name="测试1主界面")
        print("start().self.main_ui type:", type(self.main_ui))

        self.main_ui.show()
        sys.exit(self.app.exec_())

    def open_camera(self):
        """
        打开相机
        :return:
        """
        print("open_camera().", "self.cap type:", type(self.cap))  # self.cap在这里为空,说明之前的赋值没有执行
        if self.cap is None:
            print("open_camera().", "Error: self.cap is None.")
            self.b_is_open = False
            return
        else:
            print("open_camera().", "self.cap is not None.")
            self.b_is_open = True

        if not self.cap.isOpened():
            self.b_is_open = False
            print("Warning: 本机相机打开失败.")
        else:
            self.b_is_open = True
            print("Info: 本机相机打开成功.")
            # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)  # 设置图像宽度
            # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)  # 设置图像高度
            self.cap.set(cv2.CAP_PROP_FPS, 5)  # 设置帧率

    def close_camera(self):
        print("close_camera().", "self.cap type:", type(self.cap))  # self.cap在这里为空,说明之前的赋值没有执行
        self.b_exit_grabbing = True
        self.b_is_open = False
        time.sleep(1)  # 睡眠 1 秒
        self.cap.release()  # 释放摄像头

    def start_grabbing(self):
        print("run start_grabbing()")
        self.b_exit_grabbing = False
        self.thread_handle = threading.Thread(target=self.work_thread)  # 创建线程
        self.thread_handle.start()  # 运行线程

    def stop_grabbing(self):
        print("stop_grabbing")
        self.b_exit_grabbing = True
        time.sleep(1)  # 睡眠 1

    def work_thread(self) -> None:
        print("This is work_thread()")
        if not self.b_is_open:
            print("Warning: 相机未开启.")
            return

        total_time = 0  # 总时间
        total_frames = 0  # 总帧数

        # 显示图像
        while True:
            ret, frame = self.cap.read()  # 获取图像
            if ret:  # True
                total_frames += 1  # 计算总帧数
                start_time = time.time()  # 开始时间
                # frame_image = cv2.resize(frame, (640, 512))
                # cv2.imshow("frame", frame_1)   # OpentCV 图像显示框
                cv_show = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 转换色彩类型 BGR -> RGB
                # QT类型的图像
                qt_show = QImage(cv_show.data, cv_show.shape[1], cv_show.shape[0], QImage.Format_RGB888)
                # 在QT界面显示图像
                self.main_ui.show_camera_picture(qt_show)

                # 处理图像
                # 灰度处理
                cv_show_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

                # 画图形
                # 注意:OpenCV 的颜色采用的是GBR
                # cv2.rectangle(cv_show_gray, (100, 100, 150, 150), color=(255, 0, 0), thickness=1)

                # 人脸检测
                # 1、人脸检测在灰度图下进行
                # 2、加载分类器
                #    自带分类器路径:C:\ProgramData\Anaconda3\Lib\site-packages\cv2\data
                #    注意:选择分类器路径时,路径内反斜杠应该改为双反斜杠 或者 单斜杠
                face_detect = cv2.CascadeClassifier(
                    'C:/ProgramData/Anaconda3/Lib/site-packages/cv2/data/haarcascade_frontalface_alt2.xml')
                # 3、使用分类器
                face = face_detect.detectMultiScale(cv_show_gray, 1.1, 3, 0, (100, 100), (400, 400))
                # 4、获得人脸位置矩形 并绘制
                for x, y, w, h in face:
                    cv2.rectangle(cv_show_gray, (x, y), (x+w, y+h), color=(255, 0, 0), thickness=2)

                    # 面部匹配
                    f_id, confidence = recogizer.predict(cv_show_gray[y:y+h,x:x+w])
                    print('f_id=%d, confidence=%f' % (f_id, confidence))
                    if confidence > 50:
                        # 不匹配
                        cv2.putText(cv_show_gray, 'unkown', (x + 15, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), 1)
                    else:
                        # 匹配
                        # cv2.putText 不支持中文
                        cv2.putText(cv_show_gray, str(names[f_id-1]), (x + 15, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 255, 255), 1)

                # 保存图像
                # cv2.imwrite("D:/testImage.jpg", frame)
                # print("save testImage.jpg")

                # 显示处理图像
                qt_show_processing = QImage(cv_show_gray.data, cv_show_gray.shape[1], cv_show_gray.shape[0],
                                            QImage.Format_Grayscale8)  # 显示类型与图像类型要匹配
                self.main_ui.show_picture_processing(qt_show_processing)

                end_time = time.time()  # 结束时间
                total_time += end_time - start_time
                print("运算耗时:", end_time - start_time)
            else:  # False
                print("Error: self.cap.read() is failed.")

            if self.b_exit_grabbing:
                print("Exit thread")
                break

        print("共采集{}帧,总运算耗时{}秒,平均耗时{}毫秒".format(total_frames, total_time, total_time / total_frames * 1000))
        return


# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':
    print_hi('PyCharm start run.')
    print(cv2)
    # print(dir(cv2))
    # print(cv2.face)

    # 创建 LBPH 人脸识别器
    recogizer = cv2.face.LBPHFaceRecognizer_create()
    # 加载训练模板
    recogizer.read('trainer/trainer.yml')
    # 姓名列表
    names = ['me', 'wife', 'eldest daughter', 'youngest daughter',]

    m_entry = MainEntry()
    m_entry.start()


测试结果:
训练模板一个。
主要画面中主要为一人,中途换人测试,但是没有分辨出来。
本人的confidence在40左右,最大值42,最小值39

共采集700帧,总运算耗时22.16756319999695秒,平均耗时31.667947428567064毫秒

你可能感兴趣的:(Python,opencv,python,计算机视觉)