环境
- Python 3.8.8
- Pycharm 2021
- opencv-Python
效果
基本原理
圆检测的原理是在直线检测原理上的拓展,可以先看看我这篇博客霍夫直线检测下面介绍圆检测的不同之处。 圆的表达式如下:
(
x
?
a
)
2
+
(
y
?
b
)
2
=
r
(x-a)^2+(y-b)^2=r
(x?a)2+(y?b)2=r 其中
a
a
a和
b
b
b表示圆心坐标,
r
r
r表示圆半径,因此标准佛如霍夫圆检测就是在这三个参数组成的三维空间累加器上进行圆检测,此时效率就会很低,所以
O
p
e
n
C
v
OpenCv
OpenCv中使用 霍夫梯度 进行圆形的检测。霍夫梯度法将圆检测分成两个阶段,第一阶段是检测圆心,第二段是利用圆心推导出圆半径,公式如下:
a
=
x
?
r
c
o
s
θ
b
=
y
?
r
s
i
n
θ
a = x - rcos\theta \\ b = y - rsin\theta
a=x?rcosθb=y?rsinθ
- 圆心检测的原理:圆心是圆周角法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
- 圆半径确定原理:圆心到圆周上的距离(半径)是相同的,确定一个阈值,只要相同距离的数量打于该阈值,就认为该距离是该圆心的半径。
API
HoughCircles(image, method, dp, minDist,param1=100, param2=100, minRadius=0, maxRadius=0 )
- method: CV_HOUGH_GRADENT
- dp:累加面分辨率(大小) = 原始图像分辨率(大小) × 1 / dp。默认 dp = 1 时,两者分辨率相同。
- minDist: 两个圆心的最小距离。若两圆心距离 < minDist,则认为是同一个圆
- param1: canny边缘检测高阈值, 低限阈值是这个值的一半。越大检测圆边界时,要求的亮度梯度越大,一些灰灰的不明显的边界就会略去。
- param2:累加平面某点是否是圆心的判定阈值。越小,越多假的圆会被检测到,越大,能通过检测的圆就更接近完美的圆形,默认为 100。
- 后两个参数:允许检测到的圆的最大和最小半径。
完整代码
import cv2 as cv
import numpy as np
import copy
def circle_detect() :
img = cv.imread('images/weiqi.png')
cimg = copy.deepcopy(img)
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
img_gray = cv.medianBlur(img_gray, 5)
circles = cv.HoughCircles(img_gray, cv.HOUGH_GRADIENT, 1, 10, param1 = 120, param2 = 50).squeeze()
for circle in circles :
circle = np.uint16(np.around(circle))
_, img_thresh = cv.threshold(img_gray, 80, 255, cv.THRESH_BINARY)
if img_thresh[circle[1], circle[0]] == 255 :
print(f'chess is black!')
cv.circle(img, center=(circle[0], circle[1]), radius=circle[2],
color=(255, 0, 0), thickness=2)
cv.circle(img, center=(circle[0], circle[1]), radius=2,
color=(255, 0, 0), thickness=3)
else :
print('chess is white!')
cv.circle(img, center=(circle[0], circle[1]), radius=circle[2],
color=(0, 0, 255), thickness=2)
cv.circle(img, center=(circle[0], circle[1]), radius=2,
color=(0, 0, 255), thickness=3)
cv.imshow('canny', img_thresh)
print(img.shape, cimg.shape)
img_concatenate = np.concatenate((cimg, img), axis = 1)
cv.imwrite('img_con.png', img_concatenate)
cv.imshow('img', img_concatenate)
cv.waitKey(0)
if __name__ == '__main__':
circle_detect()
|