Dibujar sobre imágenes
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 , 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).

(a) Imagen en plano cartesiano.

(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)
.
- Imagen Original
- Imagen con ROI
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()
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# Cargar la imagen
image = plt.imread("imagen.jpg")
# Mostrar la imagen
fig, ax = plt.subplots()
ax.imshow(image)
ax.set_title("Rectángulo definido por (x1,y1) y (x2,y2)")
ax.set_xlabel("Eje X (ancho)")
ax.set_ylabel("Eje Y (alto)")
# Definir dos puntos (sup. izq y inf. der)
x1, y1 = 250, 70 # esquina superior izquierda
x2, y2 = 510, 320 # esquina inferior derecha
# Dibujar rectángulo
rect = patches.Rectangle((x1, y1), x2-x1, y2-y1,
linewidth=2, edgecolor='green', facecolor='none')
ax.add_patch(rect)
# Marcar esquinas
ax.scatter([x1, x2], [y1, y2], c="red", s=50)
# Etiquetar esquinas
ax.text(x1, y1, f"({x1},{y1})", color="white", fontsize=12, va="bottom")
ax.text(x2, y2, f"({x2},{y2})", color="white", fontsize=12, va="bottom")
plt.show()
Ejemplos de código
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
# Cargar imagen desde archivo
image = cv.imread(filename)
# Crear copia para modificar
img_mod = image.copy()
# Dibujar una línea
cv.line(
img_mod, # Imagen base
(0, 0), # Punto inicial (esquina superior izquierda)
(img_mod.shape[1]-1, img_mod.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_mod, # Imagen base
(0, img_mod.shape[0]-1), # Punto inicial (esquina superior izquierda)
(img_mod.shape[1]-1, 0), # Punto final (esquina inferior derecha)
(255, 0, 0), # Color en formato BGR (azul)
5 # Grosor de la línea
)
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(image, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_mod, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
img = cv.imread(filename)
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)
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_copy, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
img = cv.imread(filename)
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
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_copy, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
img = cv.imread(filename)
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)
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_copy, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from google.colab import files
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
img = cv.imread(filename)
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
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_copy, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
- Python (PC con entorno gráfico)
- Python (Google Colab)
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()
import cv2 as cv
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# Subir archivo desde tu PC
uploaded = files.upload()
filename = list(uploaded.keys())[0]
img = cv.imread(filename)
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)
# Original a la izquierda, Modificada a la derecha
fig, axes = plt.subplots(1, 2, figsize=(18, 6))
# Imagen Original
axes[0].imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
axes[0].set_title("Imagen Original")
axes[0].axis("off")
# Imagen Modificada
axes[1].imshow(cv.cvtColor(img_copy, cv.COLOR_BGR2RGB))
axes[1].set_title("Imagen Modificada")
axes[1].axis("off")
plt.show()
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.
Fuente | Descripción | Ejemplo uso |
---|---|---|
cv.FONT_HERSHEY_SIMPLEX | Fuente normal, sin serif | Texto normal |
cv.FONT_HERSHEY_PLAIN | Fuente simple, más pequeña | Etiquetas pequeñas |
cv.FONT_HERSHEY_DUPLEX | Fuente más gruesa que SIMPLEX | Texto legible y más denso |
cv.FONT_HERSHEY_COMPLEX | Fuente con trazos más detallados | Texto más estilizado |
cv.FONT_HERSHEY_TRIPLEX | Versión más gruesa que COMPLEX | Texto más destacado |
cv.FONT_HERSHEY_COMPLEX_SMALL | Versión pequeña de COMPLEX | Texto pequeño y elegante |
cv.FONT_HERSHEY_SCRIPT_SIMPLEX | Fuente tipo script (cursiva) | Texto estilo manuscrito |
cv.FONT_HERSHEY_SCRIPT_COMPLEX | Fuente tipo script más decorativa | Texto manuscrito decorativo |
cv.FONT_ITALIC | Fuente cursiva | Combinar con otras fuentes |