opencv在python中的哈夫直线变换(Hough Line Transform)

说明

在做项目中,需要识别图片中的表格,了解到opencv中的哈夫变换,相关文档只有英文版,未找到中文版,自行翻译了一遍(能力有限渣翻译),其中拓展阅读内容引自:Python OpenCV -- 霍夫线变换(十二),可帮助理解,仅供参考。

目标

在本章中,我们可以:

  • 了解哈夫变换的概念

  • 如何使用哈夫变换识别图片中的直线

  • 了解以下函数:cv2.HoughLines(), cv2.HoughLinesP()

理论

哈夫变换(Hough Transform)是一种流行的图形识别技术,如果数学模型中的图形可以被肉眼识别,那么即使图形损坏或者有一点扭曲,哈夫变换也可以识别图形,接下来介绍它的工作原理。

直线可以通过类似 y = mx + c 或 极坐标 ρ = x cosθ + y sinθ(其中ρ表示原点到直线的垂直距离,θ是垂直线与水平轴之间的逆时针方向夹角,方向主要取决于如何放置坐标系)来表示。如下图:

如果线经过原点下方,那就有小于180°的正[RHO][1]和夹角。如果线经过原点上方,相较于使用大于180°的夹角,opencv会选择使用小于180°的夹角,并采用负的RHO。垂直线是0°,水平线是90°。

来看看哈夫变换如何处理线条。任何线条都可以由(ρ,θ)2个参数形容,首先创建一个二维数组或者累加器(存储2个参数的值),初始化为0。用行表示ρ,用列表示θ,数组的大小取决于精确度需求,假设精确度为1°,则需要180列,ρ最大距离可能是图片对角线的长度,所以设置精确度为1像素,那么行数就是图片对角线长。


拓展阅读

1、

用 极坐标系 来表示直线,直线的表达式可为:

y = (- \frac{cosθ}{sinθ})x + (\frac{r}{sinθ})

化简得: r = x cosθ + y sinθ

2、一般来说对于点(x_0,y_0), 我们可以将通过这个点的一族直线统一定义为:

r_\theta = x_0 · cos\theta + y_0 · sin\theta

这就意味着每一对(r_\theta, \theta) 代表一条通过点(x_0,y_0)的直线.


假设有一个100*100的图片,有一条水平线在中间,获取这条线的第一个点,已知它的(x, y)值,然后将θ = 0,1,2,……,180放入线条方程中,获取ρ值。对于每个(ρ, θ)单元格,累加器中与之相关的(ρ, θ)单元格每次增加的值为1,所以在累加器中,(50, 90) = 1和一些其他单项相关联。

然后取线条上的第二个点,进行以上相同的动作,增加与之相关联的(ρ, θ)单元格,此时(50, 90) = 2,现在的操作都会增加(ρ, θ)的值。继续为线条上的每个点进行相同的操作,在每个点,(50, 90)单元格可以增值或者计数,其他单元格可能不会被计数。通过这种方式,最后(50, 90)单元格会得到最大的计数。如果在计数器中搜索最大计数,就可以得到(50, 90 )的值,表示在距离原点50,90°角的地方有一条线,在以下动图中显示。

这就是哈夫变换作用于线条的原理,可以使用numpy来执行它。下图展示了累加模型,图中高亮的位置代表着图片中可能是线条的参数。


拓展阅读

1、如果对于一个给定点(x_0,y_0) 我们在极坐标对极径极角平面绘出所有通过它的直线, 将得到一条正弦曲线. 例如, 对于给定点 x_0 = 8y_0 = 6我们可以绘出下图 (在平面 \theta - r):

只绘出满足下列条件的点r > 00 < \theta < 2\pi.

2、我们可以对图像中所有的点进行上述操作. 如果两个不同点进行上述操作后得到的曲线在平面\theta - r相交, 这就意味着它们通过同一条直线. 例如, 接上面的例子我们继续对点: x_1 = 9, y_1 = 4 和点x_2 = 12, y_2 = 3 绘图, 得到下图:

这三条曲线在\theta - r平面相交于点(0.925, 9.6), 坐标表示的是参数对(\theta, r) 或者是说点(x_0,y_0), 点(x_1,y_1) 和点(x_2,y_2) 组成的平面内的的直线.

3、一条直线能够通过在平面\theta - r 寻找交于一点的曲线数量来检测. 越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成. 一般来说我们可以通过设置直线上点的 阈值 来定义多少条曲线交于一点我们才认为检测 到了一条直线.

4、这就是霍夫线变换要做的. 它追踪图像中每个点对应曲线间的交点. 如果交于一点的曲线的数量超过了阈值, 那么可以认为这个交点所代表的参数对(\theta, r_\theta) 在原图像中为一条直线.


OpenCV中的哈夫变换

上面讲述的是Opencv中的函数,cv2.HoughLines()。它返回(ρ, θ)值的序列,ρ单位像素,θ单位弧度。第一个参数,输入的图片是一个二进制图片,在使用hough变换之前,应用阈值或使用canny边缘检测。第二和第三个参数分别是ρ和θ的精度,第4个参数是阈值,指可以被认为是一个线条的最小计数值。由于计数值的多少取决于线上的点数,所以这代表了可以被识别为线的最小长度。

import  cv2
import  numpy  as  np

img  =  cv2.imread('dave.jpg')
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  rho,theta  in  lines[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),2)

cv2.imwrite('houghlines3.jpg',img)</pre>

认为第9行代码存在一定错误,应为:


for i in range(0,len(lines)):

    rho,theta = lines[i][0][0],lines[i][0][1]

结果如下:

概率哈夫变换

在哈夫变换中,可以通过2个变量来检测一条线上的点,但花费大量计算。概率哈夫变换是一个优化的哈夫变换,它不会计算所有的点,而是随机的选取一组足以识别直线的点,所以我们需要减少阈值。看下图中关于哈夫变换和概率哈夫变换在哈夫空间的比较:

OpenCV 技术是基于Matas, J. and Galambos, C. and Kittler, J.V.使用概率哈夫变换进行的线条鲁棒检测。它通过cv2.HoughLinesP()来实现,函数有2个新的参数。

  • minLineLength - 线段的最小长度. Line segments shorter than this are rejected.

  • maxLineGap - 使程序识别线段为一条线的线段之间最大的空隙

最好是这样,函数直接返回了线条的两个终点,在前面的实例中,必须找到所有的点,而只获取了线的参数。在这个实例中,所有的事都变得简单直接。

import  cv2
import  numpy  as  np

img  =  cv2.imread('dave.jpg')
gray  =  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges  =  cv2.Canny(gray,50,150,apertureSize  =  3)
minLineLength  =  100
maxLineGap  =  10
lines  =  cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength,maxLineGap)
for  x1,y1,x2,y2  in  lines[0]:
    cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)

cv2.imwrite('houghlines5.jpg',img)</pre>

结果如下:


  1. 曲线饱满度,RHO 值越小,曲线就越平坦;RHO值越大,曲线就越饱满,RHO<0.5,曲线为椭圆,RHO=0.5时,曲线为抛物线;RHO>0.5时,曲线为双曲线!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容