一、霍夫变换

本文主要介绍霍夫变换检测直线和圆的原理。

霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法。主要用来从图像中分离出具有某种相同特征的集合图像(如,直线,圆等)。最基本的霍夫变换是从黑白图像中检测直线(线段)。

1、直线检测

1.1 直线的表示方式

对于平面中的一条直线,在笛卡尔坐标系中,常见的有两点式,点斜式表示方式。然而在Hough变换中,考虑的是另外一种表示方式:使用( r , θ r,\theta r,θ) 来 表 示 一 条 直 线 。 其 中 , r 为 该 直 线 到 原 点 的 距 离 , 来表示一条直线。其中,r为该直线到原点的距离, 线r线\theta$为该直线的垂线与x轴的夹角。如图下所示:

在这里插入图片描述$

也就是霍夫变换中表示一条直线的参数变成了(r, θ \theta θ)。

2.如何判断多个点是否在同一直线上

当我们的对象变成点时,我们知道一个点可以发射出无数条直线,根据霍夫变换的直线表达形式,假设这个点为i,则通过这个点的直线我们用( r i , θ i r_i,\theta_i ri,θi)表示。再假设一个点为j,则通过点j的一系列直线我们用( r j , θ j r_j,\theta_j rj,θj)表示。我们知道两点决定一条直线,所以这两个点的直线必定有 r i = r j , θ i = θ j r_i=r_j,\theta_i= \theta_j ri=rj,θi=θj的时候。
那如果是三个点呢,假设第三个点是k,则通过k点的一系列直线为( r k , θ k r_k,\theta_k rk,θk),如果三点在一条直线上,那必定有某个 r i = r j = r k = r , θ i = θ j = θ k = θ r_i=r_j=r_k = r,\theta_i = \theta_j= \theta_k = \theta ri=rj=rk=r,θi=θj=θk=θ
在霍夫变换检测直线时我们需要找到这样一样直线,如何找到这条直线呢?

3.如何检测出直线

使用hough变换来检测直线的思想就是:为每一个点假设n个方向的直线,通常n=180,此时检测的直线的角度精度为1°,分别计算这n条直线的 ( r , θ ) (r,\theta) r,θ坐标,得到n个坐标点。如果要判断的点共有N个,最终得到的 ( r , θ ) (r,\theta) r,θ坐标有N * n个。有关这N * n个(r,theta)坐标,其中 θ \theta θ是离散的角度,共有180个取值。
最重要的地方来了,如果多个点在一条直线上,那么必有这多个点在theta=某个值theta_i时,这多个点的r近似相等于 r i r_i ri。也就是说这多个点都在直线 ( r i , θ i ) (r_i,\theta_i) ri,θi上。
下面拿个例子说明:
如果空间中有3个点,如何判断这三个点在不在一个直线上,如果在,这条直线的位置为:

这个例子中,对于每个点均求过该点的6条直线的(r, θ \theta θ)坐标,共求了3 * 6个(r, θ \theta θ)坐标。可以发现在 θ \theta θ=60时,三个点的r都近似为80.7,由此可判定这三个点都在直线(80.7,60)上。
通过 r 0 θ r0\theta r0θ 坐标系可以更直观表示这种关系,如下图:图中三个点的 ( r , θ ) (r,\theta) r,θ曲线汇集在一起,该交点就是同时经过这三个点的直线。
通过 r * θ \theta θ 坐标系可以更直观表示这种关系,如下图:图中三个点的(r, θ \theta θ)曲线汇集在一起,该交点就是同时经过这三个点的直线:

img

2.Hough圆检测

继使用hough变换检测出直线之后,顺着坐标变换的思路,提出了一种检测圆的方法。

2.1如何表示一个圆?

与使用(r, θ \theta θ)来表示一条直线相似,使用(a,b,r)来确定一个圆心为(a,b)半径为r的圆。
某个圆过点 ( x 1 , y 1 ) (x_1,y_1) x1,y1,则有:$(x_1-a_1)^2 + (y_1-b_1)^2 = r_1^2 。 那 么 过 点 。 那么过点 (x_1,y_1) 的 所 有 圆 可 以 表 示 为 的所有圆可以表示为 (a_1(i),b_1(i),r_1(i)) , 其 中 ,其中 r_1 ∈ ( 0 , 无 穷 ) , 每 一 个 i 值 都 对 应 一 个 不 同 的 圆 , ∈(0,无穷),每一个 i 值都对应一个不同的圆, 0i(a_1(i),b_1(i),r_1(i)) 表 示 了 无 穷 多 个 过 点 表示了无穷多个过点 (x_1,y_1)$的圆。

2.2 如何确定多个点在同一个圆上?

如上说明,过点(x1,y1)的所有圆可以表示为 ( a 1 ( i ) , b 1 ( i ) , r 1 ( i ) ) (a_1(i),b_1(i),r_1(i)) a1(i),b1(i),r1(i),过点 ( x 2 , y 2 ) (x_2,y_2) x2,y2的所有圆可以表示为 ( a 2 ( i ) , b 2 ( i ) , r 2 ( i ) ) (a_2(i),b_2(i),r_2(i)) a2(i),b2(i),r2(i),过点 ( x 3 , y 3 ) (x_3,y_3) x3,y3的所有圆可以表示为 ( a 3 ( i ) , b 3 ( i ) , r 3 ( i ) ) (a_3(i),b_3(i),r_3(i)) a3(i),b3(i),r3(i),如果这三个点在同一个圆上,那么存在一个值 ( a 0 , b 0 , r 0 ) (a_0,b_0,r_0) a0,b0,r0,使得$ a_0 = a_1(k)=a_2(k)=a_3(k) 且b_0 = b_1(k) = b_2(k) = b_3(k) 且r_0=r_1(k)=r_2(k)=r_3(k) , 即 这 三 个 点 同 时 在 圆 ,即这三个点同时在圆 (a_0,b_0,r_0)上。$
从下图可以形象的看出:

img

首先,分析过点 ( x 1 , y 1 ) (x_1,y_1) x1,y1的所有圆 ( a 1 ( i ) , b 1 ( i ) , r 1 ( i ) ) (a_1(i),b_1(i),r_1(i)) a1(i),b1(i),r1(i),当确定 r 1 ( 4 i ) r_1(4i) r1(4i)时 , ( a 1 ( i ) , b 1 ( i ) ) (a_1(i),b_1(i)) a1(i),b1(i)的轨迹是一个以 ( x 1 , y 1 , r 1 ( i ) ) (x_1,y_1,r_1(i)) x1,y1,r1(i)为中心半径为 r 1 ( i ) r_1(i) r1(i)的圆。那么,所有圆 ( a 1 ( i ) , b 1 ( i ) , r 1 ( i ) ) (a_1(i),b_1(i),r_1(i)) a1(i),b1(i),r1(i)的组成了一个以(x1,y1,0)为顶点,锥角为90度的圆锥面。
三个圆锥面的交点A 既是同时过这三个点的圆。

opencv-python实现虹膜瞳孔边缘检测

cv2.HoughCircles函数说明:
用函数 cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius) , 其参数解释如下:
(1)image: 输入图像,需要灰度图
(2)method: 检测方法,常用CV_HOUGH_GRADIENT
(3)dp: 为检测内侧圆心的累加器图像的分辨率于输入图像之比的倒数,如dp=1,累加器和输入图像具有相同的分辨率,如果dp=2,累计器便有输入图像一半那么大的宽度和高度
(4)minDist: 表示两个圆之间圆心的最小距离
(5)circles: 找到的圆的输出向量,一般不设置
(6)param1: 默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半
(7)param2:默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值,它越小,就越可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆
(8)minRadius:默认值0,圆半径的最小值
(9)maxRadius:默认值0,圆半径的最大值

代码:

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

img = cv2.imread("E:\matlab_file\hongmoshibie\pic2.png")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #灰度图像

plt.subplot(121),plt.imshow(gray,'gray')
plt.xticks([]),plt.yticks([])
#使用HoughCircles对灰度图像进行霍夫变换
circles1 = cv2.HoughCircles(gray,cv2.HOUGH_GRADIENT,1,
100,param1=100,param2=30,minRadius=50,maxRadius=100)
circles = circles1[0,:,:] #提取为二维
circles = np.uint16(np.around(circles)) #四舍五入,取整
for i in circles[:]:
    cv2.circle(img,(i[0],i[1]),i[2],(255,0,0),5) #画圆
    cv2.circle(img,(i[0],i[1]),2,(255,0,255),10) #画圆心

plt.subplot(122),plt.imshow(img)
plt.xticks([]),plt.yticks([]);

在这里插入图片描述
瞳孔外圆检测:
调整minRadius、maxRadius参数(将其分别设置为:minRadius=200,maxRadius=290,代码基本不变),即可检测出瞳孔的外圆。
在这里插入图片描述
Tips:
1.在霍夫圆检测之前进行高斯滤波,减少噪声
2.以前利用霍夫圆检测经常出现检测不到圆,或错误检测的情况,实则是因为参数没有设置到位。应该小心调节的参数有:
minDist:根据实际情况调节,越小检测的圆越多,错误率越大
param2:这个参数以前没有注意过,针对于虹膜检测,目标圆是较小的,所以这个值理应设置的小一点。
minRadius,maxRadius:圆半径范围

GitHub 加速计划 / opencv31 / opencv
77.34 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:1 个月前 )
e1fec156 features2d: fixed out of bounds access in SIFT 21 天前
63087396 - 22 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐