霍夫变换

一、霍夫线变换

本小节主要介绍霍夫线变换的基本概念以及如何在图像中检测线条。包括以下函数:cv.HoughLines(), cv.HoughLinesP()

  • 用法如下:
  1. cv.HoughLines( image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]] ) -> lines
  2. cv.Ho直线方程怎么设ughLinesP( image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]] ) -> lines数组

1. 基本概念

如果您可以用数学形式表示该形状,则霍夫变换是一种检测任何动画片汪汪队形状的流行技术。 即使形状有点破损或变形,它也可以检测到。 我们将看到它是如何在一条线上工作的。

一条线可以表示为 yWindows=mx+c 或参数形式,如 =xcos + ysin 其中 是从原点到直线的垂直距离, 是这条垂直线与水平轴形成的角度 逆时针(该方向因您表梯度下降法原理示坐标系的方式动画片少儿小猪佩奇而异。此表示在 OpenCV 中使用)。如下所示:

OpenCV Tutorials 12 - 霍夫变换

因此,如果线在原点下方通过,它将有一个正 rho 和一个小于 180 的角度。如果它在原点上方,而不是采用大于 180 的角度,该角度小于 18梯度稀释的目的0,并且 rho 取负值。 任何垂直梯度是什么意思线将具有 0 度,动画片猫和老鼠水平线将具有 90 度。

现在让我们看看霍夫变换是如何作用动画片猫和老鼠于线条的。 任何一条线都可以用这windows7怎么重装系统两项来表示,(,)。 所以首先它创建一个二维数组或累加器(保存两个参数的值),最初设置为 0。 让行表示 ,列表示 。 数组的大小取决于梯度稀释的目的您需要的精度。 假设您希望角度的精度为 1 度,则需要 180 列。 对于 ,可能的最大动画电影距离是图像的对角线长度。 所以取一个像素精度,行数可以是图像的对角线长度。

考虑一个 100×100 的图像,中间有一条水平线。 取线的第一个点。 你知道它的 (x,y) 值。 现在在直线方程中,输入值 =0,1,2,….,180 并检查你得到的 。 对windows10激活密钥于每个 (,梯度稀释的目的) 对,您在累加器中相应的 (,) 单元格中将值动画片猫和老鼠加一。 所以现在在累加器中,单元格 (50,90) = 1 以及其他一些单元格。

现在取线上的第二个点。 执行与上述相同的操作。 增加与您获得的 (rho, theta)windows7旗舰版 对应的单元格中的值。 这一次,单元格 (50,90) = 2。您实windows11有必要升级吗际上所做的是对 (,) 值进行投票。 您对线上的每个点继续此过程。 在每一点,单元格 (50,90) 将被增加或投票,而其他单元格可能会或可能不会被投票。 这样,最后,单元格 (50,90) 将获得最大票数。 因此,如果您在累加器中动画片熊出没搜索最大票数,您会得动画片小猪佩奇到值 (50,90),表直线方程一般式示该图像中有一条线距原点 50 度,角度为 90 度。 它在下面的动画中得到了很好的展示(图片提供:Amos Storkey)

OpenCV Tutorials 12 - 霍夫变换

这就是霍夫变换对线梯度条起作用的方式。 这很简单,也许直线方程公式你可以自己使用 Numpy 来实现它。 下图显示了蓄能器。 某些位置的亮点表示它们是图像中可能线条的参直线方程一般式数。 (图片提供:数组c语言维基百科)

OpenCV Tutorials 12 - 霍夫变换

2. OpenCV中的霍夫变换

上面解释的所有windows更新有必要吗内容都封装在 OpenCV 函数 cv直线方程两点式.HoughLines() 中。 它只是返回一个 :math:(rho, theta) 值的数组。 以像素为单位, 以弧度为单位。 第一个参数,输入图像应该是二值图像,所以在应用霍夫变换之前应用阈值或使用can梯度下降法原理ny边缘检测。 第二和第三个参数分别是 和 精度。 第四个参数是阈值,这意味着它应该被视为一数组初始化条线的最低权数。 请记住,权数取决于线上的点数。 所以它代表了应该被检测到的线的最小长度。

import cv2 as cv
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
def cv_show(name, img):
    cv.imshow(name, img)
    cv.waitKey(0)
    cv.destroyAllWindows()
def compare(imgs):
  #  for i in range(len(imgs)):
 #       imgs[i][:,-3:-1,:] = [255,255,255]
    res = np.hstack(imgs)
    cv_show('Compare', res)
# 读入图像
img = cv.imread('sudo.jpg')
# 转化为灰度图便于之后的阈值处理或边缘检测
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# Canny边缘检测
edges = cv.Canny(gray,50,150,apertureSize = 3)
# Houghlines的参数分别为 二值图、  精度、  精度、权数阈值(权数越大,越能表明这条线属于直线)
# 返回值为 lines 直线集合,每条直线的首个元素是对应的  和  
lines = cv.HoughLines(edges,1,np.pi/180,200)
res = img.copy()
for line in lines:
    rho,theta = line[0]
    # 利用参数方程找出对应的直线上一点
    # x = cos
    # y = sin
    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))
    cv.line(res,(x1,y1),(x2,y2),(0,0,255),2)
compare([img, res])
cv_show('Edges', edges)

OpenCV Tutorials 12 - 霍夫变换

3. 概率霍夫变换

在霍夫变换中,您直线方程化为参数方程可以看到即使对于windows许可证即将过期怎么办具有两个参数的行,也需要大量计算。 概率霍夫变换是我们看到的霍夫变换的优化梯度下降法原理。 它没有考虑直线方程所有要点。 相反,它只需要一个足以进行线检测的随机点子集。 我们只需要降低门槛。 请参见下图,其中比较了霍夫空间中的霍夫变换和概率霍夫变换。 (图片提供:Fra动画片小猪佩奇nck Bettinger 的主windows更新有必要吗页)

OpenCV Tutorials 12 - 霍夫变换

OpenCV 的实现梯度稀释基于 Matas, J. 和 Galambos, C. 和 Kittler, J.V. [167] 使用渐进概率霍夫变换对线条进行鲁棒检测。 使用的函数是 cv.HoughLinesP()。 它有两个新参数。

  1. minLineLength – 线的最小长度。 比这短的线段被抑制。
  2. maxLin直线方程的五种形式eGap – 线段之间的最大允许间隙,直线方程的斜率若未超过将它们视为一条线。

最好的是,它直接返回线的两个端点。 在以前的情况下,你只得到线的参数,你必须找到所有的点。 在这里,一切都是直接而简单的。之前的简单霍夫变换直线方程化为参数方程需要自己解出直线上的两个点

img = cv.imread('sudo.jpg')
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray,50,150,apertureSize = 3)
# 倒数的两个参数分别为:最小线段长度(像素单位), 线段最大距离(像素单位)
lines = cv.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
res = img.copy()
for line in lines:
    x1,y1,x2,y2 = line[0]
    cv.line(res,(x1,y1),(x2,y2),(0,255,0),2)
compare([img, res])

OpenCV Tutorials 12 - 霍夫变换

二、霍夫圆变换

本小节介绍如何使用霍夫变换找出图像中的圆形,主要用到下列函数:cv.HoughCircles梯度下降()

  • 梯度下降法原理法如下:

cv.HoughCircles( image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]] ) -> circles

圆在数学上表示为 (x−xcenter)2+(y−ycenter)2=r2where(xcenter,ycenter)left(x-x_{text {cenwindows7旗舰版ter }}right)^{2}windows10激活密钥+lef直线方程公式t(y-y_{text {center }}right)^{2}=r^{2} text { where }left(x_{text {center }}, y_{text {center }}right)动画片小猪佩奇其中 (xcenter,ycenter)(x_{center}, y_{center}) 是圆的中心,r 是圆的半径。 从方程中,我们可以看到我们有 3 个参数,所动画大放映以我们需要一个 3D 累加器来进行霍夫变换,这将是非常低效的。 所以OpenCV使用了更梯度复杂的方法,Hough Gradient Method,它使用边缘的梯度信息。

# img = cv.imread('xy.png')
# gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# gray = cv.medianBlur(img,5)
# circles = cv.HoughCircles(gray,cv.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
# circles = np.uint16(np.around(circles))
# res = img.copy()
# for i in circles[0,:]:
#     # draw the outer circle
#     cv.circle(res,(i[0],i[1]),i[2],(0,255,0),2)
#     # draw the center of the circle
#     cv.circle(res,(i[0],i[1]),2,(0,0,255),3)
# compare([img, res])
img = cv.imread('pie.png',0)
img = cv.medianBlur(img,5)
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                            param1=100,param2=60,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv.imshow('detected circles',cimg)
cv.waitKey(0)
cv.destroyAllWindows()

OpenCV Tutorials 12 - 霍夫变换

三、补充资源

  1. 霍夫线检测:www.bilibili.com/video/BV1bb…
  2. 霍夫圆检测:www梯度洗脱.bilibili.com/video/BV1ob…
img = cv.imread('twitter.png',0)
img = cv.resize(img, (0,0), fx = 0.3, fy = 0.3)
img = cv.medianBlur(img,5)
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
                            param1=50,param2=35,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
img = cimg.copy()
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
compare([img ,cimg])