Detección de líneas y círculos usando la transformada de Hough con OpenCV

La Transformada de Hough, técnica propuesta y patentada por Paul Hough en 1962 es comúnmente usada en aplicaciones de visión por computador para detectar formas geométricas como círculos o líneas, OpenCV implementa esta técnica a través de dos funciones: cv::HoughCircles() y cv::HoughLines(), en el presente tutorial veremos como podemos utilizar ambas funciones para detectar las respectivas formas.

Detección de Líneas

Para poder detectar líneas tenemos dos implementaciones, cv2.HoughLines() y cv2.HoughLinesP(), antes de aplicar cualquiera de ellas, convertiremos la imagen a escala de grises y detectaremos los bordes, para lo que utilizaremos la función cv2.Canny(), veamos un ejemplo sencillo en Python 3.x.

import cv2
import numpy as np

img = cv2.imread('sudoku.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize = 3)

lines = cv2.HoughLines(edges, 1, np.pi/180, 200)

for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))

    cv2.line(img, (x1,y1), (x2,y2), (0, 0, 255), 1, cv2.LINE_AA)

cv2.imshow('Bordes de Imagen', edges)
cv2.imshow('Detector de Lineas', img)
cv2.waitKey()

Cada línea que encuentra es representada por dos valores, rho ρ y theta Θ, que representan la distancia de la perpendicular de la recta al punto de origen y el ángulo de rotación de la perpendicular, respectivamente.

Los parámetros cv2.HoughLines(edges, 1.2, PI/180, 200), establecen, primero la imagen binaria con los bordes encontrados, luego en valor rho y theta en radianes, el último parámetro establece el máximo umbral aceptable, esta función devuelve un conjunto de líneas expresadas por los valores, rho y theta, por ello los procesamos para obtener las coordenadas x, y iniciales y finales que usaremos para dibujar la línea.

detectar líneas

Otra implementación es el método probabilístico de la transformada de Hough, en este caso la función recibe dos parámetros extras, minLineLength que establece la longitud mínima de la línea y maxLineGap que indica el intervalo máximo de líneas para tratarlas como una sola.

import cv2
import numpy as np

img = cv2.imread('sudoku.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize = 3)

lines = cv2.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)

for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1,y1), (x2,y2), (0,255,0), 1, cv2.LINE_AA)

cv2.imshow('Bordes de Iamgen', edges)
cv2.imshow('Detector de Lineas', img)
cv2.waitKey()

A diferencia del la función anterior, esta nos devuelve las coordenadas de la línea directamente.

OpenCV detección de líneas

Detección de Círculos

De un modo muy similar podemos detectar los círculos presentes en una imagen a escala de grises, veamos un ejemplo de la función cv::HoughCircle(), antes de aplicar la función usaremos un filtro de mediana para reducir ruido y mejorar los resultados, esta función devuelve un conjunto de 3 valores, las coordenadas, X e Y y el radio del círculo.

import cv2
import numpy as np

img = cv2.imread('data/stuff.jpg')
src = cv2.medianBlur(img, 5)
src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

circles = cv2.HoughCircles(src, cv2.HOUGH_GRADIENT, 1, 20,
                            param1=50, param2=30, minRadius=0, maxRadius=0)

circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # dibujar circulo 
    cv2.circle(img, (i[0], i[1]), i[2], (0,255,0), 2)
    # dibujar centro
    cv2.circle(img, (i[0], i[1]), 2, (0,0,255), 3)

cv2.imshow('detected circles', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

De momento OpenCV implementa solo el método HOUGH_GRADIENT, este es el segundo parámetro, el primero como siempre es la imagen de entrada, los demás nos servirán para restringir los círculos detectados.

OpenCV detección de círculos

Como podemos ver marcamos en la imagen original los círculos encontrados y su centro.

Es todo de momento, hasta luego.

Comentarios

Temas relacionados

Entradas populares de este blog

Conectar SQL Server con Java

Entrenar OpenCV en Detección de Objetos

Conociendo la clase cv::Mat de OpenCV

Manipular pixeles OpenCV Python

Detección de contornos con OpenCV Python