Python QT5 - 多进程 OpenCV 网络摄像头和 Requests.Get
Posted
技术标签:
【中文标题】Python QT5 - 多进程 OpenCV 网络摄像头和 Requests.Get【英文标题】:Python QT5 - Multiprocess OpenCV Webcam & Requests.Get 【发布时间】:2020-06-09 12:46:00 【问题描述】:我是多处理的新手,我正在尝试在 PyQT5 中同时查看我的网络摄像头和发出 requests.get。 当前的结果是每次发出 get 请求时视频都会卡顿 - 这似乎没什么大不了的,但重要的是每秒都会发出流畅的视频。对于更复杂的 Post 请求(响应时间长达 5 秒),视频看起来基本冻结。
所以预期的结果是我有一个黄油般流畅的视频,而每秒钟都在并行发出一个获取请求。
我知道这与我按照 link 调用进程的方式有关:
p1 = Process(target=self.start_webcam())
p2 = Process(target=self.start_web_req())
应该是:
p1 = Process(target=self.start_webcam)
p2 = Process(target=self.start_web_req)
但我收到此错误:
TypeError: cannot pickle 'Ui_MainWindow' object
这是我下面的代码。
您有什么想法、建议和答案来确保视频流畅,同时提出获取请求?
谢谢你!
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget,QTableWidgetItem, QDialog
import pandas as pd
from PyQt5.QtCore import QTimer, QSize
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.uic import loadUi
import PIL
from PIL import Image
import requests
import sys
import cv2
import numpy as np
class Ui_MainWindow(QWidget):
def setupUi(self, MainWindow):
MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
MainWindow.setGeometry(0, 30, 800, 480) # x,y,w,h
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
# Camera Label
self.imgLabel = QtWidgets.QLabel(self.centralwidget)
self.imgLabel.setGeometry(QtCore.QRect(0, 0, 600, 480))
self.imgLabel.setFrameShape(QtWidgets.QFrame.Box)
self.imgLabel.setObjectName("imgLabel")
MainWindow.setCentralWidget(self.centralwidget)
# Initiate start_webcam
p1 = Process(target=self.start_webcam())
p1.start()
# Initiate start_web_req
p2 = Process(target=self.start_web_req())
p2.start()
def start_webcam(self):
self.capture=cv2.VideoCapture(0)
self.capture.set(cv2.CAP_PROP_FRAME_WIDTH,600)
self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT,480)
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_frame)
self.timer.start(5)
def update_frame(self):
ret,frame=self.capture.read()
self.cv2_im=frame
self.pil_im = Image.fromarray(self.cv2_im)
self.processedImage=self.cv2_im
self.display_image(1)
def display_image(self, window=1):
qformat = QImage.Format_Indexed8
if len(self.processedImage.shape) == 3: # rows[0],cols[1],channels[2]
if (self.processedImage.shape[2]) == 4:
qformat = QImage.Format_RGBA8888
else:
qformat = QImage.Format_RGB888
img = QImage(self.processedImage, self.processedImage.shape[1], self.processedImage.shape[0],
self.processedImage.strides[0], qformat)
# BGR > RGB
img = img.rgbSwapped()
if window == 1:
self.imgLabel.setPixmap(QPixmap.fromImage(img))
self.imgLabel.setScaledContents(True)
if window == 2:
self.processedLabel.setPixmap(QPixmap.fromImage(img))
self.processedLabel.setScaledContents(True)
def start_web_req(self):
self.timer = QTimer(self)
self.timer.timeout.connect(self.web_req)
self.timer.start(1000)
def web_req(self):
res = requests.get('https://www.google.com.au')
print(res)
def appExec(self):
app.exec_()
self.timer.stop()
self.capture.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(ui.appExec())
【问题讨论】:
1) “进程”要求类是pickleable,但小部件不是。 2)我没有看到在另一个进程中执行相机的启动或停止会提高性能。 @eyllanesc,伙计,非常感谢您提供的大量信息!以新鲜的眼光醒来并听取了您的建议 - 我将“开始”和“停止”函数合并在一起,这帮助我意识到使用 QTimer 调用函数不是做事的合适方式,因此我将其更新为线程。计时器,它工作得很好。 【参考方案1】:在eyllanesc的帮助下,我解决了。
问题出在 start_webcam() 和 start_web_req() - 我有 QTimers 分别调用 update_frame() 和 web_req()。我删除了那些启动函数并将 threading.Timer 直接放在 update_frame() 和 web_req() 中,这解决了我的视频断断续续的问题。
完整代码如下。
from multiprocessing import Process
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget,QTableWidgetItem, QDialog
import pandas as pd
from PyQt5.QtCore import QTimer, QSize
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.uic import loadUi
import PIL
from PIL import Image
import requests
import sys
import cv2
import numpy as np
class Ui_MainWindow(QWidget):
def setupUi(self, MainWindow):
MainWindow.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
MainWindow.setGeometry(0, 30, 800, 480) # x,y,w,h
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
# Camera Label
self.imgLabel = QtWidgets.QLabel(self.centralwidget)
self.imgLabel.setGeometry(QtCore.QRect(0, 0, 600, 480))
self.imgLabel.setFrameShape(QtWidgets.QFrame.Box)
self.imgLabel.setObjectName("imgLabel")
MainWindow.setCentralWidget(self.centralwidget)
self.capture=cv2.VideoCapture(1)
self.capture.set(cv2.CAP_PROP_FRAME_WIDTH,600)
self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT,480)
# Initiate start_webcam
p1 = Process(target=self.update_frame())
p1.start()
# Initiate start_web_req
p2 = Process(target=self.web_req())
p2.start()
def update_frame(self):
self.t1 = threading.Timer(0.01, self.update_frame).start()
ret,frame=self.capture.read()
self.cv2_im=frame
self.pil_im = Image.fromarray(self.cv2_im)
self.processedImage=self.cv2_im
self.display_image(1)
def display_image(self, window=1):
qformat = QImage.Format_Indexed8
if len(self.processedImage.shape) == 3: # rows[0],cols[1],channels[2]
if (self.processedImage.shape[2]) == 4:
qformat = QImage.Format_RGBA8888
else:
qformat = QImage.Format_RGB888
img = QImage(self.processedImage, self.processedImage.shape[1], self.processedImage.shape[0],
self.processedImage.strides[0], qformat)
# BGR > RGB
img = img.rgbSwapped()
if window == 1:
self.imgLabel.setPixmap(QPixmap.fromImage(img))
self.imgLabel.setScaledContents(True)
if window == 2:
self.processedLabel.setPixmap(QPixmap.fromImage(img))
self.processedLabel.setScaledContents(True)
def web_req(self):
self.t2 = threading.Timer(1.0, self.web_req).start()
res = requests.get('https://www.google.com.au')
print(res)
def appExec(self):
app.exec_()
self.t1 = None
self.t2 = None
self.capture.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(ui.appExec())
【讨论】:
如果该代码有效,则不需要处理,请删除# Initiate start_webcam p1 = Process(target=self.update_frame()) p1.start() # Initiate start_web_req p2 = Process(target=self.web_req()) p2.start()
并使用 self.update_frame() self.web_req()
更改它以上是关于Python QT5 - 多进程 OpenCV 网络摄像头和 Requests.Get的主要内容,如果未能解决你的问题,请参考以下文章