Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Creating a Camera Application using Pyqt5
PyQt5 is one of the most popular GUI libraries available for Python, allowing developers to create desktop applications with ease. In this tutorial, we will walk through the process of creating a camera application using PyQt5. The camera application will allow users to view live camera feed, capture photos, and save them to disk.
What are the advantages of PyQt5?
PyQt5 is a Python binding for the popular cross-platform GUI toolkit, Qt. Here are some key advantages of PyQt5 ?
Cross-platform ? PyQt5 applications can run on multiple platforms like Windows, Mac OS X, and Linux.
Rich set of widgets ? PyQt5 comes with a comprehensive collection of widgets including buttons, labels, text boxes, tables, and many more for creating complex graphical user interfaces.
High performance ? PyQt5 provides high-performance graphical rendering through OpenGL integration, enabling smooth and responsive GUIs.
Easy to learn ? Built on top of Python, PyQt5 inherits Python's simplicity and ease of use.
Open source ? PyQt5 is free and open-source with an active development community.
Prerequisites
Before starting, ensure you have the following installed ?
Python 3.6 or higher
A camera connected to your system (built-in or external webcam)
An IDE like VS Code, PyCharm, or any text editor
Installing Required Libraries
Install the necessary libraries using pip ?
pip install PyQt5 pip install opencv-python pip install numpy
Creating the Camera Thread
First, we'll create a separate thread to handle camera operations. This prevents the GUI from freezing while capturing video feed ?
import sys
import cv2
import numpy as np
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QPushButton, QWidget, QFileDialog
class CameraThread(QThread):
image_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
self.capture = None
self.frame = None
self.running = False
def run(self):
self.capture = cv2.VideoCapture(0)
self.running = True
while self.running:
ret, frame = self.capture.read()
if ret:
self.frame = frame.copy()
self.image_signal.emit(frame)
if self.capture:
self.capture.release()
def stop(self):
self.running = False
self.quit()
self.wait()
Creating the Main Window
Now we'll create the main application window with camera display and capture functionality ?
class CameraApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt5 Camera Application")
self.setGeometry(100, 100, 800, 600)
# Create central widget and layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
# Create label for video display
self.video_label = QLabel()
self.video_label.setMinimumSize(640, 480)
self.video_label.setStyleSheet("border: 1px solid black")
layout.addWidget(self.video_label)
# Create capture button
self.capture_button = QPushButton("Capture Photo")
self.capture_button.clicked.connect(self.capture_photo)
layout.addWidget(self.capture_button)
# Initialize camera thread
self.camera_thread = CameraThread()
self.camera_thread.image_signal.connect(self.update_frame)
self.camera_thread.start()
def update_frame(self, frame):
"""Update the video display with new frame"""
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_frame.shape
bytes_per_line = ch * w
qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
scaled_pixmap = QPixmap.fromImage(qt_image).scaled(
self.video_label.size(), aspectRatioMode=1)
self.video_label.setPixmap(scaled_pixmap)
def capture_photo(self):
"""Capture and save current frame"""
if self.camera_thread.frame is not None:
filename, _ = QFileDialog.getSaveFileName(
self, "Save Photo", "photo.jpg", "JPEG files (*.jpg)")
if filename:
cv2.imwrite(filename, self.camera_thread.frame)
print(f"Photo saved as {filename}")
def closeEvent(self, event):
"""Handle application close event"""
self.camera_thread.stop()
event.accept()
Complete Application
Here's the complete camera application code ?
import sys
import cv2
import numpy as np
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QPushButton, QWidget, QFileDialog
class CameraThread(QThread):
image_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
self.capture = None
self.frame = None
self.running = False
def run(self):
self.capture = cv2.VideoCapture(0)
self.running = True
while self.running:
ret, frame = self.capture.read()
if ret:
self.frame = frame.copy()
self.image_signal.emit(frame)
if self.capture:
self.capture.release()
def stop(self):
self.running = False
self.quit()
self.wait()
class CameraApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt5 Camera Application")
self.setGeometry(100, 100, 800, 600)
central_widget = QWidget()
self.setCentralWidget(central_widget)
layout = QVBoxLayout(central_widget)
self.video_label = QLabel()
self.video_label.setMinimumSize(640, 480)
self.video_label.setStyleSheet("border: 1px solid black")
layout.addWidget(self.video_label)
self.capture_button = QPushButton("Capture Photo")
self.capture_button.clicked.connect(self.capture_photo)
layout.addWidget(self.capture_button)
self.camera_thread = CameraThread()
self.camera_thread.image_signal.connect(self.update_frame)
self.camera_thread.start()
def update_frame(self, frame):
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_frame.shape
bytes_per_line = ch * w
qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
scaled_pixmap = QPixmap.fromImage(qt_image).scaled(
self.video_label.size(), aspectRatioMode=1)
self.video_label.setPixmap(scaled_pixmap)
def capture_photo(self):
if self.camera_thread.frame is not None:
filename, _ = QFileDialog.getSaveFileName(
self, "Save Photo", "photo.jpg", "JPEG files (*.jpg)")
if filename:
cv2.imwrite(filename, self.camera_thread.frame)
print(f"Photo saved as {filename}")
def closeEvent(self, event):
self.camera_thread.stop()
event.accept()
def main():
app = QApplication(sys.argv)
window = CameraApp()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Running the Application
To run the application, save the code to a file (e.g., camera_app.py) and execute ?
python camera_app.py
Common Issues and Solutions
Camera not detected ? Ensure your camera is properly connected and not being used by another application.
Permission denied ? Check system settings to ensure the application has camera access permissions.
Import errors ? Verify all required libraries are installed correctly.
Black screen ? Try changing the camera index from 0 to 1 in
cv2.VideoCapture(0).
Conclusion
This PyQt5 camera application demonstrates how to integrate OpenCV with PyQt5 to create a functional desktop camera app. The application uses threading to handle video capture efficiently while maintaining a responsive GUI. You can extend this basic application by adding features like video recording, filters, or multiple camera support.
