¿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.

Foto del rig de video feedback funcionando con Raspberry Pi, webcam USB y monitor HDMI

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:

Bash
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:

Bash
# 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:

Bash
# 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

Imagen del set armado mostrando el efecto de túnel recursivo en pantalla

Bash
# 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í:

Text
 * 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:

Bash
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:

Bash
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 19 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.

Detalle de la pantalla con efecto de feedback recursivo activo

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.

Resultado con varios filtros stackeados generando un patrón de túnel coloreado

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 /stream devuelve 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í:

Python
# 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:

  1. Filtro ASCII art. Suma un filtro nuevo a camera_filters_web.py que 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 con cv2.putText. Conecta visualmente el proyecto con la estética terminal/demoscene.

  2. Filtro de threshold animado. Aplica cv2.threshold con un valor que oscile en función de time.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.

  3. 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.

  4. 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.addWeighted para un meta feedback cruzado.

  5. 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

Versión chilena del tutorial inspirada en el original de Adafruit, con componentes en stock local en MechatronicStore.