简体   繁体   English

检测图像中的多个圆圈

[英]Detect multiple circles in an image

I am trying to detect the count of water pipes in this picture.我试图检测这张图片中的水管数量。 For this, I am trying to use OpenCV and Python-based detection.为此,我正在尝试使用 OpenCV 和基于 Python 的检测。 The results, I am getting is a little confusing to me because the spread of circles is way too large and inaccurate.结果,我得到的结果让我有点困惑,因为圆圈的范围太大且不准确。

在此处输入图片说明

The code编码

import numpy as np
import argparse
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Path to the image")
args = vars(ap.parse_args())

# load the image, clone it for output, and then convert it to grayscale
image = cv2.imread(args["image"])
output = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

#detect circles in the image
#circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, param1=40,minRadius=10,maxRadius=35)
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 8.5,70,minRadius=0,maxRadius=70)

#print(len(circles[0][0]))
# ensure at least some circles were found
if circles is not None:
    # convert the (x, y) coordinates and radius of the circles to integers
    circles = np.round(circles[0, :]).astype("int")
    # count = count+1   

    # print(count) 

    # loop over the (x, y) coordinates and radius of the circles
    for (x, y, r) in circles:
        # draw the circle in the output image, then draw a rectangle
        # corresponding to the center of the circle
        cv2.circle(output, (x, y), r, (0, 255, 0), 4)
        cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)

    # show the output image
   # cv2.imshow("output", np.hstack([output]))
    cv2.imwrite('output.jpg',np.hstack([output]),[cv2.IMWRITE_JPEG_QUALITY, 70])
    cv2.waitKey(0)

After I run this, I do see a lot of circles detected, however, the results are complete haywire.运行此程序后,我确实看到检测到很多圆圈,但是,结果完全出问题了。 My question is, how do I improve this detection.我的问题是,如何改进这种检测。 Which parameters are specifically needed to optimize in the HoughCircles method to achieve greater accuracy?在 HoughCircles 方法中具体需要优化哪些参数以达到更高的精度? Or, should I take the approach of annotating hundreds of similar images via bounding boxes and then train them over a full-blown CNN like Yolo to perform detection?或者,我是否应该采用通过边界框注释数百个相似图像的方法,然后在像 Yolo 这样的成熟 CNN 上训练它们来执行检测?

在此处输入图片说明

Taking the approach mentioned in answer number 2 from here Measuring the diameter pictures of holes in metal parts, photographed with telecentric, monochrome camera with opencv .采用此处的答案编号 2 中提到的方法测量金属零件中孔的直径图片,使用带有 opencv 的远心单色相机拍摄 I got this output.我得到了这个输出。 This looks close to performing a count but misses on lot of actual pipes during the brightness transformation of the image.这看起来接近执行计数,但在图像亮度转换期间错过了许多实际管道。

在此处输入图片说明

The most important parameters for your HoughCircles call are:您的HoughCircles调用最重要的参数是:

  1. param1 : because you are using cv2.HOUGH_GRADIENT , param1 is the higher threshold for the edge detection algorithm and param1 / 2 is the lower threshold. param1 :因为您使用的是cv2.HOUGH_GRADIENTparam1是边缘检测算法的较高阈值, param1 / 2是较低阈值。
  2. param2 : it represents the accumulator threshold, so the lower the value, the more circles will be returned. param2 : 表示累加器阈值,所以值越小,返回的圆越多。
  3. minRadius and maxRadius : the blue circles in the example have a diameter of roughly 20 pixels, so using 70 pixels for maxRadius is the reason why so many circles are being returned by the algorithm. minRadiusmaxRadius :示例中的蓝色圆圈的直径大约为 20 像素,因此对maxRadius使用 70 像素是算法返回如此多圆圈的原因。
  4. minDist : the minimum distance between the centers of two circles. minDist :两个圆心之间的最小距离。

The parameterization defined below:参数化定义如下:

circles = cv2.HoughCircles(gray,
                           cv2.HOUGH_GRADIENT,
                           minDist=6,
                           dp=1.1,
                           param1=150,
                           param2=15,
                           minRadius=6,
                           maxRadius=10)

returns:返回:

在此处输入图片说明

You could do an adaptive threshold as preprocessing.你可以做一个自适应阈值作为预处理。 This basically looks for areas that are relatively brighter than the neighboring pixels, your global threshold loses some of the pipes, this keeps them a little better.这基本上寻找比相邻像素相对更亮的区域,您的全局阈值会丢失一些管道,这使它们更好一点。

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

img = cv2.imread('a2MTm.jpg')
blur_hor = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((11,1,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
blur_vert = cv2.filter2D(img[:, :, 0], cv2.CV_32F, kernel=np.ones((1,11,1), np.float32)/11.0, borderType=cv2.BORDER_CONSTANT)
mask = ((img[:,:,0]>blur_hor*1.2) | (img[:,:,0]>blur_vert*1.2)).astype(np.uint8)*255

plt.imshow(mask)

You can then carry on with the same post processing steps.然后,您可以继续执行相同的后处理步骤。


Here are some example processing steps:以下是一些示例处理步骤:

circles = cv2.HoughCircles(mask,
                           cv2.HOUGH_GRADIENT,
                           minDist=8,
                           dp=1,
                           param1=150,
                           param2=12,
                           minRadius=4,
                           maxRadius=10)
output = img.copy()
for (x, y, r) in circles[0, :, :]:
  cv2.circle(output, (x, y), r, (0, 255, 0), 4)

在此处输入图片说明

You can adjust the parameters to get what you would like, read about the parameters here .您可以调整参数以获得您想要的效果,请在此处阅读有关参数的信息

Instead of using cv2.HoughCircles another approach would be to use contour filtering.而不是使用cv2.HoughCircles另一种方法是使用轮廓过滤。 We can threshold the image then filter using aspect ratio, contour area, and radius of the blob.我们可以对图像进行阈值处理,然后使用长宽比、轮廓区域和 blob 的半径进行过滤。 Here's the result:结果如下:

在此处输入图片说明

Count: 344数:344

Code代码

import cv2

image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,27,3)

cnts = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
count = 0
for c in cnts:
    area = cv2.contourArea(c)
    x,y,w,h = cv2.boundingRect(c)
    ratio = w/h
    ((x, y), r) = cv2.minEnclosingCircle(c)
    if ratio > .85 and ratio < 1.20 and area > 50 and area < 120 and r < 7:
        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), -1)
        count += 1

print('Count: {}'.format(count))

cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM