2016-11-03 3 views
0

opencv를 사용하여 카메라에서 웹캠 데이터를 가져 와서 PyQt GUI에 표시하려고합니다. 필자는 Tkinter를 사용하여 Tkinter 메인 윈도우 루프에 .after 기능을 사용하여 액세스했습니다. 그러나 PyQt는 동일한 유용성을 가지지 않는 것 같으며 애플리케이션으로 실행되는 또 다른 루프를 가지기 위해 별도의 스레드를 사용해야한다. 그래서 내가 함께 온 것입니다 :OpenCV에서 PyQt로 웹캠 촬영하기

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_()) 

내 생각은 간단했다 : 난 그냥 업데이트 할 수있는 기본 응용 프로그램을 알리는 신호를 방출하는 루프 스레드를 만듭니다. (당연히 나는 while 루프가있는 스레드를 원하지 않지만이 아이디어가 효과가 있다는 것을 보증 할 수있게되면 그것을 대체하기 위해 계획을 편리하게 사용했습니다.) 그러나 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_()) 

은 당신이 아마 스레드 대신이에 대한 타이머를 사용할 수있는 초당 너무 많은 시간을 업데이트하고 있습니다. 아마도 타이머가 사용하기 쉽고 안전합니다.

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_()) 
관련 문제