简体   繁体   English

QT Opencv 人脸检测在 Python 中不起作用?

[英]QT Opencv face detection not working in Python?

I am working on a qt project where I have created window which will display the live frames from a usb webcam using opencv .我正在开发一个qt项目,在该项目中我创建了 window ,它将使用opencv显示来自 usb 网络摄像头的实时帧I also need to detect faces in the live feed and thus I am using haar-cascading method for this.我还需要检测实时提要中的人脸,因此我为此使用了haar-cascading方法。 I have created the UI part in qt-designer and then have converted it into the .py file.我在qt-designer中创建了 UI 部分,然后将其转换为.py文件。 I am then importing this file in another app.py and using app.py for all the logic part.然后我将此文件导入另一个app.py并使用app.py作为所有逻辑部分。 Below is the content of gui.py file:以下是gui.py文件的内容:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 400)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(10, 10, 381, 370))
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.pushButton = QtWidgets.QPushButton(self.groupBox)
        self.pushButton.setGeometry(QtCore.QRect(150, 160, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(400, 10, 391, 370))
        self.groupBox_2.setTitle("")
        self.groupBox_2.setObjectName("groupBox_2")
        self.label = QtWidgets.QLabel(self.groupBox_2)
        self.label.setGeometry(QtCore.QRect(10, 10, 371, 360))
        self.label.setText("")
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "BIOT "))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

and below is the code for app.py which handles all the logic part:以下是处理所有逻辑部分的app.py的代码:

import sys
import cv2
import os
import imutils
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtGui import QImage
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QTimer
from ui.gui import Ui_MainWindow


curr_path = os.path.dirname(os.path.abspath(__file__))


class ROCKET(QMainWindow, Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.cap = cv2.VideoCapture(1)
        self.face_detect = cv2.CascadeClassifier(os.path.join(curr_path, 'models', 'haarcascade_frontalface_default.xml'))

        self.timer = QTimer()
        self.timer.timeout.connect(self.view_cam)
        self.timer.start(20)
        self.ui.pushButton.setText("Stop")

    def __del__(self):
        self.timer.stop()
        self.cap.release()
        self.ui.pushButton.setText("Start")

    def view_cam(self):

        ret, image = self.cap.read()
        image = imutils.resize(image, width=371, height=360)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
        height, width, channel = image.shape
        faces = self.face_detect.detectMultiScale(gray, 1.3, 5)
        for (x, y, width, height) in faces:
            print("face detected")
            cv2.rectangle(image, (x, y), (x + width, y + height), (255, 0, 0), 2)
        step = channel * width
        qImg = QImage(image.data, width, height, step, QImage.Format_RGB888)
        self.ui.label.setPixmap(QPixmap.fromImage(qImg))


app = QApplication(sys.argv)
main_window = ROCKET()
main_window.show()
sys.exit(app.exec_())

as you can see in the above code, I have imported cascade classifier in __init__ and I have also started a timer which is connected to view_cam function.正如您在上面的代码中看到的,我在__init__中导入了级联分类器,并且我还启动了一个连接到view_cam function 的计时器。 In view_cam function, I am reading the frames, detecting and displaying the result.view_cam function 中,我正在读取帧,检测并显示结果。 The problem here is that as soon as it starts detecting the faces, it should draw the bounding box rectangle across the face but instead of that, it looks like below:这里的问题是,一旦它开始检测人脸,它应该在人脸上绘制边界框矩形,但它看起来像下面这样:

在此处输入图像描述

When there is no face, it normally shows the live frame and works fine but as soon as the face is detected, it starts showing above zig zag kind of lines.当没有人脸时,它通常会显示实时帧并且工作正常,但是一旦检测到人脸,它就会开始显示锯齿形以上的线条。 I am not very expert in Qt .我不是Qt方面的专家。 Can anyone please guide me here as to what I am doing.任何人都可以在这里指导我我在做什么。 Please help.请帮忙。 Thanks (Please ignore stop button, its not doing anything)谢谢(请忽略停止按钮,它没有做任何事情)

The problem is that the memoryview (image.data) changes when the image is modified when using cv2.rectangle, that can be seen if the following comparison is made throwing an AssertionError :问题是当使用 cv2.rectangle 修改图像时 memoryview (image.data) 会发生变化,如果进行以下比较并抛出AssertionError可以看出这一点:

last_mv = image.data
for (x, y, width, height) in faces:
    print("face detected")
    cv2.rectangle(image, (x, y), (x + width, y + height), (255, 0, 0), 2)
    current_mv = image.data
    assert last_mv == current_mv

And changing the memoryview also changes the shape that is synchronized with height, width, channel, and you can check that with:并且更改内存视图也会更改与高度、宽度、通道同步的形状,您可以通过以下方式检查:

height, width, channel = image.shape
print("before", height, width, channel)

faces = self.face_detect.detectMultiScale(gray, 1.3, 5)

for (x, y, width, height) in faces:
    print("face detected")
    cv2.rectangle(image, (x, y), (x + width, y + height), (255, 0, 0), 2)

step = channel * width
print("after", height, width, channel)

Output: Output:

before 208 371 3
face detected
after 112 112 3
before 208 371 3
face detected
after 110 110 3
before 208 371 3
face detected
after 108 108 3

As you can see the shape before and after cv2.rectangle are different.如您所见, cv2.rectangle 前后的形状不同。

The solution is to calculate the geometry after making all the changes.解决方案是在进行所有更改后计算几何形状。

def view_cam(self):
    ret, image = self.cap.read()
    image = imutils.resize(image, width=371, height=360)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    faces = self.face_detect.detectMultiScale(gray, 1.3, 5)

    for (x, y, width, height) in faces:
        cv2.rectangle(image, (x, y), (x + width, y + height), (255, 0, 0), 2)

    height, width, channel = image.shape
    step = channel * width
    qImg = QImage(image.data, width, height, step, QImage.Format_RGB888)
    self.ui.label.setPixmap(QPixmap.fromImage(qImg))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM