我们可以把k看作自变量,把q看作因变量,则有:
A : q = − k x 1 + y 1 B : q = − k x 2 + y 2 A: q=-kx_1+y_1\\ B: q=-kx_2+y_2 A:q=−kx1+y1B:q=−kx2+y2
这个过程,称作霍夫变换,在霍夫空间上,可得到一个点,如下图所示:
由此可见:坐标系的直线,经霍夫变换后,变成了霍夫空间上的点,如下图:
当 q A = q B , k A = m × K B − x 1 ⋅ k + y 1 = − x 2 ⋅ k + y 2 当q_A=q_B,k_A=m\times K_B\\ -x_1\cdot k + y1 = -x_2\cdot k + y_2\\ 当qA=qB,kA=m×KB−x1⋅k+y1=−x2⋅k+y2
有交点Q,在交点Q处,x1=x2,y1=y2
此时,可以说明A/B在同一条直线上
k变换,q也就随之变换。这个过程表示经过D点的直线,360°旋转,如下图:
虽然图二中有多个交点,但我们主要关注的是三线相交的情况,这也是霍夫变换的后处理的基本方式:选择由尽可能多直线汇成的点
k=∞是不方便表示的,所以我们必须改变一下坐标系:用极坐标表示点,线
x 1 = ρ = c o s θ y 1 = ρ s i n θ ρ = x c o s θ + y s i n θ 所 以 , 可 用 [ ρ , θ ] 表 示 一 个 点 x_1=\rho =cos\theta\\ y_1=\rho sin\theta\\ \rho =xcos\theta+ysin\theta\\ 所以,可用[\rho,\theta]表示一个点 x1=ρ=cosθy1=ρsinθρ=xcosθ+ysinθ所以,可用[ρ,θ]表示一个点
霍夫空间也随之改变,但也就是点的曲线变了而已
那么我们应如何把它用在图像处理中呢?
假设我们图像中有一段有8个像素点组成直线
ρ = x c o s θ + y s i n θ \rho =xcos\theta+ysin\theta\\ ρ=xcosθ+ysinθ
以上就是标准霍夫变换的原理
但我们一般不用标准霍夫变换,而是用概率霍夫变换
参考资料:霍夫变换直线检测(Line Detection)原理及示例
(四十八)通俗易懂理解——霍夫变换原理
标准霍夫变换:把图像映射到它的参数空间上,它需要计算所有的M个边缘点,这样它的运算量和所需内存空间都会很大。
概率霍夫变换:如果在输入图像中只是处理m(m
HoughLinesP函数就是利用概率霍夫变换来检测直线的
cv2.HoughLinesP()
函数功能:概率霍夫变换检测直线
输入参数:
- image:图像名,强烈建议输入经Canny检测之后的图像
- rho:搜索线时的位置距离间隔(以像素为单位)
- theta:搜索线时的旋转角度差(以度为单位)
- threshold:表示丢弃长度低于该阈值的线,显然这个值越大,所判断出的直线越少;这个值越小,所判断出的直线越多
- minLineLength:设置最小线段长度,一次性丢弃较短的线
- maxLineGap:最大直线间隙,即如果有两条线段在一条直线上,但它们之间因为有间隙,所以被认为是两个线段,如果这个间隙大于该值,则被认为是两条线段,否则是一条
返回值:lines为输出的直线向量,每条线用4个元素表示,即直线的两个端点的4个坐标值(x1, y1, x2, y2)表示,其中(x1, y1)表示线段的起点,(x2, y2)表示线段的终点
示例:lines = cv2.HoughLinesP(edges,1,np.pi/180,30,minLineLength,maxLineGap)
import cv2 as cv
import numpy as np
img = cv.imread('test2.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)
for line in lines:
x1,y1,x2,y2 = line[0]
cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv.imshow('houghlines5.jpg',img)
cv.waitKey()
cv.destroyAllWindows()
注意!!!:
市面上有些教材书上是这么写的,无法得到理论结果
正确的答案为:
for line in lines:
x1,y1,x2,y2 = line[0]
cv.line(img,(x1,y1),(x2,y2),(0,255,0),2)
Opencv中还有一个函数cv2.HoughCircles,它通过霍夫梯度法,实现了圆的检测
参考资料:opencv —— HoughCircles 霍夫圆变换原理及圆检测
cv2.HoughCircles()
函数功能:霍夫变换检测圆
输入参数:
img: 待检测的灰度图
cv2.HOUGH_GRADIENT:检测的方法,霍夫梯度,也是唯一的检测方法
1:检测的圆与原始图像具有相同的大小,dp=2,检测的圆是原始图像的一半
20:检测到的相邻圆的中心的最小距离(如果参数太小,除了一个真实的圆外,还可能会错误地检测到多个相邻圆。如果太大,可能会漏掉一些圆。)
param1:Canny 边缘检测的高阈值,低阈值被自动置为高阈值的一半,默认为 100
(霍夫梯度法里面已存在Canny检测,故我们无需重复)
param2:被计算机判定为圆的难度。它越小,就越可能检测到假圆;
而它越大的话,能通过检测的圆就更加接近完美的圆形了
minRadius:最小圆半径
maxRadius:最大圆半径,如果<=0,则使用最大图像尺寸。如果<0,则返回没有找到半径的中心。
返回值:cv2.HoughCircles的返回将其reshape为(-1, 3),每一行就是一圆的参数,分别是
(圆心横坐标,圆心纵坐标,半径)
,最后用于该处:cv2.circle(coins_img, (i[0], i[1]), i[2], (0, 0, 255), 5) # 画圆
示例:circle=cv2.HoughCircles(gray_img,cv2.HOUGH_GRADIENT,1,120,param1=100,param2=30,minRadius=0,maxRadius=0)
import cv2
import numpy as np
planets = cv2.imread('planet_glow.jpg')
gray_img = cv2.cvtColor(planets,cv2.COLOR_BGR2GRAY)
gray_img = cv2.medianBlur(gray_img,5)
circles = cv2.HoughCircles(gray_img,cv2.HOUGH_GRADIENT,1,120,param1=80,param2=35,minRadius=0,maxRadius=0)
print(circles)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(planets,(i[0],i[1]),i[2],(0,255,0),2)
cv2.circle(planets,(i[0],i[1]),2,(0,0,255),3)
cv2.imshow('planet',planets)
cv2.waitKey()
cv2.destroyAllWindows()
效果显著!
Opencv入门篇已经学完了,接下来有其它的事情❌,这个专栏预计停更一两周
车牌检测,周三看看能不能做完
忙完之后,估计就到了用Haar级联实现人脸检测