使用 OpenCV(基于霍夫变换或其他特征)编写鲁棒的(颜色和大小不变)圆检测

Writing robust (color and size invariant) circle detection with OpenCV (based on Hough transform or other features)(使用 OpenCV(基于霍夫变换或其他特征)编写鲁棒的(颜色和大小不变)圆检测)
本文介绍了使用 OpenCV(基于霍夫变换或其他特征)编写鲁棒的(颜色和大小不变)圆检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了以下非常简单的 python 代码来查找图像中的圆圈:

I wrote the following very simple python code to find circles in an image:

import cv
import numpy as np

WAITKEY_DELAY_MS = 10
STOP_KEY = 'q'

cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);

key_pressed = False
while key_pressed != STOP_KEY:

    # grab image
    orig = cv.LoadImage('circles3.jpg')

    # create tmp images
    grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
    processed = cv.CreateImage(cv.GetSize(orig), 8, 1)


    cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

    cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

    # do some processing on the grey scale image
    cv.Erode(grey_scale, processed, None, 10)
    cv.Dilate(processed, processed, None, 10)
    cv.Canny(processed, processed, 5, 70, 3)
    cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

    storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

    # these parameters need to be adjusted for every single image
    HIGH = 50
    LOW = 140

    try: 
        # extract circles
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)

        for i in range(0, len(np.asarray(storage))):
            print "circle #%d" %i
            Radius = int(np.asarray(storage)[i][0][2])
            x = int(np.asarray(storage)[i][0][0])
            y = int(np.asarray(storage)[i][0][1])
            center = (x, y)

            # green dot on center and red circle around
            cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

            cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

    except:
        print "nothing found"
        pass

    # show images
    cv.ShowImage("image - press 'q' to quit", orig)
    cv.ShowImage("post-process", processed)

    cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
    key_pressed = chr(cv_key & 255)

从以下两个例子可以看出,找圈质量"变化很大:

As you can see from the following two examples, the 'circle finding quality' varies quite a lot:

案例1:

案例2:

Case1 和Case2 基本上是同一张图片,但是算法还是检测到了不同的圆圈.如果我向算法展示具有不同大小圆圈的图像,则圆圈检测甚至可能完全失败.这主要是由于 HIGHLOW 参数需要为每张新图片单独调整.

Case1 and Case2 are basically the same image, but still the algorithm detects different circles. If I present the algorithm an image with differently sized circles, the circle detection might even fail completely. This is mostly due to the HIGH and LOW parameters which need to be adjusted individually for each new picture.

因此我的问题是:使该算法更健壮的各种可能性是什么?它应该是大小和颜色不变的,以便检测具有不同颜色和不同大小的不同圆圈.也许使用霍夫变换不是最好的做事方式?有更好的方法吗?

Therefore my question: What are the various possibilities of making this algorithm more robust? It should be size and color invariant so that different circles with different colors and in different sizes are detected. Maybe using the Hough transform is not the best way of doing things? Are there better approaches?

推荐答案

以下是基于我作为视觉研究员的经验.从您的问题来看,您似乎对可能的算法和方法感兴趣,而只是对一段工作代码感兴趣.首先,我为您的示例图像提供了一个快速而肮脏的 Python 脚本,并显示了一些结果以证明它可能会解决您的问题.解决这些问题后,我将尝试回答您有关稳健检测算法的问题.

The following is based on my experience as a vision researcher. From your question you seem to be interested in possible algorithms and methods rather only a working piece of code. First I give a quick and dirty Python script for your sample images and some results are shown to prove it could possibly solve your problem. After getting these out of the way, I try to answer your questions regarding robust detection algorithms.

带有检测到的圆圈的一些示例图像(除您之外的所有图像均已从 flickr.com 下载并获得 CC 许可)(无需更改/调整任何参数,使用以下代码提取所有图像中的圆圈):

Some sample images (all the images apart from yours are downloaded from flickr.com and are CC licensed) with the detected circles (without changing/tuning any parameters, exactly the following code is used to extract the circles in all the images):

这里是代码:

import cv2
import math
import numpy as np

d_red = cv2.cv.RGB(150, 55, 65)
l_red = cv2.cv.RGB(250, 200, 200)

orig = cv2.imread("c.jpg")
img = orig.copy()
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = cv2.FeatureDetector_create('MSER')
fs = detector.detect(img2)
fs.sort(key = lambda x: -x.size)

def supress(x):
        for f in fs:
                distx = f.pt[0] - x.pt[0]
                disty = f.pt[1] - x.pt[1]
                dist = math.sqrt(distx*distx + disty*disty)
                if (f.size > x.size) and (dist<f.size/2):
                        return True

sfs = [x for x in fs if not supress(x)]

for f in sfs:
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA)
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)

h, w = orig.shape[:2]
vis = np.zeros((h, w*2+5), np.uint8)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
vis[:h, :w] = orig
vis[:h, w+5:w*2+5] = img

cv2.imshow("image", vis)
cv2.imwrite("c_o.jpg", vis)
cv2.waitKey()
cv2.destroyAllWindows()

如您所见,它基于 MSER blob 检测器.除了简单的灰度映射之外,该代码不会对图像进行预处理.因此,预计会丢失图像中那些微弱的黄色斑点.

As you can see it's based on the MSER blob detector. The code doesn't preprocess the image apart from the simple mapping into grayscale. Thus missing those faint yellow blobs in your images is expected.

简而言之:除了只提供两张没有描述的示例图像之外,您不会告诉我们您对问题的了解.在这里,我解释了为什么在我的拙见中,在询问解决问题的有效方法之前,了解有关该问题的更多信息很重要.

回到主要问题:解决这个问题的最佳方法是什么?让我们将其视为一个搜索问题.为了简化讨论,假设我们正在寻找具有给定大小/半径的圆.因此,问题归结为找到中心.每个像素都是一个候选中心,因此,搜索空间包含所有像素.

Back to the main question: what is the best method for this problem? Let's look at this as a search problem. To simplify the discussion assume we are looking for circles with a given size/radius. Thus, the problem boils down to finding the centers. Every pixel is a candidate center, therefore, the search space contains all the pixels.

P = {p1, ..., pn} 
P: search space
p1...pn: pixels

为了解决这个搜索问题,应该定义另外两个函数:

To solve this search problem two other functions should be defined:

E(P) : enumerates the search space
V(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list

假设算法的复杂性无关紧要,可以使用穷举或蛮力搜索,其中 E 获取每个像素并传递给 V.在实时应用中,重要的是减少搜索空间并优化计算V的效率.

Assuming the complexity of the algorithm doesn't matter, the exhaustive or brute-force search can be used in which E takes every pixel and passes to V. In real-time applications it's important to reduce the search space and optimize computational efficiency of V.

我们正在接近主要问题.我们如何定义 V,更准确地说,候选者的哪些属性应该是衡量标准,以及应该如何解决将它们分为可取和不可取的二分法问题.最常见的方法是找到一些属性,这些属性可用于基于属性的测量来定义简单的决策规则.这就是你通过反复试验所做的.您正在通过从正面和负面示例中学习来编写分类器.这是因为您使用的方法不知道您想做什么.您必须调整/调整决策规则的参数和/或预处理数据,以便减少二分法问题方法使用的(理想候选者的)属性的变化.您可以使用机器学习算法来找到给定示例集的最佳参数值.从决策树到遗传编程,您可以使用大量学习算法来解决这个问题.您还可以使用学习算法来找到几种圆检测算法的最佳参数值,并查看哪个提供更好的准确性.这承担了您只需要收集样本图像的学习算法的主要负担.

We are getting closer to the main question. How we could define V, to be more precise what properties of the candidates should be measures and how should make solve the dichotomy problem of splitting them into desirable and undesirable. The most common approach is to find some properties which can be used to define simple decision rules based on the measurement of the properties. This is what you're doing by trial and error. You're programming a classifier by learning from positive and negative examples. This is because the methods you're using have no idea what you want to do. You have to adjust / tune the parameters of the decision rule and/or preprocess the data such that the variation in the properties (of the desirable candidates) used by the method for the dichotomy problem are reduced. You could use a machine learning algorithm to find the optimal parameter values for a given set of examples. There's a whole host of learning algorithms from decision trees to genetic programming you can use for this problem. You could also use a learning algorithm to find the optimal parameter values for several circle detection algorithms and see which one gives a better accuracy. This takes the main burden on the learning algorithm you just need to collect sample images.

另一个经常被忽视的提高稳健性的方法是利用更容易获得的信息.如果您以几乎零额外的努力知道圆圈的颜色,您可以显着提高检测器的准确性.如果您知道平面上圆的位置并且想要检测成像的圆,您应该记住这两组位置之间的转换是由 2D 单应性描述的.并且可以仅使用四个点来估计单应性.然后,您可以提高稳健性以拥有坚如磐石的方法.特定领域知识的价值常常被低估.这样看,在第一种方法中,我们尝试基于有限数量的样本来近似一些决策规则.在第二种方法中,我们知道决策规则,只需要找到一种在算法中有效利用它们的方法.

The other approach to improve robustness which is often overlooked is to utilize extra readily available information. If you know the color of the circles with virtually zero extra effort you could improve the accuracy of the detector significantly. If you knew the position of the circles on the plane and you wanted to detect the imaged circles, you should remember the transformation between these two sets of positions is described by a 2D homography. And the homography can be estimated using only four points. Then you could improve the robustness to have a rock solid method. The value of domain-specific knowledge is often underestimated. Look at it this way, in the first approach we try to approximate some decision rules based on a limited number of sample. In the second approach we know the decision rules and only need to find a way to effectively utilize them in an algorithm.

总而言之,有两种方法可以提高解决方案的准确性/稳健性:

To summarize, there are two approaches to improve the accuracy / robustness of the solution:

  1. 基于工具:找到更易于使用的算法/参数数量更少/调整算法/使用机器学习算法自动执行此过程
  2. 基于信息的:您是否使用所有现成​​的信息?在问题中,您没有提及您对问题的了解.
  1. Tool-based: finding an easier to use algorithm / with fewer number of parameters / tweaking the algorithm / automating this process by using machine learning algorithms
  2. Information-based: are you using all the readily available information? In the question you don't mention what you know about the problem.

对于您分享的这两个图像,我将使用斑点检测器而不是 HT 方法.对于背景减法,我建议尝试估计背景的颜色,因为在两个图像中它没有变化,而圆圈的颜色会有所不同.而且大部分区域都是光秃秃的.

For these two images you have shared I would use a blob detector not the HT method. For background subtraction I would suggest to try to estimate the color of the background as in the two images it is not varying while the color of the circles vary. And the most of the area is bare.

这篇关于使用 OpenCV(基于霍夫变换或其他特征)编写鲁棒的(颜色和大小不变)圆检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Rising edge interrupt triggering multiple times on STM32 Nucleo(在STM32 Nucleo上多次触发上升沿中断)
How to use va_list correctly in a sequence of wrapper functions calls?(如何在一系列包装函数调用中正确使用 va_list?)
OpenGL Perspective Projection Clipping Polygon with Vertex Outside Frustum = Wrong texture mapping?(OpenGL透视投影裁剪多边形,顶点在视锥外=错误的纹理映射?)
How does one properly deserialize a byte array back into an object in C++?(如何正确地将字节数组反序列化回 C++ 中的对象?)
What free tiniest flash file system could you advice for embedded system?(您可以为嵌入式系统推荐什么免费的最小闪存文件系统?)
Volatile member variables vs. volatile object?(易失性成员变量与易失性对象?)