我有一个简单的代码,它利用了上一个答案中的一些提示,但使用了 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 给定您的测试图像。