2016-11-03 76 views
0

opencvを使ってカメラからWebカメラデータを取得しようとしていて、それをPyQt GUIに表示しようとしています。これまでTkinterを使って、Tkinterメインウィンドウのループに.after関数でアクセスしました。しかし、PyQtは同じユーザビリティを持っていないようで、別のループをアプリケーションで実行させるためには別のスレッドを使う必要があります。だから、これは私が出ているものです:OpenCVからPyQtへのWebカメラ映像の取得

import sys 
import cv2 
from PyQt4 import QtGui 
from PyQt4 import QtCore 
from PyQt4.QtGui import QImage 
import time 

class VideoCapture(QtGui.QWidget): 
    def __init__(self, parent = None): 
     QtGui.QWidget().__init__() 
     self.camera = None 
     self.camera = cv2.VideoCapture(0) 
     b, self.frame = self.camera.read() 
     self.label = QtGui.QLabel() 
     self.workThread = WorkThread(self) 
     self.connect(self.workThread, QtCore.SIGNAL('update_Camera'), self.draw) 
     self.workThread.start() 

    def closeEvent(self, event): 
     self.workThread.stop() 

    def draw(self): 
     print "I should Redraw" 
     height, width, channel = self.frame.shape 
     bpl = 3 * width 
     self.qImg = QImage(self.frame.data, width, height, bpl, QImage.Format_RGB888) 
     pix = QtGui.QPixmap(self.qImg) 
     self.label.setPixmap(pix) 
     self.label.show() 



class WorkThread(QtCore.QThread): 
    def __init__(self, parent): 
     QtCore.QThread.__init__(self) 
     self.parent = parent 

    def __del__(self): 
     self.wait() 

    def run(self): 
     while True: 
      self.emit(QtCore.SIGNAL('update_Camera'), "_") 
     self.terminate() 


app = QtGui.QApplication(sys.argv) 
test = VideoCapture() 
test.draw() 

sys.exit(app.exec_()) 

私の考えは簡単だった:私はちょうど更新するメインアプリケーションを伝える信号を発するループでスレッドを作成します。 (当然のことながら、私は真のループを持つスレッドを望んでいませんが、私は便宜のために使用しています。ただし、draw()関数が呼び出されないため、シグナルは登録されていないようです。私は間違って何をやっているの?

答えて

0

私はOpenCVについて何も知らないので、私は問題を推測することしかできません。

私はあなたがビデオデータを一度しか読んでいないと思います。ビデオストリームの場合、データを継続的に読み取って解釈する必要があります。

import sys 
import cv2 
from PyQt4 import QtGui 
from PyQt4 import QtCore 
from PyQt4.QtGui import QImage 
import time 

class VideoCapture(QtGui.QWidget): 

    update_video = QtCore.pyqtSignal() 

    def __init__(self, parent = None): 
     QtGui.QWidget().__init__() 
     self.camera = cv2.VideoCapture(0) 
     self.label = QtGui.QLabel() 
     layout = QtGui.QHBoxLayout() 
     self.setLayout(layout) 
     layout.addWidget(self.label) 

     # Create the worker Thread 
     self.workThread = WorkThread(self.readVideo) 
     self.update_video.connect(self.draw) 

    def start(self): 
     self.workerThread.start() 

    def stop(self): 
     self.workThread.alive = False 
     self.workThread.stop() 

    def readVideo(self): 
     """Note this method is executed in a thread. No drawing can happen in a thread. Emit a signal to draw items.""" 
     b, self.frame = self.camera.read() 
     self.update_video.emit() # Signals are slow this may happen too fast 

    def closeEvent(self, event): 
     self.stop() 
     return QtGui.QWidget.closeEvent(self, event) 
     #self.workThread.alive = False 
     #self.workThread.stop() 

    def draw(self): 
     print "I should Redraw" 
     height, width, channel = self.frame.shape 
     bpl = 3 * width 
     qImg = QImage(self.frame.data, width, height, bpl, QImage.Format_RGB888) 
     pix = QtGui.QPixmap(qImg) 
     self.label.setPixmap(pix) 
     # self.label.show() # The label is now a part of the widget layout 



class WorkThread(QtCore.QThread): 
    def __init__(self, target=None, args=(), kwargs={}): 
     QtCore.QThread.__init__(self) 
     # I don't know how Qt's threads work, so I am treating it like a python thread 
     self.target = target 
     self.args = args 
     self.kwargs = kwargs 
     self.alive = True 

    def run(self): 
     while self.alive: 
      self.target(*self.args, **self.kwargs) 


app = QtGui.QApplication(sys.argv) 
test = VideoCapture() 
test.start() 

sys.exit(app.exec_()) 

1秒間に何回も更新されているだけなので、おそらくスレッドではなくタイマーを使用できます。タイマーはおそらくより簡単で安全に使用できます。

import sys 
import cv2 
from PyQt4 import QtGui 
from PyQt4 import QtCore 
from PyQt4.QtGui import QImage 
import time 

class VideoCapture(QtGui.QWidget): 
    def __init__(self, parent = None): 
     QtGui.QWidget().__init__() 
     self.camera = cv2.VideoCapture(0) 
     self.label = QtGui.QLabel() 
     layout = QtGui.QHBoxLayout() 
     self.setLayout(layout) 
     layout.addWidget(self.label) 

     # Create the worker Thread 
     self.timer= QtCore.QTimer() 
     self.timer.setInterval(300) 
     self.timer.timeout.connect(self.draw_camera) 

    def start(self): 
     self.timer.start() 

    def stop(self): 
     self.timer.stop() 

    def draw_camera(self): 
     """You can draw in a timer, so just read the data and draw however fast you want.""" 
     print "I should Redraw" 
     b, frame = self.camera.read() 
     height, width, channel = frame.shape 
     bpl = 3 * width 
     qImg = QImage(frame.data, width, height, bpl, QImage.Format_RGB888) 
     pix = QtGui.QPixmap(qImg) 
     self.label.setPixmap(pix) 

    def closeEvent(self, event): 
     self.stop() 
     return QtGui.QWidget.closeEvent(self, event) 

app = QtGui.QApplication(sys.argv) 
test = VideoCapture() 
test.start() 

sys.exit(app.exec_()) 
0

私はあなたの問題に非常によく似たことに取り組んできました。私はあなたのコードを修正し、私のWindows PCでそれをテストしました。

ここで重要な点は、WorkThreadにcv2カメラオブジェクトを配置し、run()メソッドでメインwhileループの各フレームを読み込み、最後にQWidgetオブジェクトにイメージを表示して表示することです。このようにして、イメージのキャプチャと表示を連続して繰り返します。

import sys 
import cv2 
from PyQt4 import QtGui 
from PyQt4 import QtCore 
from PyQt4.QtGui import QImage 
import time 

class VideoCapture(QtGui.QWidget): 
    def __init__(self, parent = None): 
     # Use super() to call __init__() methods in the parent classes 
     super(VideoCapture, self).__init__() 

     # The instantiated QLabel object should belong to the 'self' QWidget object 
     self.label = QtGui.QLabel(self) # <- So put 'self' in the parenthesis 

     # Set the QLabel geometry to fit the image dimension (640, 480) 
     # The top left corner (0, 0) is the position within the QWidget main window 
     self.label.setGeometry(0,0,640,480) 

     # Instantiate a QThread object. No need to pass in the parent QWidget object. 
     self.workThread = WorkThread() 

     # Connect signal from self.workThread to the slot self.draw 
     self.connect(self.workThread, QtCore.SIGNAL('update_Camera'), self.draw) 

     self.workThread.start() 

    def closeEvent(self, event): 
     self.workThread.stop() 
     event.accept() 

    def draw(self, img): 
     print "I should Redraw" 
     height, width, channel = img.shape 
     bpl = 3 * width 
     self.qImg = QImage(img, width, height, bpl, QImage.Format_RGB888) 
     pix = QtGui.QPixmap(self.qImg) 
     self.label.setPixmap(pix) 
     self.label.show() 


class WorkThread(QtCore.QThread): 
    def __init__(self): 
     # Use super() to call __init__() methods in the parent classes 
     super(WorkThread, self).__init__() 

     # Place the camera object in the WorkThread 
     self.camera = cv2.VideoCapture(0) 

     # The boolean variable to break the while loop in self.run() method 
     self.running = True 

    def run(self): 
     while self.running: 

      # Read one frame 
      b, self.frame = self.camera.read() 

      # Emit self.frame to the QWidget object 
      self.emit(QtCore.SIGNAL('update_Camera'), self.frame) 

    def stop(self): 
     # Terminate the while loop in self.run() method 
     self.running = False 


app = QtGui.QApplication(sys.argv) 
video_capture_widget = VideoCapture() 
video_capture_widget.show() 
sys.exit(app.exec_()) 
関連する問題