Integrating with Qt (PyQt/PySide)
Relevant source files
The following files were used as context for generating this wiki page:
The picamera2 library provides extensive support for integration with Qt-based graphical user interfaces, allowing developers to embed a live camera preview directly within their applications. This is achieved through dedicated Qt widgets that handle the rendering of the camera feed. The library offers multiple implementations to suit different performance needs and dependencies, and supports various Qt bindings including PyQt5, PyQt6, PySide2, and PySide6.
There are two primary widget implementations for camera previews: QGlPicamera2, which uses OpenGL for high-performance, zero-copy rendering, and QPicamera2, a CPU-based renderer that offers broader compatibility. These components enable the creation of complex applications with real-time camera control and display, as demonstrated by the examples in the apps/ directory.
Sources: README.md, CHANGELOG.md:21-24
Core Components and Architecture
The Qt integration is built around a set of QWidget subclasses that can be seamlessly included in any Qt application layout. The choice of widget depends on the desired performance and available system dependencies.
Sources: picamera2/previews/q_gl_picamera2.py, picamera2/previews/q_picamera2.py
Widget Implementations
The library provides two main widgets for displaying the camera preview.
| Feature | QGlPicamera2 | QPicamera2 |
|---|---|---|
| Base Class | QWidget | QGraphicsView |
| Rendering | OpenGL (EGL) | CPU (QPixmap) |
| Performance | High (zero-copy DMA-buf) | Moderate |
| Dependencies | pyopengl | numpy, cv2 (for YUV) |
| Key File | q_gl_picamera2.py | q_picamera2.py |
Sources: picamera2/previews/q_gl_picamera2.py:84-86, picamera2/previews/q_picamera2.py:38-40, picamera2/previews/q_picamera2.py:199-206
QGlPicamera2: OpenGL-based Rendering
This is the recommended and most performant preview widget. It leverages EGL and the GL_OES_EGL_image_external extension to render camera frames directly from DMA buffers (dma-bufs) onto a texture. This "zero-copy" approach avoids transferring image data between the CPU and GPU, resulting in minimal overhead and high frame rates. It is ideal for applications requiring a smooth, real-time preview.
The widget initializes an EGL context and creates a GL_TEXTURE_EXTERNAL_OES texture for each camera buffer. When a new frame is available, it binds the corresponding texture and draws it using a simple GLSL shader program.
Sources: picamera2/previews/q_gl_picamera2.py:20-23, picamera2/previews/q_gl_picamera2.py:214-256
QPicamera2: CPU-based Rendering
This widget is based on QGraphicsView and renders frames on the CPU. When a frame arrives, it is converted into a NumPy array using completed_request.make_array(). This array is then used to create a QImage, which is converted to a QPixmap and displayed in a QGraphicsScene.
While easier to set up and with fewer dependencies (besides numpy), this method involves copying the image data to the CPU, which can be less efficient than the OpenGL approach, especially at high resolutions or frame rates. For YUV formats (YUV420, YUYV), it relies on the cv2 (OpenCV) library for color conversion.
Sources: picamera2/previews/q_picamera2.py:199-206, picamera2/previews/q_picamera2.py:223-230
Qt Binding Compatibility
The library dynamically adapts to the available Qt binding (PyQt5, PyQt6, PySide2, PySide6) using factory functions like _get_qglpicamera2. This ensures that the correct Qt modules are imported at runtime, making the preview widgets compatible across different environments without code changes. The CHANGELOG.md notes that support for PySide2, PySide6, and PyQt6 was added in version 0.3.26.
The following diagram illustrates the class hierarchy for the Qt preview widgets.
This diagram shows the inheritance structure of the main Qt integration classes.
Sources: picamera2/previews/qt_previews.py:13-16, picamera2/previews/q_gl_picamera2.py:84, picamera2/previews/q_picamera2.py:38, CHANGELOG.md:23-24, tests/app_test_pyqt6.py, tests/app_test_pyside6.py
Rendering and Event Handling
The preview widgets integrate with the picamera2 event system and the Qt event loop to render frames and handle asynchronous operations.
Frame Rendering Pipeline
When picamera2 has a new frame ready, it notifies the widget via a pipe. A QSocketNotifier listens for activity on this pipe and triggers the handle_requests slot, which in turn calls render_request to draw the new frame.
The following diagram shows the sequence for rendering a frame with QGlPicamera2.
This diagram illustrates the zero-copy rendering process using DMA-buf textures in QGlPicamera2.
Sources: picamera2/previews/q_gl_picamera2.py:126-129, picamera2/previews/q_gl_picamera2.py:326-330
The QPicamera2 widget follows a similar notification pattern but uses a CPU-based rendering path.
This diagram shows the CPU-based rendering path where image data is copied and converted into a QPixmap.
Sources: picamera2/previews/q_picamera2.py:73-76, picamera2/previews/q_picamera2.py:199-230
Asynchronous Operations with Signals and Slots
The Qt widgets are designed to work with picamera2's asynchronous operations, such as capturing a file. The widgets define a done_signal that is emitted when an asynchronous job is complete.
This is achieved by passing the widget's signal_done method as the signal_function to a picamera2 capture method. When the capture finishes, picamera2 calls signal_done, which emits the done_signal with the job object. A slot connected to this signal can then safely interact with the GUI, for example, by re-enabling a button.
The following diagram shows the flow for an asynchronous capture.
This sequence demonstrates how Qt's signal/slot mechanism is used for handling asynchronous camera operations.
Sources: apps/app_capture2.py:23-26, apps/app_capture2.py:29-32, picamera2/previews/q_gl_picamera2.py:85, picamera2/previews/q_gl_picamera2.py:134-135
Usage and Examples
Basic Instantiation
To use a preview widget, instantiate it with a Picamera2 object and add it to a Qt layout.
# From apps/app_capture2.py
picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
app = QApplication([])
# Instantiate the widget
qpicamera2 = QGlPicamera2(picam2, width=800, height=600, keep_ar=False)
# Set up layout
button = QPushButton("Click to capture JPEG")
window = QWidget()
layout_h = QHBoxLayout()
layout_h.addWidget(qpicamera2)
layout_h.addWidget(button)
window.setLayout(layout_h)
picam2.start()
window.show()
app.exec()
Sources: apps/app_capture2.py:18-20, apps/app_capture2.py:35-47
Key Parameters and Methods
The preview widgets share a common set of parameters and methods for basic control.
__init__ Parameters
| Parameter | Type | Description |
|---|---|---|
picam2 | Picamera2 | The Picamera2 instance to display. |
width | int | Initial width of the widget. |
height | int | Initial height of the widget. |
bg_colour | tuple | Background color as an (R, G, B) tuple. |
keep_ar | bool | Whether to maintain the image aspect ratio. |
transform | libcamera.Transform | An initial transform to apply (flip/rotate). |
Sources: picamera2/previews/q_gl_picamera2.py:86-88, picamera2/previews/q_picamera2.py:41-43
Public Methods
| Method | Description |
|---|---|
set_overlay(overlay) | Displays a NumPy array as an overlay on top of the camera feed. The overlay should be an RGBA image. |
cleanup() | Releases all resources associated with the preview. Called automatically when the widget is destroyed. |
Sources: picamera2/previews/q_gl_picamera2.py:284-286, picamera2/previews/q_picamera2.py:118-120, picamera2/previews/q_gl_picamera2.py:110-112, picamera2/previews/q_picamera2.py:80-82
Advanced Application: app_full.py
The apps/app_full.py file provides a comprehensive demonstration of the Qt integration capabilities. It builds a full-featured camera application with controls for:
- Switching between still photo and video recording modes.
- Adjusting image parameters like saturation, contrast, and sharpness.
- Controlling AEC (Auto Exposure Control) and AWB (Auto White Balance) settings.
- Digital pan and zoom via a
ScalerCropcontrol widget. - Displaying real-time metadata from the camera.
- Asynchronous still image capture and video encoding.
This application serves as an excellent reference for building advanced camera GUIs with picamera2.
Sources: apps/app_full.py
Summary
The picamera2 library offers a powerful and flexible way to integrate camera functionality into Qt applications. By providing both a high-performance OpenGL-based widget (QGlPicamera2) and a more compatible CPU-based alternative (QPicamera2), it caters to a wide range of use cases. The seamless integration with Qt's signal/slot mechanism allows for responsive and robust applications that can handle asynchronous camera operations without blocking the GUI. The included example applications provide a solid foundation for developers to build their own custom camera software.