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.
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.
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.
Como podemos ver marcamos en la imagen original los círculos encontrados y su centro.
Es todo de momento, hasta luego.
Comentarios
Publicar un comentario