Нужна критика проекта PyQt5 + QThread + OpenCV
Изучаю QThread. Есть рабочий проект c OpenCV. Я его запустил, но у меня при рабочей вэбке и перетаскивании окна по экрану начинает передвигаться это окно не плавно. Хочу услышать мнения специалистов. Какие замечания, как бы Вы его оформили? Правильно ли подобные проекты также делить на три файла? Какие изменения нужны для правильного написания? Хочу увидеть ваши версии.
main.py
import sys
from PyQt5.QtWidgets import QApplication
from views import UI_Window
from models import Camera
if __name__ == '__main__':
camera = Camera(0)
app = QApplication([])
start_window = UI_Window(camera)
start_window.show()
app.exit(app.exec_())
views.py
from PyQt5.QtCore import QThread, QTimer
from PyQt5.QtWidgets import QLabel, QWidget, QPushButton, QVBoxLayout, QApplication, QHBoxLayout, QMessageBox
from PyQt5.QtGui import QPixmap, QImage
from models import Camera
class UI_Window(QWidget):
def __init__(self, camera = None):
super().__init__()
self.camera = camera
print('UI')
# Create a timer.
self.timer = QTimer()
self.timer.timeout.connect(self.nextFrameSlot)
# Create a layout.
layout = QVBoxLayout()
# Add a button
button_layout = QHBoxLayout()
btnCamera = QPushButton("Open camera")
btnCamera.clicked.connect(self.start)
button_layout.addWidget(btnCamera)
layout.addLayout(button_layout)
# Add a label
self.label = QLabel()
self.label.setFixedSize(640, 640)
layout.addWidget(self.label)
# Set the layout
self.setLayout(layout)
self.setWindowTitle("First GUI with QT")
#self.setFixedSize(800, 800)
def start(self):
if not self.camera.open():
print('failure')
msgBox = QMessageBox()
msgBox.setText("Failed to open camera.")
msgBox.exec_()
return
self.timer.start(1000. / 24)
def nextFrameSlot(self):
frame = self.camera.read()
#frame = self.camera.read_gray()
if frame is not None:
image = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
pixmap = QPixmap.fromImage(image)
self.label.setPixmap(pixmap)
class MovieThread(QThread):
def __init__(self, camera):
super().__init__()
self.camera = camera
def run(self):
self.camera.acquire_movie(200)
if __name__ == '__main__':
app = QApplication([])
window = UI_Window()
window.show()
models.py
mport cv2
class Camera:
def __init__(self, camera):
self.camera = camera
self.vp = None
def open(self, width=640, height=480, fps=30):
self.vc = cv2.VideoCapture(self.camera)
self.width = width
self.height = height
self.fps = fps
# vc.set(5, fps) #set FPS
self.vc.set(3, width) # set width
self.vc.set(4, height) # set height
return self.vc.isOpened()
def read(self, negative=False):
rval, frame = self.vc.read()
if frame is not None:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
if negative:
frame = cv2.bitwise_not(frame)
return frame
def read_gray(self, negative=False):
rval, frame = self.vc.read()
if frame is not None:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
if negative:
frame = cv2.bitwise_not(frame)
return frame
Ответы (1 шт):
Автор решения: Владимир
→ Ссылка
Этот код и прост, и окно перемещается плавно при включенной камере.
main.py
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import cv2
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.VBL = QVBoxLayout()
self.FeedLabel = QLabel()
self.VBL.addWidget(self.FeedLabel)
self.CancelBTN = QPushButton("Cancel")
self.CancelBTN.clicked.connect(self.CancelFeed)
self.VBL.addWidget(self.CancelBTN)
self.Worker1 = Worker1()
self.Worker1.start()
self.Worker1.ImageUpdate.connect(self.ImageUpdateSlot)
self.setLayout(self.VBL)
def ImageUpdateSlot(self, Image):
self.FeedLabel.setPixmap(QPixmap.fromImage(Image))
def CancelFeed(self):
self.Worker1.stop()
class Worker1(QThread):
ImageUpdate = pyqtSignal(QImage)
def run(self):
self.ThreadActive = True
Capture = cv2.VideoCapture(0)
while self.ThreadActive:
ret, frame = Capture.read()
if ret:
Image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
FlippedImage = cv2.flip(Image, 1)
ConvertToQtFormat = QImage(FlippedImage.data, FlippedImage.shape[1], FlippedImage.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
def stop(self):
self.ThreadActive = False
self.quit()
if __name__ == "__main__":
App = QApplication(sys.argv)
Root = MainWindow()
Root.show()
sys.exit(App.exec())