Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # USB camera display using PyQt and OpenCV, from iosoft.blog
- # Copyright (c) Jeremy P Bentham 2019
- # Please credit iosoft.blog if you use the information or software in it
- VERSION = "Cam_display v0.10"
- import sys, time, threading, cv2
- try:
- from PyQt5.QtCore import Qt
- pyqt5 = True
- except:
- pyqt5 = False
- if pyqt5:
- from PyQt5.QtCore import QTimer, QPoint, pyqtSignal
- from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QLabel
- from PyQt5.QtWidgets import QWidget, QAction, QVBoxLayout, QHBoxLayout
- from PyQt5.QtGui import QFont, QPainter, QImage, QTextCursor
- else:
- from PyQt4.QtCore import Qt, pyqtSignal, QTimer, QPoint
- from PyQt4.QtGui import QApplication, QMainWindow, QTextEdit, QLabel
- from PyQt4.QtGui import QWidget, QAction, QVBoxLayout, QHBoxLayout
- from PyQt4.QtGui import QFont, QPainter, QImage, QTextCursor
- try:
- import Queue as Queue
- except:
- import queue as Queue
- IMG_SIZE = 1280,720 # 640,480 or 1280,720 or 1920,1080
- IMG_FORMAT = QImage.Format_RGB888
- DISP_SCALE = 2 # Scaling factor for display image
- DISP_MSEC = 50 # Delay between display cycles
- # CAP_API = cv2.CAP_ANY # API: CAP_ANY or CAP_DSHOW etc...
- # CAP_API = cv2.CAP_AVFOUNDATION # API: CAP_ANY or CAP_DSHOW etc...
- EXPOSURE = 0 # Zero for automatic exposure
- TEXT_FONT = QFont("Courier", 10)
- camera_num = 2 # Default camera (first in list)
- image_queue = Queue.Queue() # Queue to hold images
- capturing = True # Flag to indicate capturing
- # Grab images from the camera (separate thread)
- def grab_images(cam_num, queue):
- # cap = cv2.VideoCapture(cam_num-1 + CAP_API)
- cap = cv2.VideoCapture(cam_num-1)
- # we capture the first frame for the camera to adjust itself to the exposure
- ret_val , cap_for_exposure = cap.read()
- # cap.set(cv2.CAP_PROP_FRAME_WIDTH, IMG_SIZE[0])
- # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, IMG_SIZE[1])
- # if EXPOSURE:
- # cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)
- # cap.set(cv2.CAP_PROP_EXPOSURE, EXPOSURE)
- # else:
- # cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)
- cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25)
- cap.set(cv2.CAP_PROP_EXPOSURE , 0.001)
- while capturing:
- if cap.grab():
- retval, image = cap.retrieve(0)
- if image is not None and queue.qsize() < 2:
- queue.put(image)
- else:
- time.sleep(DISP_MSEC / 1000.0)
- else:
- print("Error: can't grab camera image")
- break
- cap.release()
- # Image widget
- class ImageWidget(QWidget):
- def __init__(self, parent=None):
- super(ImageWidget, self).__init__(parent)
- self.image = None
- def setImage(self, image):
- self.image = image
- self.setMinimumSize(image.size())
- self.update()
- def paintEvent(self, event):
- qp = QPainter()
- qp.begin(self)
- if self.image:
- qp.drawImage(QPoint(0, 0), self.image)
- qp.end()
- # Main window
- class MyWindow(QMainWindow):
- text_update = pyqtSignal(str)
- # Create main window
- def __init__(self, parent=None):
- QMainWindow.__init__(self, parent)
- self.central = QWidget(self)
- self.textbox = QTextEdit(self.central)
- self.textbox.setFont(TEXT_FONT)
- self.textbox.setMinimumSize(300, 100)
- self.text_update.connect(self.append_text)
- sys.stdout = self
- print("Camera number %u" % camera_num)
- print("Image size %u x %u" % IMG_SIZE)
- if DISP_SCALE > 1:
- print("Display scale %u:1" % DISP_SCALE)
- self.vlayout = QVBoxLayout() # Window layout
- self.displays = QHBoxLayout()
- self.disp = ImageWidget(self)
- self.displays.addWidget(self.disp)
- self.vlayout.addLayout(self.displays)
- self.label = QLabel(self)
- self.vlayout.addWidget(self.label)
- self.vlayout.addWidget(self.textbox)
- self.central.setLayout(self.vlayout)
- self.setCentralWidget(self.central)
- self.mainMenu = self.menuBar() # Menu bar
- exitAction = QAction('&Exit', self)
- exitAction.setShortcut('Ctrl+Q')
- exitAction.triggered.connect(self.close)
- self.fileMenu = self.mainMenu.addMenu('&File')
- self.fileMenu.addAction(exitAction)
- # Start image capture & display
- def start(self):
- self.timer = QTimer(self) # Timer to trigger display
- self.timer.timeout.connect(lambda:
- self.show_image(image_queue, self.disp, DISP_SCALE))
- self.timer.start(DISP_MSEC)
- self.capture_thread = threading.Thread(target=grab_images,
- args=(camera_num, image_queue))
- self.capture_thread.start() # Thread to grab images
- # Fetch camera image from queue, and display it
- def show_image(self, imageq, display, scale):
- if not imageq.empty():
- image = imageq.get()
- if image is not None and len(image) > 0:
- img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
- self.display_image(img, display, scale)
- # Display an image, reduce size if required
- def display_image(self, img, display, scale=1):
- disp_size = img.shape[1]//scale, img.shape[0]//scale
- disp_bpl = disp_size[0] * 3
- if scale > 1:
- img = cv2.resize(img, disp_size,
- interpolation=cv2.INTER_CUBIC)
- qimg = QImage(img.data, disp_size[0], disp_size[1],
- disp_bpl, IMG_FORMAT)
- display.setImage(qimg)
- # Handle sys.stdout.write: update text display
- def write(self, text):
- self.text_update.emit(str(text))
- def flush(self):
- pass
- # Append to text display
- def append_text(self, text):
- cur = self.textbox.textCursor() # Move cursor to end of text
- cur.movePosition(QTextCursor.End)
- s = str(text)
- while s:
- head,sep,s = s.partition("\n") # Split line at LF
- cur.insertText(head) # Insert text at cursor
- if sep: # New line if LF
- cur.insertBlock()
- self.textbox.setTextCursor(cur) # Update visible cursor
- # Window is closing: stop video capture
- def closeEvent(self, event):
- global capturing
- capturing = False
- self.capture_thread.join()
- if __name__ == '__main__':
- if len(sys.argv) > 1:
- try:
- camera_num = int(sys.argv[1])
- except:
- camera_num = 0
- if camera_num < 1:
- print("Invalid camera number '%s'" % sys.argv[1])
- else:
- app = QApplication(sys.argv)
- win = MyWindow()
- win.show()
- win.setWindowTitle(VERSION)
- win.start()
- sys.exit(app.exec_())
- #EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement