Просмотр исходного кода

Merge pull request #79 from cachitas/pyqt-opencv-example

PyQt5+OpenCV example
Thomas Kluyver 8 лет назад
Родитель
Сommit
e33591f145

+ 1 - 0
examples/build_all_examples.py

@@ -9,6 +9,7 @@ example_cfgs = [
     'pygtk/installer.cfg',
     'pygtk_mpl_numpy/installer.cfg',
     'pygi_mpl_numpy/installer.cfg',
+    'pyqt5_opencv/installer.cfg',
 ]
 
 examples_dir = os.path.dirname(os.path.abspath(__file__))

+ 11 - 0
examples/pyqt5_opencv/README.md

@@ -0,0 +1,11 @@
+# Description
+
+This example shows how to include **OpenCV** in a **PyQt5** application
+using **Python 3.5**.
+
+The application requires some sort of camera to display.
+
+### Requirements
+
+- FFMPEG
+- Visual C++ Redistributable for Visual Studio 2015

+ 0 - 0
examples/pyqt5_opencv/app/__init__.py


+ 54 - 0
examples/pyqt5_opencv/app/camera.py

@@ -0,0 +1,54 @@
+from PyQt5.QtCore import pyqtSignal
+from PyQt5.QtCore import QObject
+from PyQt5.QtCore import QTimer
+from PyQt5.QtGui import QImage
+import cv2
+
+
+class CameraDevice(QObject):
+
+    frame_ready = pyqtSignal(QImage)
+
+    def __init__(self, device_id=0):
+        super().__init__()
+        self.capture = cv2.VideoCapture(device_id)
+        self.timer = QTimer()
+
+        if not self.capture.isOpened():
+            raise ValueError("Device not found")
+
+        self.timer.timeout.connect(self.read_frame)
+        self.timer.setInterval(1000 / (self.fps or 30))
+        self.timer.start()
+
+    def __del__(self):
+        self.timer.stop()
+        self.capture.release()
+
+    @property
+    def fps(self):
+        """Frames per second."""
+        return int(self.capture.get(cv2.CAP_PROP_FPS))
+
+    @property
+    def size(self):
+        """Returns the size of the video frames: (width, height)."""
+        width = int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
+        height = int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
+        return (width, height)
+
+    def read_frame(self):
+        """Read frame into QImage and emit it."""
+        success, frame = self.capture.read()
+        if success:
+            img = _convert_array_to_qimage(frame)
+            self.frame_ready.emit(img)
+        else:
+            raise ValueError("Failed to read frame")
+
+
+def _convert_array_to_qimage(a):
+    height, width, channels = a.shape
+    bytes_per_line = channels * width
+    cv2.cvtColor(a, cv2.COLOR_BGR2RGB, a)
+    return QImage(a.data, width, height, bytes_per_line, QImage.Format_RGB888)

+ 44 - 0
examples/pyqt5_opencv/app/main.py

@@ -0,0 +1,44 @@
+import os
+import sys
+from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import QThread
+from PyQt5.QtGui import QImage
+from PyQt5.QtGui import QPixmap
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QMainWindow
+from PyQt5.uic import loadUi
+
+from .camera import CameraDevice
+
+THIS_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+class MainWindow(QMainWindow):
+
+    def __init__(self):
+        super().__init__()
+        self.ui = loadUi(os.path.join(THIS_DIR, 'mainwindow.ui'), self)
+
+        self.thread = QThread()
+
+        try:
+            self.camera = CameraDevice()
+        except ValueError:
+            self.ui.video.setText("Device not found!\n\nIs FFMPEG available?")
+        else:
+            self.camera.frame_ready.connect(self.update_video_label)
+            self.ui.video.setMinimumSize(*self.camera.size)
+            self.camera.moveToThread(self.thread)
+
+    @pyqtSlot(QImage)
+    def update_video_label(self, image):
+        pixmap = QPixmap.fromImage(image)
+        self.ui.video.setPixmap(pixmap)
+        self.ui.video.update()
+
+
+def main():
+    app = QApplication(sys.argv)
+    main_window = MainWindow()
+    main_window.show()
+    sys.exit(app.exec_())

+ 53 - 0
examples/pyqt5_opencv/app/mainwindow.ui

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>PyQt5-OpenCV Example</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="0">
+     <widget class="QLabel" name="video">
+      <property name="styleSheet">
+       <string notr="true">background-color: 'black'; color: 'white'</string>
+      </property>
+      <property name="frameShape">
+       <enum>QFrame::NoFrame</enum>
+      </property>
+      <property name="frameShadow">
+       <enum>QFrame::Plain</enum>
+      </property>
+      <property name="text">
+       <string/>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>400</width>
+     <height>20</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 16 - 0
examples/pyqt5_opencv/installer.cfg

@@ -0,0 +1,16 @@
+[Application]
+name=Camera App (PyQt5)
+version=1.0
+entry_point=app.main:main
+
+[Python]
+version=3.5.2
+bitness=64
+format=bundled
+
+[Include]
+packages=app
+pypi_wheels= PyQt5==5.7
+    sip==4.18.1
+    numpy==1.11.1
+    opencv-python==3.1.0.3