边缘检测与霍夫变换检测圆教程(学习笔记,仅供参考)
1、简介
边缘检测是计算机视觉中的一项基础技术,用于识别图像中物体的边界。霍夫变换是一种特征提取技术,能够从复杂背景中识别几何形状,如直线、圆形等。本教程将介绍边缘检测的基本概念和霍夫变换检测圆的数学原理,并提供Python代码示例,帮助新手理解和实践这两种技术。
2、边缘检测
边缘检测的目的是在图像中识别出显著的边缘,这些边缘通常表示物体的轮廓。常用的边缘检测算法包括Sobel、Canny等。这些算法通过计算图像中像素点的梯度来识别边缘。
3、霍夫变换
霍夫变换是一种用于检测几何形状的技术。它通过将图像空间转换到参数空间来识别特定的形状。
3.1、数学原理
霍夫变换利用事实:在图像空间中的一条直线可以在参数空间中表示为一个点。相应地,一个圆可以由三个参数表示:圆心的x坐标、y坐标以及半径。
霍夫变换检测圆的过程可以简化为:
- 对于图像中的每个边缘点,根据可能的半径值在参数空间中画出一系列圆或直线。
- 在参数空间中,多个圆或直线交点处的累积值较高,这些点对应于图像空间中的圆形。
3.2、检测圆的步骤
3.2.1、已知半径–步骤(第1种情况
):
- 应用边缘检测算法,识别图像中的
边缘
。 - 对于每个边缘点,根据已知的半径,在参数空间中
画圆
。 - 在参数空间中寻找
累积值高的点
,这些点对应的参数即为图像中圆的位置和大小。
3.2.2、已知半径(第1种情况
)
左图的圆边上点(x,y)-----> 对应右图的圆心(x,y)
左图的圆心点(a,b)-----> 对应右图的圆边上点(a,b)
3.2.3、不知道知半径(第2种情况
):
- 应用边缘检测算法,识别图像中的
边缘
。 - 对于每个边缘点,根据不同的半径,在
三维参数空间
中画直线
。 - 在三维参数空间中寻找
累积值高的点
,这些点对应的参数即为图像中圆的位置和大小。
3.2.4、不知道半径(第2种情况
)
思路:
1、面临的问题是:
不知道图片的任意一点是否某个圆边上的点
2、但知道一个事实:
如果某个点是圆边上的点,那么对应的圆心必在这个点的梯度方向上
,如下图所示
3、由2这个事实知道:
圆心在梯度方向这条直线上,如下图所示
4、对应到霍夫空间:
梯度方向这条直线上的所有点可以表示为可能的圆心,每个可能的圆心对应3个可能的参数(a,b,r)
如下图所示,因此对应到霍夫空间就是一条斜线,以此类推,在霍夫空间可以画出很多条斜线,最后,
霍夫空间中斜线相交最越多的点就越可能是圆
4、Python演示代码
以下是使用OpenCV库进行霍夫变换检测圆的Python代码示例:
import cv2
import numpy as np
# 加载图像
image = cv2.imread('your_image_path.jpg', 0)
# 应用Canny边缘检测
# image:输入图像,应为灰度图。
# 50:低阈值(low threshold)。如果像素梯度小于此值,它不会被认为是边缘。
# 150:高阈值(high threshold)。如果像素梯度高于此值,它一定会被认为是边缘。
# apertureSize=3:Sobel算子的大小,它用于计算图像梯度。此参数可选,默认值为3。它必须是1, 3, 5, 或 7中的一个。
edges = cv2.Canny(image, 50, 150, apertureSize=3)
# 应用霍夫变换检测圆
# edges:输入图像,通常是使用Canny算法预处理过的边缘检测结果。
# cv2.HOUGH_GRADIENT:检测方法。这是实现霍夫圆变换的唯一方法。
# 1:dp,图像分辨率与累加器分辨率的比值。如果dp=1,则累加器具有与输入图像相同的分辨率。如果dp=2,累加器的分辨率是输入图像的一半。
# 20:minDist,圆心之间的最小距离。如果参数太小,可能会错误地将多个相邻的圆检测为一个圆。如果太大,可能会错过一些圆。
# param1=50:高阈值(由Canny边缘检测器使用)。通常与前面的Canny边缘检测的高阈值一致。
# param2=30:累加器阈值。它是检测到圆的累加器阈值。值越小,检测到的假圆的可能性越大。值越大,可能会错过一些圆。
# minRadius=0:圆的最小半径。默认为0。
# maxRadius=0:圆的最大半径。默认为0,表示最大半径不限。
circles = cv2.HoughCircles(edges, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
# 画出检测到的圆
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# 画圆
cv2.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)
# 画圆心
cv2.circle(image, (i[0], i[1]), 2, (0, 0, 255), 3)
# 显示结果图像
cv2.imshow('Detected Circles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码效果