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()

Dibujar: círculos, líneas, rectángulos.

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()

Dibujar: elipses, texto, polígonos.

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)

Dibujar polígono relleno Python OpenCV

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:

Como dibujar una elipse en OpenCV Python

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 en OpenCV desde Python

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)

Como dibujar una flecha OpenCV Python

Al dibujar la flecha del medio cambiamos el porcentaje que ocupa la punta de la fecha a 0.3.

Comentarios

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Procesamiento de imágenes en OpenCV

Acceso a la webcam con OpenCV

Conociendo la clase cv::Mat de OpenCV