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

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)

从以下两个例子中可以看出,"寻找圆的质量"差别很大:

CASE1:

input1 detection1 post-processed1

CASE2:

input2 detection2 post-processed2

Case1和Case2基本上是相同的图像,但算法仍然检测不同的圆.如果我用不同大小的圆呈现算法,圆检测甚至可能完全失败.这主要是由于HIGHLOW个参数需要 for each 新图片单独调整.

Therefore my question:使该算法更健壮的各种可能性是什么?它应该是大小和 colored颜色 不变的,以便检测不同 colored颜色 和大小的不同圆.也许使用霍夫变换不是最好的方法?有更好的方法吗?

推荐答案

以下内容基于我作为一名视觉研究人员的经验.从您的问题看,您似乎对可能的算法和方法感兴趣,而不仅仅是一段有效的代码.首先,我为您的样例图像提供了一个快速而肮脏的Python脚本,并展示了一些结果来证明它可能解决您的问题.在解决了这些问题之后,我将try 回答您关于健壮检测算法的问题.

Quick Results

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): detected blobs in the sample image 1 detected blobs in the sample image 2 lots of circles blobs in the flickr image 1

Code (based on the MSER Blob Detector)

下面是代码:

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气泡探测器.除了简单的灰度映射之外,代码不会对图像进行预处理.因此,在你的图像中错过那些微弱的黄色斑点是意料之中的.

Theory

In short: you don't tell us what you know about the problem apart from giving only two sample images with no description of them. Here I explain why I in my humble opinion it is important to have more information about the problem before asking what are efficient methods to attack the problem.

回到主要问题:解决这个问题的最佳方法是什么?

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

要解决此搜索问题,还应定义另外两个函数:

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的计算效率非常重要.

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

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

Summary

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

  1. Tool-based:找到一个更容易使用的算法/参数数量更少/调整算法/使用机器学习算法自动化这个过程
  2. 你在使用所有现成的信息吗?在问题中,你没有提到你对这个问题的了解.

对于您共享的这两张图像,我会使用斑点检测器,而不是HT方法.对于背景减go ,我建议try 估计背景的 colored颜色 ,因为在这两张图像中,背景的 colored颜色 不变,而圆圈的 colored颜色 不同.而这一地区的大部分地区都是光秃秃的.

C++相关问答推荐

XV 6中的MLFQ和RR

try 使用libusb控制音量时LIBUSB_WRIGHT_PIPE

如何将一个integer与一个数组进行比较?

InetPton()函数无效的IP地址

C语言中字符数组声明中的标准

难以理解Makefile隐含规则

使用scanf在C中读取和存储文件中的值

在句子中转换单词的问题

为什么Fread()函数会读取内容,然后光标会跳到随机位置?

在C++中父进程和子进程中的TAILQ队列同步问题

类型定义 struct 与简单的类型定义 struct

我在C程序的Flex/Bison中遇到语法错误

C标准关于外部常量的说明

为什么GCC-O1优化破解了这个代码,为了一个GameBoy高级只读存储器而修改了VRAM的循环?

如何修复我的qsort()算法?它每次都给出不同的结果

向左移位3如何得到以字节为单位的位数?

在分配内存后使用指针是未定义的行为吗?

STM32:代码的执行似乎取决于它在闪存中的位置

令人困惑的返回和 scanf 问题相关

如何使用 VLA 语法使用 const 指针声明函数