Una GUI PySide6 multipestaña con hilo de cámara asíncrono
QThread que emite los frames como señales de Qt — así la interfaz nunca se congela — y organiza operación, captura de referencias y ajuste de parámetros en pestañas. El truco que mantiene la Raspberry Pi con capacidad de respuesta: los frames solo se emiten mientras la pestaña de vista en vivo está visible.Nunca leas la cámara desde el hilo de la GUI
cap.read() dentro del event loop de Qt congela botones, repintados y entrada táctil — la interfaz parece rota aunque el código de visión funcione bien. El patrón: un QThread posee el VideoCapture, itera sobre las lecturas y emite cada frame BGR a través de una señal. El hilo principal lo convierte a QImage y lo pinta en un QLabel. Las conexiones en cola de Qt gestionan el traspaso entre hilos de forma segura, sin locking manual alrededor de los datos del frame.Emite frames solo cuando alguien está mirando
QTabWidget.currentChanged a un flag en el hilo de cámara: cuando el operario cambia a la pestaña de referencias o de configuración, el hilo duerme en lugar de capturar. La CPU cae casi a cero y el ventilador se mantiene en silencio — sin una sola línea de código en las propias pestañas.Pestañas que se corresponden con roles en la línea
config.json que lee el pipeline, y las capturas de referencia se guardan como PNG preprocesados — la GUI es una capa fina sobre los módulos de visión, no el lugar donde vive la lógica.Un fragmento de la implementación
Tal cual del ejemplo desplegado en el Raspberry Pi + cámara USB — cópialo libremente:
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, QtEl ejemplo completo es un programa entero — cabecera de conexionado, setup y bucle principal — listo para adaptar a tu aplicación.
Preguntas frecuentes
¿Por qué PySide6 en lugar de una interfaz web?
La estación es una Raspberry Pi autónoma con pantalla táctil y sin red garantizada. Una aplicación Qt nativa arranca con el sistema, funciona offline y ofrece vídeo de baja latencia sin la sobrecarga del streaming.
¿Cómo detengo el hilo de cámara de forma segura?
Pon un flag de ejecución a false y llama a wait() sobre el hilo dentro de closeEvent, y libera la captura dentro de run(). Matar la aplicación sin esto puede dejar el dispositivo V4L2 ocupado.
¿Puede la misma GUI funcionar sin cámara conectada?
Sí. El hilo del ejemplo recurre a frames sintéticos cuando VideoCapture no consigue abrirse, lo que resulta cómodo para desarrollar la interfaz en un portátil antes de desplegarla en la Pi.