c++ hough变换代码_hough变换原理以及实现(转载)

原理链接如下:陌归:霍夫(Hough)变换之直线检测

代码链接:Ganso:Fundamentals——从车道线检测谈到霍夫变换

同样是一篇讲解原理的番外,这一篇主要讲解CV中常用的霍夫变换的数学原理。

霍夫变换的由来

“霍夫变换于1962年由Paul Hough首次提出,最初的Hough变换是设计用来检测直线和曲线,起初的方法要求知道物体边界线的解析方程,但不需要有关区域位置的先验知识。后于1972年由Richard Duda & Peter Hart推广使用。”

其实,霍夫变换的中心思想就是通过坐标变换来检测直线,后来经过改进,就可以检测椭圆等。

霍夫线变换

坐标系的角度:

说起直线,我们会想到笛卡尔坐标系(即x-y坐标系)下的直线方程,细分之则有点斜式、截距式等,

是我们最熟悉的一种。但直线垂直于x轴时斜率
不存在,这给我们带来许多不便之处。

这时极坐标就carry全场了,它与笛卡尔坐标系的转换关系:

,变形可得
为原点到直线的距离,也常用
表示,示意图如下:

50dca3042e2bd79d6056f916f9ede15f.png

由此极坐标下,直线可用

表示。这就启发我们,同一直线上的点具有相同的

1c62d69e8fb9800e316d1de66dd5cfc9.png
x-y坐标系下的一个点在rho-theta坐标系下为正弦曲线

b373328976dee12818644b3062262b7a.png
同一直线上的点会有相同的rho和theta,即在rho-theta下交于一点

统计学的角度:

内容出自:Opencv学习笔记-----霍夫变换直线检测及原理理解 - CSDN博客

d85a8c8af9c3106c581046b6d1ba5345.png

如上图,假定在一个8*8的平面像素中有一条直线,并且从左上角

像素点开始分别计算
为0°、45°、90°、135°、180°时的
,图中可以看出
分别为
,并给这5个值分别记一票,同理计算像素点
为0°、45°、90°、135°、180°时的
,再给计算出来的5个
值分别记一票,此时就会发现
的这个值已经记了两票了,以此类推,遍历完整个8*8的像素空间的时候
就记了5票, 别的
值的票数均小于5票,所以得到该直线在这个8*8的像素坐标中的极坐标方程为
,到此该直线方程就求出来了。

霍夫圆变换

霍夫圆变换使用的算法叫霍夫梯度法,对应的函数为HoughCircles,这个函数实际上是对常规找圆算法的一种改进,这里不展开讲,想学习这个原理的同学请参考找圆算法((HoughCircles)总结与优化 - CSDN博客

1. base

导入必要的包,顺便写一个打印图像的函数,cv2与plt颜色通道不一致(所以为什么不用plt导入呢)。

import numpy as np
import matplotlib.pyplot as plt
import cv2

# opencv的颜色通道顺序为[B,G,R],而matplotlib的颜色通道顺序为[R,G,B]。
def plotImg(img):
    if len(img.shape)==3:
        img = img[:,:,(2,1,0)]
        plt.imshow(img)
    else:
        plt.imshow(img, cmap='gray')
    plt.show()

导入图片,感觉如果干扰很多效果也不会太好。

image = cv2.imread('test_image.jpg')
plotImg(image)

b1c6c8e79981c229f5a2a74dbbc9077d.png

canny

灰度,模糊,canny三连击。
canny输入需求如此。

def canny(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray,(5,5),0)
    canny = cv2.Canny(blur, 50, 150)
    return canny

lane_image = np.copy(image)
canny = canny(lane_image)
plotImg(canny)

02e0b2fb2536313b1f37895b50c66a35.png

region_of_interest

手工特征区域?作者的思路也是蛮清奇的。
简单来说就是对于视角前面的三角形区域做了一个mask,全部填充255,与原图像bitwise。

def region_of_interest(image):
    height = image.shape[0]
    polygons = np.array([
        [(200,height), (1100,height), (550,250)]
    ])
    mask = np.zeros_like(image)
    cv2.fillPoly(mask, polygons, 255)
    masked_image= cv2.bitwise_and(image,mask)
    return masked_image

cropped_image = region_of_interest(canny)
plotImg(cropped_image)

a9dbdf7a4a5b8d7682e4c33dc704ba90.png

091455c4df7168d0a199a34b6f9b1837.png

2. Hough Transform

将图像提取边缘之后获得了很多杂乱的点,而我们需要做的就是找到过这些点的公共直线。

点斜式方程

点斜式方程是

,那么对于经过下图黑色点的直线簇,我们可以将其映射到一个以m,b位坐标的空间,b是m的线性函数。对于不同的两个点,我们可以将其直线簇映射到mb空间的两个直线上,而mb空间两个直线的交点(m,b)就是这两个点公共直线的参数。但是这样还是存在问题的,当直线是垂直的时候,m趋向于无穷,不好表示,我们需要另外一种映射。

5cd13ce38b3e10625997882995b54edf.png

极坐标方程

在极坐标空间中,对于过固定点的直线,过原点做垂线,记距离为

,夹角为
,通过图示我们可以得到对于过一点x,y的直线簇有:

e528fe452f6199c8bb80a8d1b115f372.png

也就是说过固定点的直线簇

之间有一定的函数关系。

霍夫变换

我们将过每个点的直线簇映射到极坐标空间,基本都由一条曲线表示,比如图示的三个点,这样。曲线的交点对应的坐标就是过所有点的直线的极坐标参数。

e26e4e588eaa23a5a499ea1c0a5f328d.png

投票机制

当图片上的点非常多时,所有曲线并不期望相交于一点。我们可以将霍夫空间划分为一个个patch,当一个patch上面的交点满足大于某个threshold时,我们视为这些点有它们的公共直线。

7c972031b69a5892b4fc43d60ba02f4d.png

3. cv2实现

cv.2HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]])

参数
image 图像。
rho、theta:分辨率。(分别率就是指同一个角度,如果计算出两点的rio值小于2,则认为是同一直线。)
threshold:投票阈值。
lines:没有查到。
minLineLength:最小线条长度。
maxLineGap:最大线条间隔。

def display_lines(image,lines):
    line_image = np.zeros_like(image)
    if lines is not None:
        for line in lines:
            x1, y1, x2, y2 = line.reshape(4)
            cv2.line(line_image, (x1,y1), (x2,y2),(255,0,0),10)
    return line_image
            
lines = cv2.HoughLinesP(cropped_image, 2, np.pi/180, 100, np.array([133,2]), minLineLength=40, maxLineGap=5)
line_image = display_lines(image,lines)
plotImg(line_image)

combo_image = cv2.addWeighted(lane_image,0.8, line_image,1,1)
plotImg(combo_image)

霍夫变换求直线

89d743002caca940846f802347727a37.png

8c807c0b2ee2ddee46824cefc53a7ab4.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值