Camera Previews
Relevant source files
The following files were used as context for generating this wiki page: - [picamera2/picamera2.py](https://github.com/przkos/picamera2/blob/HEAD/picamera2/picamera2.py) - [picamera2/previews/null_preview.py](https://github.com/przkos/picamera2/blob/HEAD/picamera2/previews/null_preview.py) - [picamera2/previews/drm_preview.py](https://github.com/przkos/picamera2/blob/HEAD/picamera2/previews/drm_preview.py) - [picamera2/previews/q_gl_picamera2.py](https://github.com/przkos/picamera2/blob/HEAD/picamera2/previews/q_gl_picamera2.py) - [apps/app_full.py](https://github.com/przkos/picamera2/blob/HEAD/apps/app_full.py) - [tests/preview_cycle_test.py](https://github.com/przkos/picamera2/blob/HEAD/tests/preview_cycle_test.py)In the picamera2 library, a "preview" is more than just a window showing the camera's output. It is the component responsible for running the main event loop that processes camera frames. When a preview is running, it continuously receives completed frame requests from libcamera, makes them available for processing (e.g., display, encoding, analysis), and then recycles the buffers back to the camera system. This mechanism is essential for the continuous operation of the camera.
The library provides several preview implementations tailored for different environments, from headless operation to integration with graphical user interfaces like Qt or direct rendering to a display. The choice of preview backend determines how and where the camera images are displayed, but the underlying role of driving the camera's event loop remains the same.
Sources: picamera2/picamera2.py:1210-1221, picamera2/previews/null_preview.py:12-24
Core Concepts
Preview Management
The Picamera2 class manages the lifecycle of a preview window. The primary methods for this are start_preview and stop_preview.
start_preview(preview, **kwargs): This method initiates a preview. It can take aPreviewenum member, a boolean, or a pre-constructed preview object. It is responsible for creating and starting the chosen preview implementation, which in turn attaches itself to thePicamera2instance and starts its event loop.stop_preview(): This method stops the currently running preview, which terminates the event loop and detaches the preview from thePicamera2instance.attach_preview(preview)/detach_preview(): These methods are called by the preview implementations themselves to register or unregister with thePicamera2instance.
Sources: picamera2/picamera2.py:580-618
The Picamera2 class provides a Preview enum to simplify the selection of a backend.
| Enum Member | Class | Description |
|---|---|---|
NULL | NullPreview | A headless preview that runs the event loop without any graphical output. |
DRM | DrmPreview | Renders directly to a display using the Direct Rendering Manager (DRM). |
QT | QtPreview | Renders into a Qt widget. |
QTGL | QtGlPreview | Renders into a Qt widget using OpenGL for hardware acceleration. |
Sources: picamera2/picamera2.py:48-54
The following diagram illustrates the sequence of events when start_preview is called.
This diagram shows the sequence for starting a camera preview.
Sources: picamera2/picamera2.py:580-602, picamera2/previews/null_preview.py:46-57
The Preview Event Loop
At the heart of every preview is an event loop that runs in a dedicated thread. This loop's primary responsibility is to wait for notifications from the Picamera2 object that new camera frames (requests) are ready and then process them.
The general flow is as follows:
- The event loop waits for a read event on a notification pipe (
notifyme_r). - When
libcameracompletes a request, theCameraManagerwrites to the pipe. - The event loop wakes up and calls
picam2.process_requests(self). process_requestsretrieves the completed requests, executes any pending jobs (like captures), and calls callbacks.- For each request,
process_requestseventually calls the preview'srender_requestmethod to display the image. - The loop then waits for the next notification.
This diagram illustrates the core event loop driven by the preview.
Sources: picamera2/previews/null_preview.py:12-24, picamera2/picamera2.py:1223-1290
Preview Implementations
Class Hierarchy
Most previewers inherit from a common base class, NullPreview, which provides the fundamental event loop threading logic.
This diagram shows the inheritance structure for some of the preview classes.
Sources: picamera2/previews/null_preview.py, picamera2/previews/drm_preview.py, picamera2/previews/q_gl_picamera2.py
NullPreview
The NullPreview is the simplest implementation. It runs the event loop to drive the camera but does not display any images. This is ideal for headless applications where the program needs to process frames (e.g., for video encoding or computer vision) without a graphical display. Its render_request method is empty.
Sources: picamera2/previews/null_preview.py:63-65
DrmPreview
The DrmPreview is designed for systems that do not have a traditional windowing system (like X11) running. It renders frames directly to a connected display using the Linux Direct Rendering Manager (DRM) and Kernel Mode-Setting (KMS) via the pykms library.
Key features:
- Resource Management: It uses a
DrmManagerto manage and share DRM resources (Card,ResourceManager,CRTC) between multipleDrmPreviewinstances. - Atomic Commits: It uses atomic commits (
pykms.AtomicReq) to update the display, which prevents tearing. - Format Support: It maps
picamera2pixel formats topykms.PixelFormatvalues, supporting formats likeXRGB8888,YUV420, andMJPEG(with an internal decoding buffer). - Overlays: It supports displaying a 4-channel RGBA NumPy array as an overlay on top of the camera feed.
Sources: picamera2/previews/drm_preview.py:16-43, 62-69, 131-196
QGlPicamera2 (Qt OpenGL Preview)
QGlPicamera2 is a QWidget that can be embedded in PyQt/PySide applications. It uses OpenGL ES for hardware-accelerated rendering of camera frames, making it very efficient.
- EGL Integration: It creates an EGL context and surface to render directly into the Qt widget. It uses the
EGL_EXT_image_dma_buf_importextension to create EGL images from DMA-buf file descriptors provided bylibcamera. - Shader-based Rendering: It uses GLSL shaders to render the camera texture. A different shader program is used for the main image (
samplerExternalOES) and for overlays (sampler2D).
-g Buffer Management: It maintains a dictionary ofDmabufFramebufferobjects, mapping them tolibcamerarequest buffers. This avoids re-creating textures for every frame. - Overlays: Like
DrmPreview, it supports aset_overlaymethod to display a 4-channel RGBA NumPy array.
A full application example using QGlPicamera2 can be found in apps/app_full.py. This application demonstrates complex interactions, including mode switching, control adjustments, and a custom pan/zoom widget.
Sources: picamera2/previews/q_gl_picamera2.py, apps/app_full.py:1003-1006
Usage
Starting a preview is typically a one-line command.
Starting a Null Preview
For headless operation, use Preview.NULL or simply None.
picam2 = Picamera2()
picam2.start_preview(Preview.NULL)
# Or equivalently:
# picam2.start_preview()
# picam2.start(show_preview=False)
Sources: picamera2/picamera2.py:593-594, tests/preview_cycle_test.py:28-30
Starting a DRM Preview
To render to a display without a windowing system, use Preview.DRM. You can specify the position and size of the preview window.
picam2 = Picamera2()
# Start a preview at (100, 200) with size 800x600
picam2.start_preview(Preview.DRM, x=100, y=200, width=800, height=600)
Sources: picamera2/previews/drm_preview.py:70
Starting a Qt Preview
In a Qt application, you instantiate QGlPicamera2 and add it to your layout. The preview starts automatically when the widget is created.
# From apps/app_full.py
app = QApplication([])
window = QWidget()
qpicamera2 = QGlPicamera2(picam2, width=800, height=600)
layout_h = QHBoxLayout()
layout_h.addWidget(qpicamera2)
window.setLayout(layout_h)
window.show()
app.exec()
Sources: apps/app_full.py:1004, apps/app_full.py:1052-1057
Overlays
Both DrmPreview and QGlPicamera2 support displaying an overlay image. The overlay must be a NumPy array with 4 channels (e.g., RGBA).
# Create a semi-transparent red overlay
overlay = np.zeros((200, 300, 4), dtype=np.uint8)
overlay[: ,:] = (255, 0, 0, 64)
# This method must be called after the preview has started.
picam2.set_overlay(overlay)
The set_overlay method is part of the Picamera2 class, which delegates the call to the active preview object. The preview implementation is then responsible for rendering it.
Sources: picamera2/picamera2.py:1688-1699, picamera2/previews/drm_preview.py:112-129, picamera2/previews/q_gl_picamera2.py:270-291
Summary
Camera previews in picamera2 are fundamental components that drive the camera's event loop, enabling continuous frame processing. The library offers a flexible system with multiple backends (Null, DRM, QtGL) to suit different use cases, from headless server applications to rich desktop GUIs. The core logic is abstracted, allowing developers to easily switch between preview types while the underlying mechanism of request handling and rendering remains consistent. Advanced features like hardware-accelerated rendering and image overlays are supported in the graphical backends.