霍夫变换---OpenCV-Python开发指南(35)

举报
择城终老 发表于 2021/07/27 00:52:55 2021/07/27
【摘要】 目录 什么是霍夫变换HoughLines函数HoughLines实战HoughLinesP实战HoughCircles实战 什么是霍夫变换 霍夫变换是一种在图像中寻找直线,圆形以及其他简单形状的方法。霍夫变换采用类似于投票的方式来获取当前图像内的形状集合,该变换由Paul Hough(霍夫)于1962年首次提出。 最初的霍夫变换只能用于检测直线,经过发...

什么是霍夫变换

霍夫变换是一种在图像中寻找直线,圆形以及其他简单形状的方法。霍夫变换采用类似于投票的方式来获取当前图像内的形状集合,该变换由Paul Hough(霍夫)于1962年首次提出。

最初的霍夫变换只能用于检测直线,经过发展后,霍夫变换不仅能够识别直线,还能识别其他简单的图形结构,常见的有圆形,椭圆等。

HoughLines函数

在OpenCV中,它给我们提供了cv2.HoughLines()函数来实现霍夫直线变换,该函数要求所有操作的原图是一个二值图像,所以在进行霍夫变换之前,需要将图像进行二值化处理。或者进行Canny边缘检测。

其完整定义如下:

def HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None):

  
 
  • 1

image:原始图形,必须是8位单通道的二值图像

rho:以像素为单位的距离r的精度。一般情况下,使用的精度是1

theta:为角度θ的精度。一般情况下,使用的精度是Π/180,表示要搜索所有可能的角度

threshold:阈值。该值越小,判定出直线就越多。识别直线时,要判定多少个点位于该直线上。在判定直线是否存在时,对直线所穿过的点的数量进行评估,如果直线所穿过的点的数量小于阈值,则认为这些点恰好在算法构成直线,但是在原始图像中该直线并不存在;如果大于阈值,则认为直线存在。所以,如果阈值越小,就会得到较多的直线;阈值越大,就会得到较少的直线

lines:返回值,它的每个元素都是一对浮点数,表示检测到的直线的参数,即(r,θ)。是numpy.ndarray类型。

HoughLines实战

了解了函数常用的参数之后。下面,我们通过一个棋盘来进行霍夫变换。代码如下:

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

img = cv2.imread("35.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLines(edges, 1, np.pi / 180, 140)
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, 255, 0), 2)
plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行之后,效果如下:
霍夫变换

HoughLinesP实战

使用HoughLines虽然可以完成霍夫变换,但其本身存在非常严重的误检测。为了解决这个问题,OpenCV加入了概率霍夫变换函数cv2.HoughLinesP()函数。

其完整定义如下:

def HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None): 

  
 
  • 1

image:原始图像,比如为8位单通道二值图像

rho:同上

theta:同上

threshold:同上

lines:同上

minLineLength:用来控制”接受直线的最小长度“的值。默认值为0

maxLineGap:用来控制接受共线线段之间的最小间隔,即在一条直线中两点的最大间隔。如果两点间的间隔超过了参数maxLineGap的值,就认为这两点不在一条直线上。默认值为0

将上面的例子,使用HoughLinesP改进以下:

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

img = cv2.imread("35.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 10, 10)
for line in lines: x1, y1, x2, y2 = line[0] cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 5)
plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行之后,效果如下:

霍夫变换2
可以看到,这里我们通过函数HoughLinesP,将棋盘线完整的全标记出来了。

HoughCircles实战

霍夫变换出来用来检测直线外,我们还可以用来检测其他的几何对象。实际上,只要是能用一个方程式表示的对象,都适合用霍夫变换来检测。

其中,我们就可以使用霍夫圆变换来检测图像中的圆。这里我们只需要考虑圆心坐标(x,y)与半径r共3个参数。

在OpenCV中要经过2个步骤:

  1. 找出可能存在圆的位置(圆心)
  2. 根据1计算半径

在OpenCV中,它给我们提供的霍夫圆变换函数为cv2.HoughCircle()。该函数也是将Canny边缘检测与霍夫变换结合,唯一的区别是,不要我们进行Canny边缘检测,该函数自动先进行Canny边缘检测。

其完整定义如下:

def HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None): 

  
 
  • 1

image:原始图像,8位单通道灰度图像

method:检测方法,HOUGH_GRADIENT是唯一可用的参数值。该参数代表霍夫圆检测中两轮检测所使用的方法

dp:累计器分辨率,它是一个分割比例,用来指定图像分辨率与圆心累加器分辨率的比例。例如,如果dp=1,则输入图像和累加器具有相同的分辨率

minDist:圆心间最小间距。该值被作为阈值来使用,如果存在圆心间距小于该值的多个圆,则仅有一个会被检测出来。因此,如果该值太小,则会有很多临近的圆被检测出来;如果该值很大,则可能会在检测时漏掉很多圆

circles:返回值,有圆心坐标和半径构成的numpy.ndarray类型。

param1:该参数缺省,默认100。它对应的是Canny边缘检测器的高阈值(低阈值是高阈值的二分之一)

param2:圆心位置必须受到的投票数。只有在第1论筛选的过程中,投票数超过该值的圆,才有资格进入第2轮的筛选。因此,该值越大,检测到的圆越少;该值越小,检测到的圆越多。也是缺省值,默认100

minRadius:圆半径最小值,小于该值的圆不会被检测出来。也是缺省值,默认0,不起作用

maxRadius:圆半径的最大值,大于该值的圆不会被检测出来。也是缺省值,默认0,不起作用

下面,我们来用一个奥运五环的照片,进行霍夫圆变换。代码如下:

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

img = cv2.imread("35_1.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 300, param1=50, param2=20,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0, :]: cv2.circle(img, (i[0], i[1]), i[2], (255, 0, 0), 12) cv2.circle(img, (i[0], i[1]), 2, (255, 0, 0), 12)

plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行之后,效果如下:
霍夫圆

文章来源: liyuanjinglyj.blog.csdn.net,作者:李元静,版权归原作者所有,如需转载,请联系作者。

原文链接:liyuanjinglyj.blog.csdn.net/article/details/114033863

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。