基于opencv和PyQt5的人脸识别

目    录

一、准备工作

二、分割任务

三、代码实现阶段

1、基于opencv读取照片

2、在图片上绘制矩形

3、在读取照片成功的前提下理解视频的本质,读取视频

4、在视频上绘制矩形

5、调用人脸识别模块

 6、动态调整矩形,让矩形通过人脸识别算法追踪人脸

7、调用Qt组件,创建窗口、按钮等

8、让程序对鼠标事件做出响应

9、调用定时器链接槽函数实时更新视频帧

10、创建图片容器,将视频帧放入容器中

11、美化页面

 四、总结

一、准备工作

先装上人脸识别所需要的库

 (1)在设置-python解释器-‘+’搜索同名即可添加

(2)menu+R键调出输入框输入cmd

在命令行中输入pip install 库名

等待安装即可

安装过慢,即可pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple

二、分割任务

我们要做出的窗口人脸识别效果如下:

 

 

 拆解学习任务:

(1)基于opencv读取照片

(2)在图片上绘制矩形

(3)在读取照片成功的前提下理解视频的本质,读取视频

(4)在视频上绘制矩形

(5)调用人脸识别模块

(6)动态调整矩形,让矩形通过人脸识别算法追踪人脸

(7)调用Qt组件,创建窗口、按钮等

(8)让程序对鼠标事件做出响应

(9)调用定时器链接槽函数实时更新视频帧

(10)创建图片容器,将视频帧放入容器中

(11)美化页面

三、代码实现阶段

1、基于opencv读取照片

先导包,然后通过cv.imread()读取图片,括号中为路径。可将图片放在项目文件夹下。

import cv2 as cv

img1 = cv.imread("fff.jpg")
cv.imshow("img", img1)    # 展示图片   "img"为图片标题
cv.waitKey(0)    # (0)代表等待用户操作,如没此行代码,图片将一闪而过

 代码运行结果如下:

2、在图片上绘制矩形

先读取图片,再利用rectangle函数绘制矩形,参数值可自行调节

import cv2 as cv

img1 = cv.imread("fff.jpg")
x, y, w, h = 100, 80, 200, 200
# rectangle中 img1为待处理的图片,(x,y)为左上角坐标x1,y1,(x+w,y+w)为右下角坐标(x2,y2),color在python中对应BGR,thickness为框线宽度
cv.rectangle(img1, (x, y), (x+w, y+h), color=(0, 100, 255), thickness=3)
cv.imshow("img", img1)    # 展示图片   "img"为图片标题

cv.waitKey(0)    # (0)代表等待用户操作,如没此行代码,图片将一闪而过

代码运行结果如下:

3、在读取照片成功的前提下理解视频的本质,读取视频

视频就是 根据 视觉暂留 原理,当图像连续的快速变化时,人眼无法分辨单幅的静态画面,看上去是平滑连续的视觉效果。

简单来讲就是 视频就是一帧一帧的图片组成的。

所以我们要读取视频,其实就是 一直不停的读取图片帧。(一直不停:即为循环)

import cv2 as cv

video = cv.VideoCapture("video.mp4")

while True:
    flag, frame = video.read()  # 循环读取视频,数据存入frame  读取结果 flag
    if not flag:  # 如果读取成功即持续读取下去,失败则退出循环(一般视频结束即为读取失败)
        break
    
    cv.imshow("frame", frame)   # 持续展示读取到的图片
    cv.waitKey(40)  # 每播放一张图片等待40ms再播放下一张 

运行结果如下:

好,此时我们已经可以做到读取视频了。

但同时我们也面临着一个问题:这个视频怎么也关不掉。

本质上就是:循环一直在进行,关掉当前的画面又会有新的图片展示出来。

别急,解决办法在这:

我们只需要定向设置一个“退出键”即可,当键盘录入此键,则程序结束循环:

我们可以直接在图片播放延迟的代码上继续操作。

    if cv.waitKey(40) == 27:  # 27为ESC键的ASCII码值,当ESC键录入,则程序退出循环
        break

 同理,我们应养成好的编码习惯,那既然程序退出了,那我们也应该释放内存空间:

frame.release()  # 释放内存空间

4、在视频上绘制矩形

我们刚刚理清了视频的本质:我们要对视频做出处理,即为在其中连续播放的图片上做出处理。

我们将绘制矩形的操作添加进循环里,则可以让每一帧画面都绘制上矩形,即为视频上绘制矩形。

import cv2 as cv

video = cv.VideoCapture("video.mp4")
x, y, w, h = 100, 80, 200, 200
while True:   
    flag, frame = video.read()  # 循环读取视频,数据存入frame  读取结果 flag
    if not flag:  # 如果读取成功即持续读取下去,失败则退出循环(一般视频结束即为读取失败)
        break
    # rectangle中 img1为待处理的图片,(x,y)为左上角坐标x1,y1,(x+w,y+w)为右下角坐标(x2,y2),color在python中对应BGR,thickness为框线宽度
    cv.rectangle(frame, (x, y), (x + w, y + h), color=(0, 100, 255), thickness=3)
    cv.imshow("frame", frame)   # 持续展示读取到的图片
    if cv.waitKey(40) == 27:  # 27为ESC键的ASCII码值,当ESC键录入,则程序退出循环
        break

frame.release()  # 释放内存空间

运行结果如下:

5、调用人脸识别模块

 好,现在已经成功的在视频上绘制矩形了。接下我们的问题就是:它这个框也没对准人脸啊?

接下来就要继续引入我们强大的opencv库了:

opencv已经有对人脸模型的算法,只要我们调用它的算法,就能精确在视频的每一帧上识别出人脸。

我们找到我们opencv的算法文件:一个前脸的算法模型。

在我们存放python解释器的文件夹下——lib——site-packages——cv2——data——haarcascade_frontalface_default.xml

将此文件复制到我们的项目文件夹下:

接下来,我们调用opencv的前脸识别模块:

face_detector = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
    face = face_detector.detectMultiScale(image)   # 调用检测人脸

6、动态调整矩形,让矩形通过人脸识别算法追踪人脸

既然是追踪人脸,那么我们绘制的矩形的坐标值和大小就不能是一个定值,它应该实时跟着人脸变化。既然要实时跟着变化,那么它就可以套进一个循环,让每一帧图片根据人脸识别模块定位矩形的左上角坐标值和右下角坐标值画出矩形,即做到视频的人脸识别。

    for x, y, w, h in face:
        cv.rectangle(image, (x, y), (x+w, y+h), color=(0, 100, 255), thickness=3)
    cv.imshow("frame", image)

我们将整一套人脸识别画出矩形封装进函数里:

def face_dectect_demo(image):
    # 加载人脸模型 存到 对象中
    face_detector = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
    face = face_detector.detectMultiScale(image)   # 调用检测人脸
    for x, y, w, h in face:
        cv.rectangle(image, (x, y), (x+w, y+h), color=(0, 100, 255), thickness=3)
    cv.imshow("frame", image)

 此时此刻,我们只需要读取视频后调用这个函数就可以做到动态人脸识别。

运行结果:

7、调用Qt组件,创建窗口、按钮等

首先我们导包

from PyQt5.Qt import *   # *为通配符,即为所有
import sys

接着我们创建一个子类继承父类的控件

class SettingUI(QWidget):
    def __init__(self):
        super(SettingUI, self).__init__()

 然后我们写主函数调用

if __name__ == '__main__':
    app = QApplication(sys.argv)
# QApplication 类管理图形用户界面应用程序的控制流和主要设置。 可以说 QApplication是Qt的整个后台管理的命脉

    setting = SettingUI()
    setting.show()

    sys.exit(app.exec())
# app.exec_()的作用是运行主循环,必须调用此函数才能开始事件处理,调用该方法进入程序的主循环直到调用exit()结束。
# 不用sys.exit(app.exec_()),只使用app.exec_(),程序也可以正常运行,但是关闭窗口后进程却不会退出。
# sys.exit(n)的作用是退出应用程序并返回n到父进程。

 运行结果如下:

 我们已经成功创建出一个窗口。此时我们初始化这个窗口,记得在__inti__函数里调用它:

    def __init__(self):
        super(SettingUI, self).__init__()
        self.intiUI()

    def intiUI(self):
        self.resize(600, 600)    # 窗口大小,可自行调整参数
        self.setWindowTitle("人脸识别")   # 窗口标题

 标题已经成功添加,大小也调整合适,接下来我们利用QPushButton函数添加按钮:

startbtn = QPushButton("播放", self)    # "播放"为按钮的名称 
        startbtn.move(50, 50)   # 按钮的坐标位置

 播放按钮有了,我们再添加一个暂停按钮:

        # 同理,暂停按钮如下:
        endbtn = QPushButton("暂停", self)
        endbtn.move(150, 50)

 运行结果如下:

我们再创建一段文本:

self.lab = QLabel("这里是显示视频的区域", self)
        self.lab.move(200, 250)

 运行结果如下:

 至此,我们已经成功的完成了组件的调用。

8、让程序对鼠标事件做出响应

我们发现,点击播放和暂停按钮,程序没有任何反应。这个按钮就仅仅只是个按钮,我们需要让程序做出响应。

我们利用clicked.connect函数给播放按钮链接上点击播放按钮的事件。

startbtn.clicked.connect(self.on_setting_click)

我们暂定一个调试事件看是否链接成功:

    def on_setting_click(self):
        self.lab.setText("点击播放了!")

看点击播放按钮是否会跳出”点击播放了“等字样

运行结果如下:

说明我们链接播放按钮已经成功!同理,我们再链接暂停按钮:

        endbtn.clicked.connect(self.up_setting_click)  # 链接鼠标事件

    def up_setting_click(self):    # 设置鼠标事件
        self.lab.setText("暂停播放了!")

 运行结果如下:

至此,我们已经完成程序对鼠标事件做出响应。

9、调用定时器链接槽函数实时更新视频帧

因为我们要做的是点击播放然后就播放一段视频,点击暂停视频就停止的项目。而视频又是一个不停地读取图片地过程。我们不能让用户一直点击播放来不停地读取图片,那怎么能让用户只点击一次就能一直重复地进行读取操作呢?

这里就需要用到我们的定时器,用定时器链接我们的事件响应函数(即为槽函数)。点击播放按钮后,我们的计时器开始计时。每当时间超时就自动做出事件响应,而我们就可以把读取图片这个操作放入事件响应中,即做到点击播放按钮后一直不停地读取图片--播放视频。

要让视频停止播放,即让暂停按钮链接的响应函数里放入结束定时器操作即可。

同样的。我们先测试定时器链有没有接上槽函数。

上代码:

    # 在播放事件中让定时器开始计时
    def on_setting_click(self):
        self.timer.start(30)
    # 在暂停事件中让定时器结束计时
    def up_setting_click(self):
        self.timer.stop()
        self.lab.setText("暂停播放了!")
    self.timer = QTimer(self)
    self.num = 1


    def updata_image(self):
        self.num += 1
        self.lab.setText("图片更新了!"+str(self.num))

运行结果如下:

此时我们已经成功让定时器链接上槽函数了。

接下来我们将读取视频帧的操作放入槽函数:

import cv2   # 导包


cap = cv2.VideoCapture("video.mp4")  

    def updata_image(self):
        flag, frame = cap.read()
        cv2.imshow("frame", frame)

 运行结果如下:

 现在我们已经做到能通过窗口按钮控制视频播放和暂停了。

此时我们要解决的最后一个问题就是将视频放入窗口中,而不是视频单独再开一个窗口。

10、创建图片容器,将视频帧放入容器中

首先,我们要将视频帧放入窗口中,就要先让图片格式与窗口显示的图片容器格式统一。然后再创建一个容器用于存放视频帧。

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # frame  opencv mat
        # mat =>  Qt 图片容器格式

        image = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)

        pixmap = QPixmap.fromImage(image)

        pixmap = pixmap.scaled(self.lab.size())

        self.lab.setPixmap(pixmap)    # 展示视频帧

 运行结果如下:

 

 我们可以看到,我们已经成功的将视频帧放入到图片容器中,并能够点击按钮播放和暂停。

(也可以先美化页面再调用人脸识别方法,这样可以第一时间测试人脸识别方法是否运行成功)

我们接着继续调用人脸识别模块,让我们播放的视频帧是经过人脸识别处理的。

如何调用人脸识别模块上面有讲,我们现在要操作的就是如何将这个模块完全融入到函数里。

我们先将整个人脸识别方法‘搬’过来:

def face_dectect_demo(self,image): # 第一个参数只能是self类型
    # 加载人脸模型 存到 对象中
    face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    face = face_detector.detectMultiScale(image)   # 调用检测人脸
    for x, y, w, h in face:
        cv2.rectangle(image, (x, y), (x+w, y+h), color=(0, 100, 255), thickness=3)
    # cv2.imshow("frame", image)   此时已经不需要人脸识别函数来展示视频帧了

 接着,再在转化视频帧格式前调用这个方法:

        flag, frame = cap.read()

        self.face_dectect_demo(frame)    # 位置添加在这

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

运行结果如下:

隐约能看见红框。

但是展示的视频太小和按钮的位置不美观,那我们就进入最后一步,美化界面,顺便再检测一下我们的人脸识别方法是否已经调用成功。

11、美化页面

我们此时需要做的就是调整按钮和视频帧的位置和大小,上代码:

参数可自行更改调整。

startbtn.resize(560, 30)   # 播放按钮的大小设置函数
startbtn.move(20, 480)   # 按钮的坐标位置函数

# 同理,暂停按钮的设置函数
endbtn.resize(560, 30)
endbtn.move(20, 520)

# 槽函数中容器的设置函数
self.lab.move(40, 40)   # 位置设置函数
self.lab.resize(520, 390)   # 大小设置函数

 运行结果如下:

 

 美化完毕,人脸识别方法也成功调用。

 四、总结

我们已经完成了在窗口中通过按钮控制视频,并进行人脸识别的全过程。

此项目可延展用做考勤打卡等项目,这里就不再扩展了。

源代码如下:

from PyQt5.Qt import *
import sys
import cv2

cap = cv2.VideoCapture("video.mp4")   # 参数 0 为本机摄像头


class SettingUI(QWidget):
    def __init__(self):
        super(SettingUI, self).__init__()
        self.timer = QTimer(self)
        self.intiUI()

    def intiUI(self):
        self.resize(600, 600)    # 窗口大小,可自行调整参数
        self.setWindowTitle("人脸识别")   # 窗口标题

        # 定时器链接槽函数
        self.timer.timeout.connect(self.updata_image)

        startbtn = QPushButton("播放", self)    # "播放"为按钮的名称
        startbtn.resize(560, 30)   # 播放按钮的大小设置函数
        startbtn.move(20, 480)   # 播放按钮的坐标位置函数
        startbtn.clicked.connect(self.on_setting_click)   # 播放按钮链接鼠标事件

        # 同理,暂停按钮如下:
        endbtn = QPushButton("暂停", self)
        endbtn.resize(560, 30)
        endbtn.move(20, 520)
        endbtn.clicked.connect(self.up_setting_click)   # 暂停按钮链接鼠标事件

        self.lab = QLabel("这里是显示视频的区域", self)    # 文本标签
        self.lab.move(220, 250)     # 标签位置

    def on_setting_click(self):   # 点击播放按钮即进行操作的函数
        self.timer.start(30)   # 定时器开始计时30ms

    def up_setting_click(self):
        self.timer.stop()   # 定时器结束计时

    def updata_image(self):
        flag, frame = cap.read()   # 读取视频帧,数据存入frame  读取结果 flag

        self.face_dectect_demo(frame)   # 调用人脸识别方法

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # frame  opencv mat
        # mat =>  Qt 图片容器格式

        image = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)

        pixmap = QPixmap.fromImage(image)

        pixmap = pixmap.scaled(self.lab.size())
        self.lab.setPixmap(pixmap)
        self.lab.move(40, 40)   # 位置设置函数
        self.lab.resize(520, 390)  # 大小设置函数

    def face_dectect_demo(self, image):
        # 加载人脸模型 存到 对象中
        face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
        face = face_detector.detectMultiScale(image)  # 调用检测人脸
        for x, y, w, h in face:
            cv2.rectangle(image, (x, y), (x + w, y + h), color=(0, 100, 255), thickness=3)


if __name__ == '__main__':
    app = QApplication(sys.argv)

    setting = SettingUI()
    setting.show()

    sys.exit(app.exec())

猜你喜欢

转载自blog.csdn.net/Nantainanle/article/details/132404673