Skip to Content

← All functionalities

Visual inspection (machine vision)Raspberry Pi + USB cameraUSB/V4L2HMI / Dashboard

A multi-tab PySide6 GUI with an asynchronous camera thread

A vision station needs an interface an operator can use with gloves on: live video, one inspect button, a clear OK/NOK verdict. This PySide6 camera GUI, from a real production line visual inspection deployment, runs the USB camera in a QThread that emits frames as Qt signals — so the interface never freezes — and organizes operation, reference capture and parameter tuning into tabs. The trick that keeps a Raspberry Pi responsive: frames are only emitted while the live view tab is visible.

Never read the camera from the GUI thread

Blocking on cap.read() inside the Qt event loop freezes buttons, repaints and touch input — the interface feels broken even when the vision code is fine. The pattern: a QThread owns the VideoCapture, loops on reads, and emits each BGR frame through a signal. The main thread converts it to QImage and paints a QLabel. Qt's queued connections handle the cross-thread handoff safely, with no manual locking around frame data.

Emit frames only when someone is watching

On a Raspberry Pi, capturing, converting and painting 30 frames per second eats a whole core. The deployed GUI connects QTabWidget.currentChanged to a flag in the camera thread: when the operator switches to the references or configuration tab, the thread sleeps instead of capturing. CPU drops to near zero and the fan stays quiet — with zero code in the tabs themselves.

Tabs that map to roles on the line

Operation is the only tab an operator needs: live view, inspect button, verdict. Reference capture and processing sliders live in separate tabs used during product changeover. The sliders write to the same config.json the pipeline reads, and reference captures are saved as preprocessed PNGs — the GUI is a thin shell over the vision modules, not where the logic lives.

A snippet from the implementation

Straight from the example as deployed on the Raspberry Pi + USB camera — copy it freely:

COMPLETE EXAMPLE — Multi-tab PySide6 GUI with asynchronous camera thread

Hardware:  Raspberry Pi + USB camera
Based on:  visual inspection project in production (gui.py, vision.py)

Requirements:
    pip install opencv-python PySide6 numpy

What it does — the same architecture as the shop-floor application:
    - Camera QThread: captures frames in its own thread and emits them
      as a Qt signal. The GUI never blocks waiting for the camera.
    - Key CPU saving on the Raspberry Pi: the thread ONLY emits frames
      when the tab with the live view is active (set_live_enabled).
    - 3 tabs: Operation (video + Inspect button), References
      (capture pattern) and Configuration (persisted sliders).
    Without a connected camera it generates synthetic frames: it works on any PC.

Integration with the catalog:
    - "Inspect" would call the pipeline + matching from the catalog:
      ejemplos/inspeccion-visual/opencv-silkscreen-pipeline.py
      ejemplos/inspeccion-visual/rotational-template-matching.py
    - The sliders persist in config.json and the references as PNG:
      ejemplos/inspeccion-visual/json-config-references.py
"""

import sys
import time
import cv2
import numpy as np
from PySide6.QtCore import QThread, Signal, Qt

The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.

Frequently asked questions

Why PySide6 instead of a web interface?

The station is a standalone Raspberry Pi with a touchscreen and no guaranteed network. A native Qt app starts at boot, works offline and gives low-latency video without streaming overhead.

How do I safely stop the camera thread?

Set a running flag to false and call wait() on the thread inside closeEvent, then release the capture inside run(). Killing the app without this can leave the V4L2 device busy.

Can the same GUI run without a camera attached?

Yes. The example thread falls back to synthetic frames when VideoCapture fails to open, which is convenient for developing the interface on a laptop before deploying to the Pi.

Related functionalities