¿Te imaginás convertir una webcam vieja y un Raspberry Pi en una máquina de arte psicodélico capaz de generar túneles infinitos, glitches a la Vaporwave y efectos rainbow en vivo? El efecto de retroalimentación de video. apuntar una cámara a la pantalla que muestra esa misma cámara. fue accidente molesto en los 60, se volvió arte en MTV de los 90 y hoy es un proyecto perfecto para una tarde con Raspberry Pi.
⚠️ Aviso médico: el video feedback genera destellos rápidos que pueden disparar episodios en personas fotosensibles o con epilepsia. Si es tu caso, mejor saltate este proyecto.

Qué vas a aprender
Este tutorial te guía paso a paso para montar un set de video feedback con:
- Raspberry Pi 5 (o 4) corriendo Raspberry Pi OS 64-bit
- Webcam USB barata (Logitech C270 o similar)
- Monitor HDMI portátil con kickstand
- Servidor Flask en Python con OpenCV para los filtros
- 10 filtros stackeables controlables desde el navegador
- Modo kiosko en Chromium para foto/video sin elementos de UI
Al final tienes una "cámara experimental" web controlada que sirve tanto para crear contenido visual original como para entender en profundidad cómo OpenCV procesa frames en tiempo real.
Cómo funciona el efecto: la física rápida
El concepto es brutal pero simple: la webcam apunta al monitor, el monitor muestra lo que ve la webcam, la webcam vuelve a capturarlo. Cada frame contiene una copia recursiva del anterior. como dos espejos enfrentados, pero en digital. Si pones cualquier objeto frente a la cámara, vas a verlo replicado en un túnel infinito.
La gracia del proyecto es que entre la captura y la visualización metemos filtros OpenCV que distorsionan cada iteración. El blur acumulado crea desvanecimientos psicodélicos; el edge detection convierte el túnel en líneas tipo neon; el rowshift hace glitches al estilo VHS dañado.
Hardware: lista de compra
| Componente | Por qué |
|---|---|
| Raspberry Pi 5 4GB+ (o Pi 4 4GB+) | El Pi 5 da framerate notoriamente más fluido por la GPU mejorada. En Pi 4 funciona pero a ~15 FPS. |
| Webcam USB | Más libertad de movimiento que las CSI (cinta plana es corta y rígida). La Logitech C270 sigue siendo el estándar dorado por su Linux UVC nativo. |
| Monitor HDMI 10", 15" con kickstand | Tamaño suficiente para que la webcam capture bien sin que el set se vea ridículo. Idealmente con entrada USB-C para alimentación única. |
| Cable Micro HDMI a HDMI 1.5m | Indispensable para el Pi 5 / Pi 4 (todos tienen micro HDMI). |
| Fuente USB-C 5V 5A (Pi 5) o 3A (Pi 4) | La oficial evita el throttling cuando OpenCV satura los 4 cores. |
💡 También funciona con módulo Pi Camera vía CSI, pero perdés flexibilidad de encuadre. el cable plano es corto y poco maleable, así que terminás restringido en ángulos.
Paso 1: Preparar el Raspberry Pi OS
Comenzamos instalando la versión completa de Raspberry Pi OS (64-bit) usando Raspberry Pi Imager. Si vas a tener el Pi en una mesa con el rig montado, en el menú de personalización del Imager activa SSH y configura tu llave pública. así controlas todo desde tu notebook sin teclado conectado al Pi.
Tras el primer arranque, conecta el Pi a internet y actualiza el sistema:
sudo apt update
sudo apt upgrade
Paso 2: Entorno virtual e instalación de dependencias
El servidor que sirve la previsualización web está escrito en Python con Flask + OpenCV + NumPy. Para no contaminar el Python del sistema, lo aislamos en un venv:
# Crear entorno virtual
python -m venv ~/venv_videofeedback
# Activar entorno virtual
source ~/venv_videofeedback/bin/activate
# Instalar dependencias
pip install Flask opencv-python numpy adafruit-blinka
El paquete adafruit-blinka se usa solo por su módulo rainbowio, que entrega la paleta del filtro arcoiris. Si no tienes acceso a PyPI, también puedes instalar OpenCV vía apt: sudo apt install python3-flask python3-opencv python3-numpy.
Paso 3: Descargar el proyecto
Adafruit publica el bundle completo del proyecto como ZIP. Bájalo directo desde el terminal del Pi:
# Ir al home
cd ~
# Descargar el zip del proyecto
wget https://cdn-learn.adafruit.com/assets/assets/000/144/514/original/Raspberry_Pi_Video_Feedback.zip
# Descomprimir
unzip Raspberry_Pi_Video_Feedback.zip
Paso 4: Arrancar el servidor

# Entrar al folder del proyecto
cd ~/Raspberry_Pi_Video_Feedback
# Activar entorno virtual
source ~/venv_videofeedback/bin/activate
python camera_filters_web.py
Si todo va bien vas a ver una salida así:
* Serving Flask app 'camera_filters_web'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.1.242:5000
Esa terminal queda ocupada con el servidor mientras uses el rig. Para detenerlo: Ctrl+C. Abre una segunda terminal o sesión SSH para los siguientes pasos.
Paso 5: Navegador en modo kiosko
Si lanzas Chromium con sus barras estándar (URL, tabs, marcadores), todo eso aparece atrapado en el loop recursivo y rompe la magia. El proyecto incluye un script que abre Chromium en modo full screen sin UI:
cd ~/Raspberry_Pi_Video_Feedback
./launch_browser.sh
El script exporta DISPLAY=:0 para que funcione tanto vía SSH como en la consola local del Pi, y dirige logs al journal del sistema. Si el navegador no arranca:
journalctl -t glitch_cam_browser -f
El panel de control y los 10 filtros
Cuando se carga la página, ves el preview a pantalla completa. Para abrir el panel de control: haz click en cualquier parte o presiona F. Los filtros se activan/desactivan con checkbox o con teclas 1–9 y 0. Cada filtro tiene un slider de intensidad (0 a 100%) y se aplican en orden de arriba a abajo, así que el orden importa.

| Tecla | Filtro | Efecto |
|---|---|---|
| 1 | Edges | Detecta bordes con Canny: imagen negra con líneas finas claras. |
| 2 | Grayscale | Convierte a escala de grises. |
| 3 | Rainbow | Overlay arcoiris en filas/columnas/diagonales (orientación configurable). |
| 4 | Color Gel | Shift por canal RGB independiente (positivo o negativo). |
| 5 | Color Matrix | Multiplicación matricial 3x3 sobre los canales. Default = sepia. |
| 6 | Invert | Invierte colores. Por la recursividad se cancela cada 2 frames → patrones intermitentes. |
| 7 | Blur | Gaussian blur 15×15. El más sutil del set. |
| 8 | Cartoon | Bilateral filter + edges = look de animación. |
| 9 | Glitch | Separa canales R/G/B y los desplaza/escala/sesga. |
| 0 | Rowshift | Divide la imagen en filas y las intercambia a la izquierda/derecha. |
Para guardar foto: tecla S o botón 📷. Para grabar video: tecla R (start/stop). Las galerías quedan accesibles desde el mismo panel.
El truco del control desde otro equipo
Si controlas el panel desde el Pi mismo, ese panel se incluye en el feedback loop y arruina la composición. Conviene cargar la página desde tu notebook o celular apuntando a http://<ip-del-pi>:5000/ — así el Pi solo renderea el preview limpio y tú manipulas filtros desde otro dispositivo. El truco se nota muchísimo en las grabaciones finales.

Cómo funciona el código por debajo
El script camera_filters_web.py usa una arquitectura de dos threads:
- Thread de cámara: captura frames continuamente, aplica los filtros activos y guarda el resultado en una variable compartida.
- Thread del servidor (Flask): cada GET a
/streamdevuelve el último frame cacheado en formato MJPEG.
Esa separación permite que múltiples clientes conecten al preview sin saturar el Pi (todos comparten el mismo frame ya procesado). El cuerpo principal del archivo arranca así:
# SPDX-FileCopyrightText: 2026 Tim Cocks, written for Adafruit Industries
# SPDX-License-Identifier: MIT
"""
Live camera preview with stackable, intensity-adjustable filters,
served as a web page over the local network via Flask + MJPEG.
"""
import os
import time
import threading
from typing import List, Optional, TypedDict
import cv2
import numpy as np
import rainbowio
from flask import (
Flask,
Response,
request,
jsonify,
render_template,
send_from_directory,
abort,
)
def filter_grayscale(frame, config=None):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
return cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
def filter_edges(frame, config=None):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 80, 160)
return cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
def filter_blur(frame, config=None):
return cv2.GaussianBlur(frame, (15, 15), 0)
def filter_invert(frame, config=None):
return cv2.bitwise_not(frame)
def filter_cartoon(frame, config=None):
color = cv2.bilateralFilter(frame, 9, 75, 75)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 5)
edges = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 2
)
edges = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
return cv2.bitwise_and(color, edges)
El archivo completo está en el bundle del proyecto. incluye el filtro Rainbow (con cache de offsets para no recalcularlos en cada frame), Color Gel, Color Matrix, Glitch y Rowshift.
Variantes y mejoras
Algunas extensiones que no están en el tutorial original y que valen la pena agregar al rig:
Filtro ASCII art. Suma un filtro nuevo a
camera_filters_web.pyque mapee cada bloque de 8×8 píxeles a un carácter ASCII según su brillo promedio. Lo más simple: convertir a grayscale, downsamplear, indexar en una string" .:-=+*#%@"y dibujarlo concv2.putText. Conecta visualmente el proyecto con la estética terminal/demoscene.Filtro de threshold animado. Aplica
cv2.thresholdcon un valor que oscile en función detime.time()— el resultado son patrones de blanco/negro pulsantes sincronizados con el feedback. Perfecto para audio reactivo si después conectas un sensor de sonido.Modo timelapse. Reemplaza la captura continua por una toma cada N segundos y un export a video con
cv2.VideoWriter. Combinado con video feedback, en 10 minutos consigues secuencias de un minuto que muestran cómo evoluciona el túnel cuando movés objetos lentamente.Servidor para múltiples cámaras simultáneas. El Pi 5 tiene puertos suficientes: con 2 webcams USB puedes generar dos feeds independientes y combinarlos con
cv2.addWeightedpara un meta feedback cruzado.Trigger por hardware. Conecta un botón al GPIO17 y lanza foto/grabación sin teclado. útil cuando estás tomando fotos de objetos que requieren las dos manos.
Personalización para Chile
En MechatronicStore consigues casi todo el set local. Equivalencias frente al BOM original:
- Placa Raspberry Pi 5 (8GB). la versión 4GB del original también sirve, pero 8GB te deja correr el feedback + un editor de imágenes a la vez sin lag. Si prefieres ahorrar, la Placa Raspberry Pi 4 Model B (4GB) funciona idéntico aunque con framerate menor.
- Fuente USB-C 5V 5A para Pi 5. sustituye a la "Official Raspberry Pi 45W USB-C Power Supply" del tutorial original.
- Cable Micro HDMI a HDMI. clave para conectar el Pi 5/4 al monitor.
- Webcam USB Logitech C270. el clásico, full compatible con Linux UVC. Alternativa más barata: cualquier webcam Logitech / Genius USB de las que vendemos.
- Display HDMI 7 pulgadas o Display HDMI 10 pulgadas. para empezar; lo del tutorial original es un monitor portátil USB-C de 15" pero el efecto se aprecia desde 7" para arriba.
- Tarjeta microSD 32GB clase 10. Raspberry Pi OS pesa ~5GB con todo instalado; 32GB queda holgado.
Total del rig en MechatronicStore: aproximadamente CLP $175.000 con Pi 5 + display 7" + accesorios. La versión con Pi 4 + microSD baja a ~CLP $130.000.
Recursos
- Tutorial original: Video Feedback with Raspberry Pi por Tim C en Adafruit Learning System
- Bundle del proyecto (.zip con código + templates): Raspberry_Pi_Video_Feedback.zip
- PDF del tutorial completo: video feedback-with raspberry-pi.pdf
- Documentación OpenCV: docs.opencv.org
- Raspberry Pi Imager: raspberrypi.com/software
Versión chilena del tutorial inspirada en el original de Adafruit, con componentes en stock local en MechatronicStore.








