如何用Python+opencv检测此图像中的所有圆?

我用了cv.HoughCircles函数,但不会选择合适的参数,效果不好。
原图:

img


结果:

img

{

```

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

def show(img):
if img.ndim == 2:
plt.imshow(img,cmap='gray')
else:
plt.imshow(cv.cvtColor(img,cv.COLOR_BGR2RGB))
plt.show()

img=cv.imread('C:/Users/1/Desktop/img/test.jpg')
gray=cv.cvtColor(img, cv.COLOR_BGR2GRAY)

dst = cv.equalizeHist(gray)#应用直方图均衡化
gaussian = cv.GaussianBlur(dst,(9,9),0)
#利用Canny进行边缘检测
GrayImage = cv.Canny(gaussian, 20,180, apertureSize=3)
ret, th1 = cv.threshold(GrayImage, 127, 255, cv.THRESH_TOZERO) # 固定阈值二值化
th2 = cv.adaptiveThreshold(th1, 255, cv.ADAPTIVE_THRESH_MEAN_C, cv.THRESH_BINARY, 3, 5)
th3 = cv.adaptiveThreshold(th2, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 3, 5)
kernel = np.ones((6, 9), np.uint8)
erosion = cv.erode(th3, kernel, iterations=1) # 腐蚀处理
dilation = cv.dilate(erosion, kernel, iterations=1) # 膨胀处理
imgray = cv.Canny(erosion, 3, 8) # Canny算子边缘检测

circles = cv.HoughCircles(imgray, cv.HOUGH_GRADIENT, 1, 40, param1=100, param2=6, minRadius=8,maxRadius=10)

circles = np.uint16(np.around(circles))
P = circles[0] # 去掉circles数组一层外括号
for i in P:
cv.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 5)
cv.circle(img, (i[0], i[1]), 5, (0, 0, 255), 3)

show(img)
}

我参考了一些博主的文章,链接:https://blog.csdn.net/SouthWooden/article/details/98741985

废话不多说,直接上代码

img

import cv2
import numpy as np


def cv_show(neme, img):
    cv2.imshow(neme, img)  
    cv2.waitKey(0)  
    cv2.destroyAllWindows()  


image = cv2.imread('1.jpg')
img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Canny 边缘检测(图像、min值、max值)
edges = cv2.Canny(img, 7, 12)
ret, thresh1 = cv2.threshold(edges, 127, 255, cv2.THRESH_BINARY)

# 膨胀操作
kernel1 = np.ones((5, 5), np.uint8)
# 换个封装函数,膨胀      当前载入 腐蚀后--膨胀
erosion = cv2.dilate(thresh1, kernel1, iterations=1)

kernel = np.ones((3, 3))
# 腐蚀操作
sb = cv2.erode(erosion, kernel, iterations=1)

cv_show("s", thresh1)
cv_show("name", erosion)
cv_show('sda', sb)

# 轮廓查询
contours, hierarchy = cv2.findContours(sb, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

for i in range(len(contours)):
    # 轮廓外接圆
    (x, y), radius = cv2.minEnclosingCircle(contours[i])
    center = (int(x), int(y))
    radius = int(radius)

    # 轮廓区域
    # 轮廓面积
    area = cv2.contourArea(contours[i])
    if 300 <= area < 2000:
        image = cv2.circle(image, center, radius, (0, 0, 255), 1)

cv_show('sad', image)

可以检测圆,后边有说明。

import cv2
import numpy as np


__author__ = "boboa"


def detect_circles_demo(image):
    dst = cv2.pyrMeanShiftFiltering(image, 10, 100)  # 均值偏移滤波
    cimage = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(cimage, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=40, minRadius=0, maxRadius=0)
    # 整数化,#把circles包含的圆心和半径的值变成整数
    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("circles", image)


if __name__ == "__main__":
    img = cv2.imread("image/circles.jpg")
    cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("input image", img)
    detect_circles_demo(img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)

参数:
  image:输入图像,必须是灰度图像
  method:检测方法,常用CV_HOUGH_GRADIENT
  dp:检测内侧圆心的累加器图像的分辨率于输入图像之比的倒数,如dp=1,累加器和输入图像具有相同的分辨率,如果dp=2,累计器便有输入图像一半那么大的宽度和高度
  minDist: 两个圆心之间的最小距离
  param1: 是method方法的参数,在CV_HOUGH_GRADIENT表示传入canny边缘检测的阈值
  param2:对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值
它越小,就越可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了
minRadius:默认值0,圆半径的最小值

  maxRadius:默认值0,圆半径的最大值

cv2.circle是画圆函数(img, center, radius, color[, thickness[, lineType[, shift]]]) -> img

参数:img:源图像

   center:圆心坐标

   radius:圆的半径

   color:设定圆的颜色

   thickness:如果是正数,表示圆轮廓的粗细程度。如果是负数,表示要绘制实心圆

   lineType:圆线条的类型

   shift:圆心坐标和半径值中的小数位数

图像中的圆直径基本一致,比较好处理。
(1)检查一下 固定阈值二值化 的参数"127"是否合适,在该语句后显示一下二值化图像即可;
(2)主要是 HoughCircles 中的最大、最小半径 minRadius、maxRadius 参数设置是否合适
从运行结果来看设置的小了,可以适当增大,保证要找的圆的半径值在 minRadius、maxRadius 之间。