使用opencv(基于霍夫变换或其他特征)编写鲁棒(颜色和大小不变)圆检测, [英] writing robust (color and size invariant) circle detection with opencv (based on Hough transform or other features)

查看:707
本文介绍了使用opencv(基于霍夫变换或其他特征)编写鲁棒(颜色和大小不变)圆检测,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了以下非常简单的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)

#对灰度图像做一些处理
cv.Erode(grey_scale,processed,None,10)
cv.Dilate(处理,处理,无,10)
cv.Canny(处理,处理,5,70,3)
cv.Smooth(处理,处理,cv.CV_GAUSSIAN,15,15)

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

#这些参数需要为每个单个图像调整
HIGH = 50
LOW = 140

$ b尝试:
#提取圈
cv.HoughCircles(处理,存储,cv.CV_HOUGH_GRADIENT,2,32.0,高,低)

对于i在范围len(np.asarray(storage))):
printcircle#%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])$ ​​b $ b center = (x,y)

#中心的绿色圆点和
周围的红色圆圈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 ,1,cv.CV_RGB(0,255,0),-1,8,0)
cv.Circle(processed,center,Radius,cv.CV_RGB(255,0,0),3,8, 0)

除了:
printnothing 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:







CASE2:







Case1和Case2基本上是相同的图像,但算法仍然检测不同的圆。如果我向算法呈现具有不同大小的圆的图像,则圆检测甚至可能完全失败。这主要是由于需要为每个新图片单独调整的 HIGH LOW 参数。 >

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

解决方案

以下基于我作为视觉研究员的经验。从你的问题,你似乎对可能的算法和方法感兴趣,而不是一个工作的代码。首先,我给你的样例图像一个快速和肮脏的Python脚本,一些结果显示,以证明它可能可以解决您的问题。在尝试解决这些问题后,我尝试回答关于强大检测算法的问题。



快速结果



一些示例图像(除了你的图像以外的所有图像都是从flickr.com下载的并且是CC许可的)与检测到的圆圈(不改变/调整任何参数,以下代码用于提取所有图像中的圆圈):





代码(基于MSER Blob检测器)



这里是代码:

  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 b $ b img2 = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

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

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

sfs = [x for 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检测器。除了将简单映射到灰度之外,代码不预处理图像。因此,预计在图像中缺少那些模糊的黄色斑点。



理论



简而言之:您不会告诉我们您所知道的问题从给出仅两个样品图像而没有描述它们。在这里,我解释为什么我谦虚地认为有更多的问题信息是重要的,在询问什么是有效的方法来攻击这个问题。



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

  P = {p1,...,pn} 
P:搜索空间
p1 .pn:pixels

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

  E(P):枚举搜索空间
V(p):检查项目/像素是否具有所需的属性,项目通过检查添加到输出列表

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



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



另一种提高鲁棒性的方法是利用额外的现成信息。如果你知道圆的颜色几乎零额外的努力,你可以提高检测器的精度显着。如果你知道圆的位置在飞机上,你想检测成像的圆,你应该记住这两个位置之间的转换由二维单应性描述。并且单应性可以仅使用四个点来估计。然后你可以提高鲁棒性有一个岩石坚实的方法。领域特定知识的价值常常被低估。看看这样,在第一种方法,我们试图逼近一些基于有限数量的样本的决策规则。在第二种方法中,我们知道决策规则,只需要找到一种在算法中有效利用它们的方法。



摘要



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


  1. 基于工具:找到更容易使用的算法/使用较少数量的参数/调整算法/使用机器学习算法自动完成此过程

  2. 基于信息:你使用所有现成​​的信息吗?

对于您共享的这两个图片,我将使用一个blob检测器不是HT方法。对于背景减法我建议尝试估计背景的颜色,因为在两个图像,它不变化,而圆的颜色变化。而且大部分地区是裸露的。


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:

CASE1:

CASE2:

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?

解决方案

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.

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):

Code (based on the MSER Blob Detector)

And here is the code:

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()

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.

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.

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

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.

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.

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.

Summary

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

  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.

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(基于霍夫变换或其他特征)编写鲁棒(颜色和大小不变)圆检测,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆