Entrada y salida de archivos
Todo el código de ejemplo se encuentra en Google Colab para su ejecución directa. Si no puedes ejecutar OpenCV localmente, puedes usar Google Colab junto con matplotlib para visualizar imágenes.
Objetivo
- Comprender cómo leer y mostrar imágenes desde archivos utilizando OpenCV.
- Aprender a guardar imágenes procesadas en distintos formatos para reutilización o análisis posterior.
- Manejar la lectura, procesamiento y visualización de videos.
- Explorar el uso de
VideoCapture
para capturar datos desde archivos, cámaras locales o transmisiones en vivo. - Implementar la escritura de videos procesados mediante diferentes codecs y formatos.
- Reconocer conceptos clave como resolución, FPS, profundidad de color y canales de color en imágenes y videos.
- Identificar y gestionar problemas comunes como buffers llenos al trabajar con transmisión en tiempo real.
Conceptos clave
- Entrada de archivos: Cómo OpenCV obtiene información desde imágenes, videos o cámaras en vivo.
- Salida de archivos: Cómo OpenCV guarda los resultados procesados para reutilizarlos o compartirlos.
- Frame (cuadro por video): Cada video está compuesto por una secuencia de imágenes llamadas frames.
- Resolución: Indica el tamaño de una imagen o frame en píxeles (ancho x alto).
- Profundidad de color (bit depth): Representa la cantidad de bits usados para cada canal de color en una imagen. Por ejemplo, imágenes RGB suelen usar 8 bits por canal, dando un total de 24 bits por píxel. Para imágenes en escala de grises, se usan 8 bits por píxel.
- Canales de color: Una imagen puede ser escala de grises (1 canal) o color (3 canalaes: R, G, B).
- FPS (Frames per second / cuadros por segundo): Velocidad a la que se reproducen los frames de un video.
- Formato de archivo: El tipo de archivo influye en la compatibilidad y la compresión. Ejemplos:
.jpg
,.png
para imágenes;.avi
,.mp4
para videos. - Codec: Algoritmo que comprime o descomprime video. Afecta calidad, tamaño del archivo y compatibilidad. Ejemplos:
XVID
,MJPG
,MP4V
,H264
,H265
. - Captura en tiempo real: Permite obtener frames directamente de una cámara o cámara IP.
- Buffers de video: OpenCV mantiene un buffer interno al leer frames de un video o cámara. Es importante procesar los frames a tiempo para evitar retrasos o pérdidas.
Pipeline básico
En visión por computadora, la entrada y salida de archivos es el primer paso de cualquier pipeline:
- Leer los datos (imágenes, videos, señal en vivo).
- Procesar los datos (filtros, transformaciones).
- Guardar o mostrar los resultados (imágenes, videos).
Funciones principales en OpenCV
cv2.imread()
: Leer una imagen desde un archivo y cargarla en una matriz.cv2.imwrite()
: Guardar una matriz como imagen en un archivo.cv2.VideoCapture()
: Abrir un archivo de video o una cámara para capturar video.cv2.VideoWriter()
: Guardar una secuencia de imágenes como archivo de video.cv2.imshow()
: Mostrar una imagen en una ventana.cv2.waitKey()
: Esperar por una tecla para cerrar la ventana o avanzar en el video.cv2.destroyAllWindows()
: Cerrar todas las ventanas abiertas por OpenCV.
Preparación del entorno
Antes de instalar OpenCV, siempre es recomendable crear un entorno virtual para no afectar tus paquetes globales o otros proyectos.
# Crear un entorno virtual
python -m venv venv
# Activar el entorno virtual en Windows
venv\Scripts\activate
------------------------------------------
# Activar el entorno virtual en macOS / Linux
source venv/bin/activate
Ejemplos de código
Antes de instalar OpenCV, asegúrate de activar tu entorno virtual para que las dependencias queden aisladas. Luego, puedes instalar OpenCV con pip, usando la versión recomendada 4.11.0.86:
pip install opencv-python==4.11.0.86
Leer y mostrar una imagen
Aquí se muestra cómo abrir una imagen y visualizarla. Es el primer paso para cualquier procesamiento de imagen. El siguiente ejemplo funciona en un computador local con entorno gráfico (no en Google Colab). En caso de usar Google Colab, puedes mostrar imágenes con matplotlib
.
- Python (PC con entorno gráfico)
- Python (Google Colab)
import cv2 as cv
# Leer imagen
img = cv.imread("imagen.jpg")
# Convertir imagen a RGB (OpenCV por defecto usa BGR)
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# Mostrar imagen en una ventana
cv.imshow("Imagen RGB", img_rgb)
cv.waitKey(0)
cv.destroyAllWindows()
import cv2 as cv
import matplotlib.pyplot as plt
# Leer imagen
img = cv.imread("imagen.jpg")
# Convertir imagen a RGB
img_rgb = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# Mostrar imagen en Colab con matplotlib
plt.imshow(img_rgb)
plt.axis("off")
plt.show()
Guardar una imagen procesada
En esta sección se muestra cómo guardar resultados de leer una imagen y aplicar procesamiento básico. Esto es útil para análisis posterior o para generar conjunto de datos.
- Python (PC con entorno gráfico)
- Python (Google Colab)
import cv2 as cv
# Leer imagen
img = cv.imread("imagen.jpg")
# Convertir a gris
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Guardar la imagen procesada
cv.imwrite("imagen_gris.jpg", img_gray)
# Mostrar la imagen procesada
cv.imshow("Imagen Gris", img_gray)
cv.waitKey(0)
cv.destroyAllWindows()
import cv2 as cv
import matplotlib.pyplot as plt
# Leer imagen
img = cv.imread("imagen.jpg")
# Convertir a gris
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Guardar la imagen procesada
cv.imwrite("imagen_gris.jpg", img_gray)
# Mostrar en Colab
plt.imshow(img_gray, cmap='gray')
plt.axis("off")
plt.show()
Leer y procesar un video
Se explica cómo abrir un archivo de video y procesar cada frame.
El código para google colab no es posible ya que no soporta ventanas gráficas.
Detalle importante:
if cv.waitKey(30) & 0xFF == ord('q'):
cv.waitKey(30)
:
- Espera 30 milisegundos a que el usuario presione una tecla.
- Devuelve un valor entero que representa la tecla presionada.
& 0xFF
:
- Este operador bit a bit toma los últimos 8 bits del valor devuelto por
cv.waitKey()
. - La razón es que
cv.waitkey()
en algunos sistemas (especialmente Windows) puede devolver un entero de más de 8 bits, donde los bits más altos contiene información irrelevante para la tecla presionada. - Al hacer
& 0xFF
, nos aseguramos de obtener solo el código de la tecla, compatible con ASCII.
ord('q')
:
- Devuelve el código ASCII de la tecla
'q'
.
En conjunto, la condición verifica si se presionó la tecla 'q'
para salir del bucle y cerrar las ventanas.
- Python (PC con entorno gráfico)
import cv2 as cv
# Abrir video
cap = cv.VideoCapture("video.mp4")
while True:
ret, frame = cap.read()
if not ret:
break
# Convertir a gris
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# Convertir a RGB
rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
# Convertir a HSV
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# Convertir a LAB
lab = cv.cvtColor(frame, cv.COLOR_BGR2LAB)
# Convertir a YCrCb
ycrcb = cv.cvtColor(frame, cv.COLOR_BGR2YCrCb)
# Mostrar video original
cv.imshow("Video original", frame)
# Mostrar video en escala de grises
cv.imshow("Video Gris", gray)
# Mostrar video en escala rgb
cv.imshow("Video RGB", rgb)
# Mostrar video en escala HSV
cv.imshow("Video HSV", hsv)
# Mostrar video en escala LAB
cv.imshow("Video LAB", lab)
# Mostrar video en escala YCrCb
cv.imshow("Video YCrCb", ycrcb)
if cv.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
Guardar un video procesado
Se muestra cómo usar cv.VideoWriter
para guardar la secuencia de frames procesados como un nuevo video. Esto es útil para registrar resultados o compartirlos.
- Python (PC con entorno gráfico)
import cv2 as cv
cap = cv.VideoCapture("video.mp4")
# Obtener ancho, alto y FPS del video original
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv.CAP_PROP_FPS)
# Crear VideoWriter para guardar el video procesado
out = cv.VideoWriter("video_gris.avi", cv.VideoWriter_fourcc(*'XVID'), fps, (width, height), False)
while True:
ret, frame = cap.read()
if not ret:
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
out.write(gray)
cap.release()
out.release()
print("Video guardado como video_gris.avi")
Leer y procesar transmisión en vivo desde una cámara
Esta sección muestra cómo capturar video en tiempo real desde una cámara local o una cámara IP/streaming, y cómo aplicar transformaciones como escala de grises o conversión a RGB.
Para cámaras en red (IP), puedes usar la URL de la transmisión. Por ejemplo, en Insecam se pueden obtener URLs públicas de cámaras para pruebas.
- Python (PC con entorno gráfico)
import cv2 as cv
# Abrir video
cap = cv.VideoCapture("url_de_la_camara")
# Tamaño deseado
width, height = 920, 480
while True:
ret, frame = cap.read()
if not ret:
break
# Redimensionar frame original
frame_resized = cv.resize(frame, (width, height))
# Convertir a gris
gray = cv.cvtColor(frame_resized, cv.COLOR_BGR2GRAY)
# Convertir a RGB
rgb = cv.cvtColor(frame_resized, cv.COLOR_BGR2RGB)
# Convertir a HSV
hsv = cv.cvtColor(frame_resized, cv.COLOR_BGR2HSV)
# Mostrar video original
cv.imshow("Video original", frame_resized)
# Mostrar video en escala de grises
cv.imshow("Video Gris", gray)
# Mostrar video en escala rgb
cv.imshow("Video RGB", rgb)
# Mostrar video en escala HSV
cv.imshow("Video HSV", hsv)
if cv.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
Grabar transmisión en vivo desde una cámara
OpenCV también permite guardar la transmisión en vivo mientras la procesamos. Esto es útil para análisis posterior o generación de conjunto de datos.
- Python (PC con entorno gráfico)
import cv2 as cv
# Abrir video
cap = cv.VideoCapture("url_de_la_camara")
# Tamaño deseado
width, height = 920, 480
fourcc = cv.VideoWriter_fourcc(*'XVID')
out_original = cv.VideoWriter('video_original.avi', fourcc, 20.0, (width, height))
out_gray = cv.VideoWriter('video_gris.avi', fourcc, 20.0, (width, height), isColor=False)
while True:
ret, frame = cap.read()
if not ret:
break
# Redimensionar frame
frame_resized = cv.resize(frame, (width, height))
# Convertir a gris
gray = cv.cvtColor(frame_resized, cv.COLOR_BGR2GRAY)
# Mostrar videos
cv.imshow("Video original", frame_resized)
cv.imshow("Video Gris", gray)
# Guardar videos
out_original.write(frame_resized)
out_gray.write(gray)
if cv.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
out_original.release()
out_gray.release()
cv.destroyAllWindows()
Simulación de un buffer lleno
Cuando se procesa video en tiempo real, es posible que el procesamiento no sea lo suficientemente rápido para mantener el ritmo de los frames entrantes. Esto puede causar que el buffer interno de OpenCV se llene, resultando en retrasos o pérdida de frames. El siguiente ejemplo simula un procesamiento lento para ilustrar este problema.
- Python (PC con entorno gráfico)
import cv2 as cv
import time
# Abrir la cámara
cap = cv.VideoCapture(0)
# Establecer el tamaño del buffer (número máximo de frames que puede almacenar)
buffer_size = 5
buffer = []
while True:
ret, frame = cap.read()
if not ret:
break
# Simular un procesamiento lento
time.sleep(0.1) # Ir aumentando el valor para que se note, ej: 0.5, 0.8...
# Agregar el frame al buffer
buffer.append(frame)
# Si el buffer está lleno, eliminar el frame más antiguo
if len(buffer) > buffer_size:
buffer.pop(0) # 0 -> frame más antiguo
# Mostrar el frame más reciente
cv.imshow('Frame', buffer[-1]) # -1 -> último frame agregado
# Salir si se presiona la tecla 'q'
if cv.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
Algunos Codecs de OpenCV
Codec | Formato de archivo común | Descripción | Ejemplo de uso |
---|---|---|---|
XVID | .avi | Codec MPEG-4 popular, buena compatibilidad con Windows | cv2.VideoWriter_fourcc(*'XVID') |
MJPG | .avi , .mov | Motion JPEG, cada frame es una imagen JPEG, buena velocidad. | cv2.VideoWriter_fourcc(*'MJPG') |
MP4V | .mp4 | MPEG-4, más comprimido que XVID, soportado por muchos reproductores. | cv2.VideoWriter_fourcc(*'MP4V') |
H264 | .mp4 | Alta compresión, calidad alta, requiere soporte del sistema. | cv2.VideoWriter_fourcc(*'H264') |
H265 | .mp4 | También llamado HEVC, compresión más eficiente que H264, requiere librerías externas. | cv2.VideoWriter_fourcc(*'HEVC') |
DIVX | .avi | Otro codec MPEG-4 compatible con Windows | cv2.VideoWriter_fourcc(*'DIVX') |