Funciones de dibujo OpenCV Python
OpenCV nos proporciona varias funciones que nos permiten dibujas diversas figuras de una menara rápida y sencilla, para este tutorial haremos uso del trackbar y el ratón para dibujar figuras como círculos, rectángulos y líneas, además veremos las funciones usadas para pintar elipses, polígonos y texto.
Las funciones de dibujo tienen los siguientes parámetros en común:
- img: imagen sobre la que se desea dibujar, siempre es el primero que indicamos.
- color: color con que se debe pintar la figura.
- thickness: grosor del contorno de la figura, -1 rellena la figura, el valor por defecto es 1.
- lineType: define el tipo de línea, por defecto es cv2.LINE_8, la opción cv2.LINE_AA usa anti-aliased por lo que el resultado será mejor, también puedes usar cv2.LINE_4.
Para esta primera demostración crearemos una aplicación que nos permitirá dibujar líneas, círculos, y rectángulos usando el mouse, por ejemplo, para crear una línea hacemos clic izquierdo en el punto inicial de la misma y arrastramos hasta el punto final, al soltar el botón izquierdo la línea será dibujada.
import cv2
import numpy as np
from math import sqrt
mode = 'circle'
color = (0, 0, 255)
pt = None
tk = 1
def on_track(value):
global tk
# el valor -1 dibuja una figura rellena
tk = -1 if value == 0 else value
# no se puede rellenar una line
if mode == 'line' and tk == -1:
tk = 1
def on_mouse(event, x, y, flags, param):
global pt, draw
if event == cv2.EVENT_LBUTTONDOWN:
pt = (x, y)
print('Dibujando ', mode, ', en el punto: ', pt)
elif event == cv2.EVENT_LBUTTONUP:
if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)
elif mode == 'rectangle':
cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)
elif mode == 'line':
cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)
if __name__ == "__main__":
title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)
cv2.namedWindow(title)
cv2.createTrackbar('RELLENO', title, 1, 10, on_track)
cv2.setMouseCallback(title, on_mouse, image)
while(1):
cv2.imshow(title, image)
key = cv2.waitKey(20) & 0xFF;
if key == ord('c'):
mode = 'circle'
elif key == ord('r'):
mode = 'rectangle'
elif key == ord('l'):
mode = 'line'
elif key == 27:
break
cv2.destroyAllWindows()
Esta es la aplicación completa, consta de las siguientes partes:
if __name__ == "__main__":
title = 'Drawing'
image = np.zeros((600, 800, 3), np.uint8)
cv2.namedWindow(title)
cv2.createTrackbar('RELLENO', title, 1, 10, on_track)
cv2.setMouseCallback(title, on_mouse, image)
while(1):
cv2.imshow(title, image)
key = cv2.waitKey(20) & 0xFF;
if key == ord('c'):
mode = 'circle'
elif key == ord('r'):
mode = 'rectangle'
elif key == ord('l'):
mode = 'line'
elif key == 27:
break
cv2.destroyAllWindows()
Aquí inicia la aplicación, se crea la imagen sobre la que dibujaremos de tamaño 800x600 de 3 canales de tipo uint8, creamos también la ventana, le agregamos un trackbar y el manejador de eventos para el mouse.
El bucle inferior nos permite cambiar la figura que deseamos dibujar usando las teclas: c, r, l, para dibujar círculos, rectángulos y líneas respectivamente, presionando ESC salimos de la aplicación, al terminar el bucle destruimos la ventana.
def on_track(value):
global tk
# el valor -1 dibuja una figura rellena
tk = -1 if value == 0 else value
# no se puede rellenar una line
if mode == 'line' and tk == -1:
tk = 1
Esta es la función invocada cada vez que cambia el valor del trackbar, este valor será usado para definir el thickness de la figura, si el valor es cero lo cambiamos a -1 para dibujar una figura rellena, debemos tener en cuenta que una línea no se puede rellenar.
def on_mouse(event, x, y, flags, param):
global pt, draw
if event == cv2.EVENT_LBUTTONDOWN:
pt = (x, y)
print('Dibujando ', mode, ', en el punto: ', pt)
elif event == cv2.EVENT_LBUTTONUP:
if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)
elif mode == 'rectangle':
cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)
elif mode == 'line':
cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)
Aquí controlamos los eventos del mouse, al hacer clic izquierdo EVENT_LBUTTONDOWN guardamos la posición del mouse, cunado soltamos dicho botón verificamos cual es la figura a dibujar, obtenemos la posición actual y dibujamos la figura.
El parámetro llamado param corresponde a la imagen en donde se debe dibujar, este parámetro fue enviado desde la función principal.
Dibujar un circulo
Usamos la función cv2.circle()
debemos indicar la imagen destino, el punto inicial y el radio, los demás parámetros ya los conocimos al principio del tutorial.
if mode == 'circle':
rad = sqrt(pow(pt[0] - x, 2) + pow(pt[1] - y, 2))
cv2.circle(param, pt, int(rad), color, tk, cv2.LINE_AA)
Para obtener el radio calculamos la distancia que hay desde el primer punto hasta el punto actual.
Dibujar un rectángulo
Para esta figura requerimos indicar dos puntos además de los parámetros comunes, el primer punto corresponde a la esquina superior izquierda y el segundo a la esquina inferior derecha del rectángulo, la función es cv2.rectangle()
.
elif mode == 'rectangle':
cv2.rectangle(param, pt, (x, y), color, tk, cv2.LINE_AA)
Dibujar líneas
Con cv2.line()
pintamos una líneas solo debemos indicar el punto inicial y final de la misma.
elif mode == 'line':
cv2.line(param, pt, (x, y), color, tk, cv2.LINE_AA)
Existen otras funciones de dibujo que no hemos incluido en esta primera demostración, ellas son para dibujar: textos, elipses y polígonos, veamos un ejemplo de como utilizarlas.
import cv2
import numpy as np
if __name__ == "__main__":
title = 'Drawing'
img = np.zeros((600, 800, 3), np.uint8)
font = cv2.FONT_HERSHEY_TRIPLEX
cv2.putText(img, 'OpenCV Python', (5, 560), font, 3, (255,255,255), 1, cv2.LINE_AA)
pts = np.array([[403, 75], [587, 312], [216, 150], [588, 155], [215, 313]], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255), 5, cv2.LINE_AA)
cv2.ellipse(img, (400, 360), (100, 50), 0, 45, 360, (255, 0, 255), -1, cv2.LINE_AA)
cv2.imshow(title, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Explicación de cada una de las funciones utilizadas, al igual que las anteriores usamos los parámetros comunes previamente explicados, el primer parámetro es la imagen en donde se desea dibujar.
Dibujar Texto
Para pintar un texto tenemos la función cv2.putText()
, le pasamos el texto, luego la ubicación, sigue la fuente y su tamaño.
font = cv2.FONT_HERSHEY_TRIPLEX
cv2.putText(img, 'OpenCV Python', (5, 560), font, 3, (255,255,255), 1, cv2.LINE_AA)
Las fuentes disponibles son las siguientes:
- FONT_HERSHEY_SIMPLEX
- FONT_HERSHEY_PLAIN
- FONT_HERSHEY_DUPLEX
- FONT_HERSHEY_COMPLEX
- FONT_HERSHEY_TRIPLEX
- FONT_HERSHEY_COMPLEX_SMALL
- FONT_HERSHEY_SCRIPT_SIMPLEX
- FONT_HERSHEY_SCRIPT_COMPLEX
Dibujar un polígono
Usando la función cv2.polylines()
podemos dibujar una serie de líneas, debemos crear un conjunto de puntos que definen la figura, esto puntos serán unidos usando líneas, de este modo podemos crear figuras complejas, ejemplo, la estrella que vemos en la imagen superior.
pts = np.array([[403, 75], [587, 312], [216, 150], [588, 155], [215, 313]], np.int32)
cv2.polylines(img, [pts], True, (0, 255, 255), 5, cv2.LINE_AA)
La variable pts guarda cada uno de los puntos requeridos para formar la estrella, estos corresponden a las puntas de la misma, el booleano que en nuestro caso hemos establecido a True indica si se debe conectar el último punto con el primero.
Si deseamos dibujar una figura con relleno en su interior debemos usar cv2.fillPoly(...)
se utiliza de manera similar con la diferencia de que se rellena el interior de la figura, ejemplo:
cv2.fillPoly(img, [pts], (0, 125, 125), cv2.LINE_AA)
Otra función que trabaja de manera similar es cv2.fillConvexPoly(...)
.
Dibujar una elipse
Para esta tarea usamos cv2.ellipse()
de la siguiente manera:
cv2.ellipse(img, (400, 360), (100, 50), 0, 45, 360, (255, 0, 255), -1, cv2.LINE_AA)
Los parámetros para la función son:
Esta función nos permite tener mucho control sobre la figura dibujar, para una explicación más detallada de cada uno de los parámetros visita la documentación oficial.
Dibujar marcadores
OpenCV nos proporciona la función cv2.drawMarker(...)
que nos permite dibujar uno de los marcadores seleccionado, debemos indicar su posición, el marcador, su color y opcionalmente el tamaño del mismo, por ejemplo:
for marker in range(0, 7):
offset = 60 * marker
cv2.drawMarker(img, (100 + offset, 20), (0,255,0), marker)
cv2.drawMarker(img, (100 + offset, 60), (0,0,255), marker, 40, 1, cv2.LINE_AA)
cv2.drawMarker(img, (100 + offset, 120), (255,0,0), marker, 40, 2)
Estos son los marcadores disponibles:
- MARKER_CROSS
- MARKER_TILTED_CROSS
- MARKER_STAR
- MARKER_DIAMOND
- MARKER_SQUARE
- MARKER_TRIANGLE_UP
- MARKER_TRIANGLE_DOWN
Dibujar una flecha
Esta es la última función de dibujo que veremos cv2.arrowedLine()
nos sirve para dibujar una flecha, solo será necesario indicar el punto de inicio y final de la misma, ejemplo:
cv2.arrowedLine(img, (10, 20), (100, 20), (255, 100, 100), 1, cv2.LINE_AA)
cv2.arrowedLine(img, (10, 40), (150, 40), (255, 100, 100), 2, cv2.LINE_AA, 0, 0.3)
cv2.arrowedLine(img, (10, 60), (100, 60), (255, 100, 100), 2, cv2.LINE_4)
Al dibujar la flecha del medio cambiamos el porcentaje que ocupa la punta de la fecha a 0.3.
Hola, tengo una duda.
ResponderEliminarEn qué unidades se maneja la imagen, es por pixeles o alguna otra?
Correcto, son pixeles.
Eliminar