检测二进制图像中的圆圈

时间:2014-09-28 16:28:41

标签: algorithm opencv image-processing

您建议使用什么算法检测二进制图像中的黑色圆圈?我正在使用的图像是白色的,还有一些其他对象以及我感兴趣的黑色圆圈。 我已经实现了用于圆检测的霍夫变换方法。问题是任何算法比霍夫变换快多少?

这些不是完美的圆圈,而且我只知道它们的半径的下限和上限:

enter image description here

2 个答案:

答案 0 :(得分:5)

您必须先检测形状。这可以通过"连接组件分析来完成。

您可以使用现成的工具,或者您可以为您的目的制作一个简单的工具:实现flood filling algorithm,并按如下方式使用它:逐行扫描图像,直到遇到黑色像素。然后从这个像素填充洪水,涂成白色。这将使形状完全消失。继续扫描。最后,图像将完全变白。

但是,如果你没有跟踪发生的事情,那么这将完全没用。在填充形状时,您将记录您访问的像素的最小/最大横坐标和纵坐标。最后,您将知道形状的边界框。然后,您可以使用这个非常简单的标准来表示圆形的矩形:对于矩形,起始像素是边界框的左上角;不是一个圆圈。 (实际上,它甚至足以保持最小横坐标)。

你明白了。如果你处于一个更复杂的情况(比如三角形),请保持这个原则:执行斑点检测并测量斑点的一些几何特征;使用这些特征(它们被称为" blob特征")来区分你的形状。

更新:

一个非常有区别的测试可以如下:找到边界框并找到所有轮廓像素。然后对于每个轮廓像素检查(X-Xc)²/W²+(Y-Yc)²/H²=1/4,即它们位于以边界框为中心的椭圆上,并且轴(W/2, H/2)。由于形状的数字特性,您需要添加+/- 1像素容差。

答案 1 :(得分:2)

我有一个简单的代码,它利用了上一个答案中的一些提示,但使用了OpenCV函数:

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

int main(int argc, char **argv){

    Mat img = imread("test.png", 0);

    Mat edge, out;

    Canny(img, edge, 1, 1);
    cvtColor(img, out, CV_GRAY2BGR);

    vector<vector<Point> > contours;
    vector<Vec4i> hierachy;

    findContours(edge, contours, hierachy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0));

    for(int i = 0; i < (int)contours.size(); i++){
        double p = (double)contours[i].size();
        double a = contourArea(contours[i]);

        if(fabs(1-pow(p,2)/(4*CV_PI*a)) < 0.2){
            drawContours(out, contours, i, Scalar(0,0,255), 2);
        }
    }

    imshow("out", out);
    waitKey(0);
    return 0;
}

基本思路很简单。您可以以像素方式检索边缘图像中的所有外部(最外部,因此CV_RETR_EXTERNAL)轮廓(因此CV_CHAIN_APPROX_NONE)。拥有它们后,您可以使用该区域和周边来确定它们是否为圆形。在此示例中,我使用了简单的度量C=(P^2)/(4*PI*A),其中包含周边P和区域A。对于一个完美的圆圈,这将是1,所有偏离它的东西都不是圆圈。这当然仅适用于非重叠形状。

可能是简单的紧凑度测量不足以将圆圈与可能在图像中的其他形状区分开来。但为此,我建议调查这个paper,概述一些循环性和紧凑性度量,或者查看一些image moments(例如偏心率)和OpenCV中的实现。也许你可以提出自己的标准。

以下是给出测试图像的上述代码的output

enter image description here