霍夫变换

2020-06-01  本文已影响0人  原上的小木屋

基本原理

基本步骤

  1. 我们用边缘图像来对边缘像素进行霍夫变换。
    canny边缘检测步骤
  1. 在霍夫变换后获取值的直方图并选择最大点。
  2. 对极大点的r和t的值进行霍夫逆变换以获得检测到的直线的参数。

详细步骤

def Hough_Line_step1(edge):
    ## Voting
    def voting(edge):
        H, W = edge.shape
        drho = 1
        dtheta = 1
        # get rho max length
        rho_max = np.ceil(np.sqrt(H ** 2 + W ** 2)).astype(np.int)#计算大于等于该值的最小整数,这里需要解释一下,rho_max即为sqrt(a**2+b**2)
        #是因为后面的公式rho=asint+bcost,可以用高中知识轻易证明,rho的绝对值要小于rho_max
        # hough table#计算霍夫表格
        hough = np.zeros((rho_max * 2, 180), dtype=np.int)#生成霍夫表格的尺#寸,因此可以看到这里hough的高度为二倍的rho_max,也就很容易理解后面的hough[rho+rho_max,theta]+=1了
        # get index of edge
        ind = np.where(edge == 255)#取得边缘像素点的索引
        ## hough transformation
        for y, x in zip(ind[0], ind[1]):
            for theta in range(0, 180, dtheta):
                # get polar coordinat4s
                t = np.pi / 180 * theta#依次计算角度的弧度值
                rho = int(x * np.cos(t) + y * np.sin(t))#依次计算不同弧度值对应的不同的rho值
                # vote
                hough[rho + rho_max, theta] += 1#进行投票,票数在一定地方集中
        out = hough.astype(np.uint8)
        return out
    # voting
    out = voting(edge)
    return out

第一步完成后,需要对投票结果进行非极大值抑制,和canny边缘检测最后一步的阈值滞后中的落入高阈值与低阈值区间的处理方法极为相似,即抽取八邻域与中间点做比较,如果有比中间像素值大的情况,中间像素值置为0

    # non maximum suppression
    def non_maximum_suppression(hough):
        rho_max, _ = hough.shape #得到hough图像的尺寸
        ## non maximum suppression
        for y in range(rho_max):
            for x in range(180):
                # get 8 nearest neighbor
                x1 = max(x - 1, 0)#非常巧妙的处理,兼顾了边缘和中央区域
                x2 = min(x + 2, 180)#非常巧妙的处理,兼顾了边缘和中央区域
                y1 = max(y - 1, 0)#非常巧妙的处理,兼顾了边缘和中央区域
                y2 = min(y + 2, rho_max - 1)#非常巧妙的处理,兼顾了边缘和中央区域
                if np.max(hough[y1:y2, x1:x2]) == hough[y, x] and hough[y, x] != 0:
                    pass
                # hough[y,x] = 255
                else:
                    hough[y, x] = 0
        return hough

最后一步,也就是根据特征点把线画在原图上的一步,叫rough反变换

    def inverse_hough(hough, img):#将经历第一步第二步过程的rough图像和原图像作为参数输入进来
        H, W, _ = img.shape#原图像尺寸
        rho_max, _ = hough.shape#hough图像尺寸
        out = img.copy()#复制一个
        # get x, y index of hough table
        ind_x = np.argsort(hough.ravel())[::-1][:20]#按行重组倒序取前20个值得索引坐标
        ind_y = ind_x.copy()
        thetas = ind_x % 180#取得角度
        rhos = ind_y // 180 - rho_max / 2#取得rhos值,这个不必解释,很好理解,和前面的第一个函数结合起来看非常明显
        # each theta and rho#坐标系转换
        for theta, rho in zip(thetas, rhos):
            # theta[radian] -> angle[degree]
            t = np.pi / 180. * theta#算出t
            # hough -> (x,y)
            for x in range(W):
                if np.sin(t) != 0:
                    y = - (np.cos(t) / np.sin(t)) * x + (rho) / np.sin(t)#依据x逐次算出y的坐标
                    y = int(y)
                    if y >= H or y < 0:
                        continue
                    out[y, x] = [0, 0, 255]#在图中表示出来
            for y in range(H):#依据y逐步算出x的坐标
                if np.cos(t) != 0:
                    x = - (np.sin(t) / np.cos(t)) * y + (rho) / np.cos(t)
                    x = int(x)
                    if x >= W or x < 0:
                        continue
                    out[y, x] = [0, 0, 255]#将其表示出来
        out = out.astype(np.uint8)
        return out

下面我们来总结一下霍夫检测直线的具体步骤

  1. 进行高斯滤波
  2. 两个方向上进行sobel滤波
  3. 将两个方向上sobel滤波之后的两个矩阵变换为一个梯度幅度矩阵和一个梯度方向矩阵
  4. 利用梯度幅度矩阵和梯度方向矩阵进行非极大值抑制
  5. 对上一步进行非极大值抑制之后的梯度幅度矩阵进行阈值滞后
    至此,canny边缘检测任务完成,hough变换是建立在canny边缘检测的基础上的
  6. 建立hough矩阵,具体构建方法见上述说明。细节:hough角度0-180rho_max2sqrt(a**2+b**2),依次遍历进行投票
  7. 对hough矩阵进行非极大值抑制(8像素领域)
  8. 排序输出,hough前n个值取其rho及角度thetas,由这两个值反向推的x,y坐标
    至此,hough检测的任务便完成了
上一篇 下一篇

猜你喜欢

热点阅读