Saltar al contenido principal

Dibujar sobre imágenes

info

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 dibujar diferentes formas geométricas sobre imágenes usando OpenCV.
  • Aprender a agregar y personalizar texto en imágenes.
  • Conocer los distintos tipos de fuentes que OpenCV ofrece y cómo aplicarlas en los textos.
  • Familiarizarse con conceptos de coordenadas, colores y grosor de líneas para realizar anotaciones precisas en imágenes****.****

Conceptos clave

  • Dibujo en imágenes: Usar OpenCV para agregar formas y texto a imágenes.
  • Coordenadas de píxeles: Entender el sistema de coordenadas en imágenes (origen en la esquina superior izquierda).
  • Colores y grosor: Especificar colores en formato BGR y definir el grosor de las líneas.
  • Funciones de dibujo: Utilizar las funciones de OpenCV para crear gráficos sobre imágenes.
  • Visualización: Mostrar imágenes con las formas dibujadas usando OpenCV o matplotlib.
  • Aplicaciones prácticas: Usar dibujo para anotaciones, resaltado y creación de gráficos simples en imágenes.
  • Transformaciones geométricas: Entender cómo las formas se posicionan y escalan en la imagen.
  • Canales de color: Trabajar con imágenes en escala de grises y en color (BGR).
  • Espacio de color BGR: OpenCV usa el formato BGR en lugar de RGB, lo que afecta cómo se especifican los colores.

Funciones principales en OpenCV

  • cv.line(img, pt1, pt2, color, grosor): Dibujar líneas.
  • cv.rectangle(img, pt1, pt2, color, grosor): Dibujar rectángulos.
  • cv.circle(img, center, radius, color, grosor): Dibujar círculos.
  • cv.ellipse(img, center, axes, angle, startAngle, endAngle, color, grosor): Dibujar elipses.
  • cv.polylines(img, pts, isClosed, color, grosor): Dibujar polígonos.
  • cv.putText(img, text, org, fontFace, fontScale, color, grosor, lineType): Añadir texto a una imagen.

¿Cómo funcionan las coordenadas en una imagen?

Cuando trabajamos con imágenes en OpenCV o Matplotlib, es importante entender cómo se representan las coordenadas. Una imagen no es más que una matriz de píxeles organizada en filas y columnas.

  • El eje X corresponde al ancho de la imagen (se desplaza de izquierda a derecha).
  • El eje Y corresponde al alto de la imagen (se desplaza de arriba hacia abajo).
  • El punto de origen (0, 0) siempre está en la esquina superior izquierda de la imagen.

De esta forma, cualquier punto dentro de la imagen se puede representar con un par de coordenadas (x,y)(x, y), donde x es la posición horizontal y y la vertical.

En la siguiente ilustración (a) se observa una imagen de 350 píxeles de alto por 650 píxeles de ancho. Si seleccionamos dos puntos de interés: (x1, y1) = (250, 70) y (x2, y2) = (510, 320), se define un rectángulo o Región de Interés (ROI) dentro de la imagen, como se muestra en la ilustración (b).

Imagen en plano cartesiano

(a) Imagen en plano cartesiano.

Imagen en plano cartesiano con ROI

(b) Imagen en plano cartesiano con ROI.

El siguiente código muestra cómo generar las figuras anteriores, primero visualizando la imagen original con sus ejes y luego dibujando el rectángulo correspondiente al ROI definido por (x1,y1) y (x2,y2).

import matplotlib.pyplot as plt

# Cargar la imagen
image = plt.imread("imagen.jpg")

# Mostrar la imagen
plt.imshow(image)
plt.title("Imagen Original")

# Dibujar ejes de coordenadas
plt.xlabel("Eje X (ancho)")
plt.ylabel("Eje Y (alto)")

# Mostrar la figura
plt.show()

Ejemplos de código

info

Para los siguientes ejemplos se utilizará la imagen de prueba imagen.jpg. Si deseas usar una imagen propia, recuerda que debes ajustar las coordenadas (x1, y1) y (x2, y2) de acuerdo al tamaño de tu imagen y a la región que quieras resaltar.

Dibujar línea

Se aprenderá a trazar líneas entre dos puntos específicos de la imagen, controlando color, grosor y estilo. Esto es útil para resaltar contornos o guiar la atención hacia ciertas regiones.

import cv2 as cv

# Cargar imagen desde archivo
img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Dibujar una línea
cv.line(
img_copy, # Imagen base
(0, 0), # Punto inicial (esquina superior izquierda)
(img.shape[1]-1, img.shape[0]-1), # Punto final (esquina inferior derecha)
(255, 0, 0), # Color en formato BGR (azul)
5 # Grosor de la línea
)

cv.line(
img_copy, # Imagen base
(0, img.shape[0]-1), # Punto inicial (esquina superior izquierda)
(img.shape[1]-1, 0), # Punto final (esquina inferior derecha)
(255, 0, 0), # Color en formato BGR (azul)
5 # Grosor de la línea
)

# Mostrar imagen
cv.imshow('Original', img)
cv.imshow('Modificada', img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Dibujar un rectángulo

Con cv.rectangle() se puede dibujar un rectángulo a partir de la esquina superior izquierda y la inferior derecha. Los rectángulos son útiles para delimitar áreas de interés, como regiones de objetos en imágenes.

import cv2 as cv

img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Dibujar un rectángulo
cv.rectangle(
img_copy, # Imagen base
(250, 70), # (x1, y1)
(510, 320), # (x2, y2)
(0, 255, 0), # Color del rectángulo (B, G, R)
2) # Grosor del rectángulo

# Dibujar rectángulo en ojo derecho
cv.rectangle(
img_copy,
(345, 90),
(415, 160),
(255, 0, 0),
2)

# Dibujar rectángulo en ojo izquierdo
cv.rectangle(
img_copy,
(415, 130),
(485, 205),
(0, 0, 255),
2)

cv.imshow("Original", img)
cv.imshow("Modificada", img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Dibujar un círculo

Los círculos se definen por su centro y radio, y se pueden dibujar con contorno o relleno. Son útiles para marcar puntos o resaltar elementos circulares en la imagen.

import cv2 as cv

img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Dibujar un círculo
cv.circle(
img_copy,
(370, 200),
145,
(0, 255, 0),
2) # 1 = sin relleno / -1 = con relleno

# Dibujar un círculo en ojo derecho
cv.circle(
img_copy,
(380, 125),
35,
(255, 0, 0),
2) # 1 = sin relleno / -1 = con relleno

# Dibujar un círculo en ojo izquierdo
cv.circle(
img_copy,
(450, 170),
35,
(0, 0, 255),
2) # 1 = sin relleno / -1 = con relleno

cv.imshow("Original", img)
cv.imshow("Modificada", img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Dibujar una elipse

Se puede crear una elipse especificando centro, ejes y ángulo de rotación. Las elipses permiten marcar áreas con formas más flexibles que un círculo o rectángulo.

import cv2 as cv

img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Dibujar elipse
cv.ellipse(
img_copy, # Imagen base
(370, 200), # Centro de la elipse (x, y)
(150, 120), # Ejes de la elipse (semieje mayor, semieje menor)
-40, # Ángulo de rotación de la elipse en grados
0, # Ángulo inicial del arco (en grados)
360, # Ángulo final del arco (360 -> elipse completa)
(0, 255, 0), # Color en BGR
2) # Grosor de la línea (-1 = con relleno)

cv.imshow("Original", img)
cv.imshow("Modificada", img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Dibujar un polígono

Con cv.polylines() es posible dibujar polígonos conectando varios puntos. Esto es útil para delimitar áreas irregulares o contornos complejos.

import cv2 as cv
import numpy as np

img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Definir puntos del polígono
pts = np.array([
[250, 145], # Punto 1 (x, y)
[400, 65], # Punto 2 (x, y)
[535, 150], # Punto 3 (x, y)
[425, 300], # Punto 4 (x, y)
[250, 310]], # Punto 5 (x, y)
np.int32) # Valores del array son enteros de 32 bits.

# Formato que OpenCV requiere
pts = pts.reshape((
-1, # Calcular automáticamente el número de puntos
1, # Cada punto es un vector interno
2)) # Cada punto tiene dos coordenadas (x, y)

cv.polylines(
img_copy, # Imagen base
[pts], # Lista de puntos
True, # Cerrar polígono (True -> conecta todos los puntos)
(0, 255, 0), # Color en BGR
2) # Grosor de la línea

cv.imshow("Original", img)
cv.imshow("Modificada", img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Agregar texto a la imagen

cv.putText() permite escribir texto en la imagen, especificando fuente, tamaño, color y grosor. Es útil para anotaciones, etiquetas o mensajes sobre la imagen.

import cv2 as cv

img = cv.imread("imagen.jpg")

img_copy = img.copy()

# Definir el tipo de fuente
font = cv.FONT_HERSHEY_SIMPLEX

cv.putText(
img_copy, # Imagen base
'Baby Gumball', # Texto a escribir
(250, 330), # Punto inferior izquierdo del texto (x, y)
font, # Fuente
1, # Tamaño de la fuente
(0, 0, 0), # Color en BGR
2, # Grosor de la línea
cv.LINE_AA) # Tipo de línea (anti-aliasing para suavizar)

cv.imshow("Original", img)
cv.imshow("Modificada", img_copy)
cv.waitKey(0)
cv.destroyAllWindows()

Tipos de fuente

OpenCV ofrece diversas fuentes, desde simples hasta decorativas o cursivas, para personalizar el texto. Esto permite adaptar la escritura según la finalidad, ya sea informativa o estética.

FuenteDescripciónEjemplo uso
cv.FONT_HERSHEY_SIMPLEXFuente normal, sin serifTexto normal
cv.FONT_HERSHEY_PLAINFuente simple, más pequeñaEtiquetas pequeñas
cv.FONT_HERSHEY_DUPLEXFuente más gruesa que SIMPLEXTexto legible y más denso
cv.FONT_HERSHEY_COMPLEXFuente con trazos más detalladosTexto más estilizado
cv.FONT_HERSHEY_TRIPLEXVersión más gruesa que COMPLEXTexto más destacado
cv.FONT_HERSHEY_COMPLEX_SMALLVersión pequeña de COMPLEXTexto pequeño y elegante
cv.FONT_HERSHEY_SCRIPT_SIMPLEXFuente tipo script (cursiva)Texto estilo manuscrito
cv.FONT_HERSHEY_SCRIPT_COMPLEXFuente tipo script más decorativaTexto manuscrito decorativo
cv.FONT_ITALICFuente cursivaCombinar con otras fuentes