Transformada de Hough para el procesamiento de imágenes para detectar líneas rectas

I. Introducción

La transformada de Hough es una extracción de características que se usa ampliamente en el análisis de imágenes, la visión artificial y el procesamiento de imágenes digitales. Inventada por Richard Duda y Peter Hart en 1972 AD, y llamada transformada de Hough generalizada (transformada de Hough generalizada), la transformada de Hough generalizada está relacionada con la patente de Paul Hough en 1962 antes. La transformada de Hough clásica es para detectar líneas rectas en la imagen. Después de eso, la transformada de Hough no solo puede reconocer líneas rectas, sino también reconocer cualquier forma, como círculos y elipses. En 1981, debido a un artículo de revista "Generalización de la transformada de Hough para detectar formas arbitrarias" de DanaH.Ballard, la transformada de Hough se hizo popular en la comunidad de visión artificial. La transformada de Hough se utiliza para identificar características en objetos, como líneas. El flujo de su algoritmo es aproximadamente el siguiente: dado un objeto y el tipo de forma a identificar, el algoritmo realizará una votación en el espacio de parámetros para determinar la forma del objeto, y esto está determinado por el parcial en el espacio del acumulador. máximo (máximo local) a determinar.

Dos, transformación de Hough

Una recta puede estar compuesta por dos puntos A = ( x 1 , y 1 ) A=(x_1,y_1)A=( X1,y1) sumaB = ( x 2 , y 2 ) B=(x_2,y_2)B=( X2,y2) determinado (coordenadas cartesianas)

Por otro lado, y = kx + by=kx+by=k x+b también se puede escribir sobre( k , q ) (k,q)( k ,q ) expresión de la función (espacio de Hough):
{ q = − kx 1 + y 1 q = − kx 2 + y 2 \left\{ \begin{aligned} q=-kx_1+y_1 \\ q=-kx_2 +y_2 \ \ \end{alineado} \right.{ q=k x1+y1q=k x2+y2
El proceso de transformación del espacio es como se muestra en la siguiente figura:
el espacio transformado se convierte en el espacio de Hough. Es decir: una línea recta en el sistema de coordenadas cartesianas corresponde a un punto en el espacio de Hough.
inserte la descripción de la imagen aquí
Lo contrario también es cierto (una línea recta en el espacio de Hough corresponde a un punto en el sistema de coordenadas cartesianas):
inserte la descripción de la imagen aquí
dos puntos en el sistema de coordenadas cartesianas corresponden a dos líneas en el espacio de Hough:
inserte la descripción de la imagen aquí
si los tres puntos en el sistema de coordenadas cartesianas son colineal, el correspondiente Las tres líneas del espacio de Hough se intersecan en un punto
inserte la descripción de la imagen aquí
El método básico de posprocesamiento de la transformada de Hough: seleccione el punto donde convergen tantas líneas rectas como sea posible.
Sin embargo, según el sistema de coordenadas cartesianas, se presentará la siguiente situación: cuando la línea de los puntos en el espacio de la imagen es perpendicular al eje x, la pendiente es infinita y el punto de intersección no se puede encontrar en el espacio de Hough. Por lo tanto, la gente eventualmente introdujo la notación de coordenadas polares.
inserte la descripción de la imagen aquí
El principio de la detección de la línea de Hough en coordenadas polares es exactamente el mismo que el de las coordenadas rectangulares. Lo único que debe volver a derivarse es la función del parámetro de coordenadas polares del espacio de Hough: y = ( − cos θ sin θ ) x +
rsin θ y=\left (-\frac{cos\theta}{sin\theta}\right)x+\frac{r}{sin\theta}y=( -s en θcos θ)X+s en θr
Definición:
r = xcos θ + ysen θ r=xcos\theta+ysen\thetar=x cos θ+ys en θ
si para un punto dado( x 0 , y 0 ) (x_0,y_0)( X0,y0) , lo que significa que cada par de( r , θ ) (r,\theta)( R ,θ ) Representa un camino a través del punto( x θ , y θ ) (x_\theta,y_\theta)( Xi,yi) línea recta. Dibujamos todas las rectas que lo atraviesan en el plano de coordenadas polares a radio polar y ángulo polar, y obtendremos una curva seno, por ejemplo, para un punto dado (x 0 = 8 y y 0 = 6 ) (x_0 = 8 y y_0= 6)( X0=8 suma y0=6 ) Podemos dibujar la siguiente figura (en el plano):
inserte la descripción de la imagen aquí
la fórmula de conversión entre coordenadas polares y coordenadas cartesianas, a partir de coordenadas polares( r , θ ) (r, θ)( R ,θ ) en el sistema de coordenadas cartesianas( x , y ) (x,y)( X ,y ) :
{ x = rcos θ y = rsen θ \left\{ \begin{alineado} x=rcos\theta \\ y=rsen\theta \\ end{alineado} \right.{ X=rcos θy=rs en θ
Convertir ( x , y ) de coordenadas cartesianas (x,y)( X ,y ) a coordenadas polares( r , θ ) (r,θ)( R ,θ ) :
r = x 2 + y 2 θ = arctan ( y / x ) r=\sqrt{x^2+y^2} \\ \theta=arctan(y/x)r=X2+y2 i=a rc t an ( y / x )
en el sistema de coordenadas polares es en realidad lo mismo: un punto en coordenadas polares → una línea recta en el espacio de Hough, pero el espacio de Hough ya no es [ k , q ][k,q][ k ,q ] , pero( r , θ ) (r,\theta)( R ,yo ) .

3. Detección de línea

De la introducción anterior, podemos ver que dibujando x − y xyXLos puntos en el espacio de coordenadas y corresponden a curvas en el espacio de parámetros, y luego calcula el punto de intersección de las curvas en el espacio de parámetros para obtener los parámetros que se buscan. Pero todavía hay un problema: cuando hay múltiples intersecciones de las curvas en el espacio de parámetros, ¿cómo elegir la solución más probable?
En el cálculo específico, el espacio de parámetros se puede dividir en la llamada unidad de acumulaciónA ( θ , ρ ) A(\theta,\rho)un ( yo ,ρ ) _ Como se muestra en la siguiente figura, parax − y xyXCada punto que no sea de fondo del plano y ( xk , yk ) (x_k,y_k)( Xk,yk) ,θ \ thetaθ es igual a cada valor de subdivisión posible, segúnθ = − xk θ + yk \theta=-x_k\theta+y_ki=xki+ykCalcular el correspondiente ρ \rhovalor de ρ , cada cálculo de un grupo deA ( θ , ρ ) A(\theta,\rho)un ( yo ,ρ ) ,paraA ( θ , ρ ) = A ( θ , ρ ) + 1 A(\theta,\rho)=A(\theta,\rho)+1un ( yo ,r )=un ( yo ,r )+1 . Después de calcular todos los resultados, encuentreA ( θ , ρ ) A(\theta,\rho)un ( yo ,ρ ) correspondiente al valor pico deθ \thetaθ yρ \rhoρ , se puede detectar la línea recta. ( θ min , θ max ) (\theta_{min},\theta_{max})( yominuto,imáximo _)( ρ min , ρ max ) (\rho_{min},\rho_{max})( rminuto,rmáximo _) es el rango de parámetros deseado:0 ο ≤ θ ≤ 18 0 ο 0^\omicron \leq\theta \leq180^\omicron0Eli18 0ο− D ≤ θ ≤ D -D \leq\theta \leq D- reiD ,DDD es la longitud de la diagonal de la imagen. θ \ thetaθ yρ \rhoEl número de subdivisiones de ρ determina la precisión de los resultados de detección.
inserte la descripción de la imagen aquí

Durante el proceso de votación, puede ver el siguiente GIF:
inserte la descripción de la imagen aquí
los puntos cian de la izquierda representan los píxeles de la imagen y los puntos amarillos representan la búsqueda de cada punto desde diferentes ángulos. La mitad derecha es la placa de votación, cuanto más claro es el color, más votos.

4. Implementación del código

1. aunque detección

def lines_detector_hough(img,ThetaDim=None, DistStep=None, threshold=None, halfThetaWindowSize=2,
                         halfDistWindowSize=None):
    '''

    :param img: 经过边缘检测得到的二值图
    :param ThetaDim: hough空间中theta轴的刻度数量(将[0,pi)均分为多少份),反应theta轴的粒度,越大粒度越细
    :param DistStep: hough空间中dist轴的划分粒度,即dist轴的最小单位长度
    :param threshold: 投票表决认定存在直线的起始阈值
    :return: 返回检测出的所有直线的参数(theta,dist)和对应的索引值,
    '''
    row,col= edge.shape
    if ThetaDim == None:
        ThetaDim = 90
    if DistStep == None:
        DistStep = 1
    # 计算距离分段数量
    MaxDist = np.sqrt(row ** 2 + col ** 2)
    DistDim = int(np.ceil(MaxDist / DistStep))

    if halfDistWindowSize == None:
        halfDistWindowSize = int(DistDim /50)

    # 建立投票
    accumulator = np.zeros((ThetaDim, DistDim))  # theta的范围是[0,pi). 在这里将[0,pi)进行了线性映射.类似的,也对Dist轴进行了线性映射
    #
    sinTheta = [np.sin(t * np.pi / ThetaDim) for t in range(ThetaDim)]
    cosTheta = [np.cos(t * np.pi / ThetaDim) for t in range(ThetaDim)]
    #计算距离(rho)
    for i in range(row):
        for j in range(col):
            if not edge[i, j] == 0:
                for k in range(ThetaDim):
                    accumulator[k][int(round((i * cosTheta[k] + j * sinTheta[k]) * DistDim / MaxDist))] += 1
    M = accumulator.max()
#---------------------------------------
    #非极大抑制
    if threshold == None:
        threshold = int(M * 1.369/ 10)
    result = np.array(np.where(accumulator > threshold))  # 阈值化
    #获得对应的索引值
    temp = [[], []]
    for i in range(result.shape[1]):
        eight_neiborhood = accumulator[
                           max(0, result[0, i] - halfThetaWindowSize + 1):min(result[0, i] + halfThetaWindowSize,
                                                                              accumulator.shape[0]),
                           max(0, result[1, i] - halfDistWindowSize + 1):min(result[1, i] + halfDistWindowSize,
                                                                             accumulator.shape[1])]
        if (accumulator[result[0, i], result[1, i]] >= eight_neiborhood).all():
            temp[0].append(result[0, i])
            temp[1].append(result[1, i])
    #记录原图所检测的坐标点(x,y)
    result_temp= np.array(temp)
#-------------------------------------------------------------
    result = result_temp.astype(np.float64)
    result[0] = result[0] * np.pi / ThetaDim
    result[1] = result[1] * MaxDist / DistDim
    return result,result_temp

2. Dibujar un código de línea recta

def drawLines(lines, edge, color=(255, 0, 0), err=3):

    '''
    :param lines: 检测后的直线参数
    :param edge: 原图
    :param color: 直线的颜色
    :param err:检测的可接受的误差值
    :return: 无
    '''

    if len(edge.shape) == 2:
        result = np.dstack((edge, edge, edge))
    else:
        result = edge
    Cos = np.cos(lines[0])
    Sin = np.sin(lines[0])

    for i in range(edge.shape[0]):
        for j in range(edge.shape[1]):
            e = np.abs(lines[1] - i * Cos - j * Sin)
            if (e < err).any():
                result[i, j] = color
    plt.imshow(result, cmap='gray')
    plt.axis('off')
    plt.show()

3. Dibuja el código de espacio de Hough

def data_img(data):

    '''
    :param data: 直线上含有的点(x,y)
    :return: 输出hough空间图像
    '''

    fig = plt.figure()  # 新建画布
    ax = axisartist.Subplot(fig, 111)  # 使用axisartist.Subplot方法创建一个绘图区对象ax
    fig.add_axes(ax)
    ax.axis[:].set_visible(False)  # 隐藏原来的实线矩形
    ax.axis["x"] = ax.new_floating_axis(0, 0, axis_direction="bottom")  # 添加x轴
    ax.axis["y"] = ax.new_floating_axis(1, 0, axis_direction="bottom")  # 添加y轴
    ax.axis["x"].set_axisline_style("->", size=1.0)  # 给x坐标轴加箭头
    ax.axis["y"].set_axisline_style("->", size=1.0)  # 给y坐标轴加箭头
    t = np.arange(-np.pi / 2, np.pi / 2, 0.1)
    ax.annotate(text='x', xy=(2 * math.pi, 0), xytext=(2 * math.pi, 0.1))  # 标注x轴
    ax.annotate(text='y', xy=(0, 1.0), xytext=(-0.5, 1.0))  # 标注y轴
    for i in range(data.shape[1]):
        rho = data[0][i] * np.cos(t) + data[1][i] * np.sin(t)
        plt.plot(t, rho)
    plt.show()

4. Resultados de la prueba

inserte la descripción de la imagen aquí
Haga clic aquí para descargar la imagen de detección.
Todos los códigos se pueden encontrar en mi almacén de GitHub . Si el código es útil, haga clic en estrella
hough. Antes de la detección, el operador astuto necesita detectar el borde básico. Haga clic aquí para ver el contenido relevante de el algoritmo astuto

Si este artículo te es útil, ¡síguelo y dale me gusta! ! ! ! !

Supongo que te gusta

Origin blog.csdn.net/weixin_42491648/article/details/131848334
Recomendado
Clasificación