霍夫圆变换的基本原理和霍夫线变换类似,只是点对应的二维极径极角空间被三维的圆心点x, y还有半径r空间取代。
对直线来说,一条直线能由参数极径极角(r, θ)表示。而对圆来说,我们需要三个参数来表示一个圆,由于比直线检测多出一个维度,使得标准的霍夫圆检测需要大量的内存且速度比较慢。出于对运算效率的考虑,OpenCV实现的霍夫圆检测是一个比标准霍夫圆检测更为灵活的检测方法:霍夫梯度法,也叫2-1霍夫变换(21HT)。
霍夫梯度法:
它的原理依据是圆心一定是在圆上的每个点的模向量上,这些圆上点模向量的交点就是圆心,霍夫梯度法的第一步就是找到这些圆心,这样三维的累加平面就又转化为二维累加平面。第二步根据所有候选中心的边缘非0像素对其的支持程度来确定半径。
实现原理就是首先对图像进行模糊降噪,进行canny边缘检测,然后考虑边缘图像中的每一个非0点的局部梯度,通过Sebol()函数计算x, y方向上的sobel一阶导数得到梯度,利用得到的梯度,由斜率指定直线上的每一个点都在累加器中被累加,然后从累加器中这些点中选择候选的中心画圆。
执行步骤:
1、执行均值偏移滤波,消除噪声
2、转成灰度图
3、canny边缘检测
4、执行霍夫圆检测
5、绘制出检测到的圆
第一步和第二步可以根据实际情况调整顺序,但一定要消除噪声。
具体代码
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def Hough_circle_demo(img):
#均值偏移滤波
dst = cv.pyrMeanShiftFiltering(img, 10, 120)
cv.imshow('filter', dst)
#转成灰度图
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
cv.imshow('gray', gray)
#canny边缘检测
edges = cv.Canny(gray, 50, 150, apertureSize=3)
cv.imshow('canny', edges)
#执行霍夫圆检测
circles = cv.HoughCircles(edges, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
'''
HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
image: 输入图像
method: 检测方法
minDist: 检测到圆心之间的最小距离 img.rows/8
circles: 返回结果 (x,y,r)
param1: canny边缘函数的高阈值
param2: 圆心检测阈值
minRadius: 能检测到的最小圆半径
maxRadius: 能检测到的最大圆半径
'''
circles = np.uint16(np.around(circles))
#绘制出检测到的圆
for i in circles[0, :]:
cv.circle(img, (i[0], i[1]), i[2], (0, 0, 255), 1)
cv.circle(img, (i[0], i[1]), 2, (0, 255, 0), 2)
cv.imshow('circles', img)
img = cv.imread('img/target.jpg')
cv.namedWindow('img',cv.WINDOW_AUTOSIZE)
cv.imshow('img',img)
Hough_circle_demo(img)
cv.waitKey(0)
cv.destroyAllWindows()
效果图对比:
cv.pyrMeanShiftFiltering(img, 10, 120),进行了canny边缘检测的结果
cv.pyrMeanShiftFiltering(img, 10, 100),执行了canny边缘检测
cv.pyrMeanShiftFiltering(img, 10, 100),没有执行canny边缘检测
通过三种结果的对比,我们可以看出执行了canny边缘检测的效果更好,而不用的模糊效果得到的结果也不同,所以在以后的操作中,一定要注意。