找圆方法的总结和比较(三种主要识别方法的比较和融合)

找圆方法的总结和比较(三种主要识别方法的比较和融合)

本篇博客是课程《

基于OpenCV的钢管计数项目实战》第7课的提纲。在前面已经详细分析3种主要算法的基础上,本节的重点在于如果将每一种算法找到的目标有效地融合起来,并且进一步横向分析研究算法间的关系,最后就整套算法创造过程中产生的思考进行联想和畅谈,希望多少能够给关注这个方向、有类似需求的创作者一些思考。

一、算法流程

首先对于自然图片,通过blod detection获得准确的半径以及一些准确的钢管;

而后基于准确的半径,分别调用HoughCircle以查漏补缺,对图片进行预处理后再调用Contours分析,寻找水泥管。

最后,以上获得的结果,需要进行融合筛选。

二、融合方法

数据结构:

使用

KeyPoint

vector

,这种数据结构能够保存x,y和size,对于圆这种对象来说,非常对口。

融合依据:

在添加的过程中首先进行判断:

for (size_t i

=

0; i

< specialKeypoints.size(); i

++)

{

bool isNear

=

true;

for (size_t j

=

0; j

< keypoints.size(); j

++)

{

double dist

= norm(specialKeypoints[i].pt

- keypoints[j].pt);

isNear

= (dist

<

= radius

*

2.

5f);

if (isNear)

{

break;

}

}

if (isNear)

{

keypoints.push_back(specialKeypoints[i]);

}

}

在全部点叠加之后,再进行筛选:

std

:

:vector

< KeyPoint

> resultKeypoints;

for (size_t i

=

0; i

< keypoints.size(); i

++)

{

bool isNew

=

true;

for (size_t j

=

0; j

< resultKeypoints.size(); j

++)

{

double dist

= norm(keypoints[i].pt

- resultKeypoints[j].pt);

isNew

= (dist

>

= keypoints[i].size

/

2

&& dist

>

= resultKeypoints[j].size

/

2);

if (

!isNew)

{

break;

}

}

if (isNew

&& keypoints[i].size

> radius)

resultKeypoints.push_back( keypoints[i]);

}

当然你也可以尝试将所有的点全部融合在一起后,再进行全局筛选。逻辑上是没有问题的,实际操作上效果要差一些。

三、算法异同

在程序的实现过程中,没有过多考虑并行等因素

// 基于Blob方法进行圆的寻找

SimpleBlobDetector

:

:Params params;

params.filterByColor

=

false;

params.minThreshold

=

0;

params.maxThreshold

=

250;

vector

> keypoints;

cv

:

:Ptr

:

:SimpleBlobDetector

> detector

= cv

:

:SimpleBlobDetector

:

:create(params);

detector

-

>detect(srcNormal, keypoints);

//获得半径

std

:

:vector

<

double

> dists;

double radius;

for (size_t pointIdx

=

0; pointIdx

< keypoints.size(); pointIdx

++)

{

dists.push_back(keypoints[pointIdx].size);

}

std

:

:sort(dists.begin(), dists.end());

radius

= (dists[dists.size()

/

2])

/

2.;

//基于HoughCircle方法进行圆的寻找

vector

> tmpKeypoints

= findPipMethodHough(srcNormal, radius);

//基于轮廓方法,专门寻找“水泥管”

vector

> specialKeypoints

= findConcretePip(srcNormal, radius);

我们将三类算法的结构进行比较:

算法代码注释讲解

SimpleBlobDetector::Params params;

params.filterByColor = false;

params.minThreshold = 0;

params.maxThreshold = 250;

vector keypoints;

cv::Ptr detector = cv::SimpleBlobDetector::create(params);

detector->detect(srcNormal, keypoints);

//获得半径

std::vector dists;

double radius;

for (size_t pointIdx = 0; pointIdx < keypoints.size(); pointIdx++)

{

dists.push_back(keypoints[pointIdx].size);

}

std::sort(dists.begin(), dists.end());

radius = (dists[dists.size() / 2]) / 2.;基于Blob方法进行圆的寻找,除了参数的定义有一些学问以外,基本上就是对自然图片进行基本处理,有个特点是然会radius

Mat gray;

vector vecCenters;

vector vec3f_method_hough;

//处理彩色图片,进行Hough处理

if (src.channels() == 3 || src.channels() == 4)

cvtColor(src, gray, COLOR_BGR2GRAY);

else

gray = src.clone();

blur(gray, gray, cv::Size(3, 3));

HoughCircles(gray, vec3f_method_hough, HOUGH_GRADIENT, 2, p_radius*2, 100, 33, p_radius-2, p_radius + 2);

for (int i = 0; i < vec3f_method_hough.size(); i++)

{

Point center(cvRound(vec3f_method_hough[i][0]), cvRound(vec3f_method_hough[i][1]));

cv::KeyPoint kpt(center, (float)(p_radius * 2.0f));

vecCenters.push_back(kpt);

}

return vecCenters;基于Hough方法进行圆的寻找,除了参数中radius是确定的以外,基本上就是通用的找圆算法

float f_area = CV_PI * p_radius * p_radius;//数学公式

vector vec_method_normal;//返回结果

Mat gray;

Mat tmp25;

Mat draw;

Mat srcClone = src.clone();

//局部阈值方法算法

cvtColor(src, gray, COLOR_BGR2GRAY);

blur(gray, gray, Size(3, 3)); //简单平滑

adaptiveThreshold(gray, tmp25, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY,(int) p_radius * 2 + 1, 0.0); //局部阈值

//形态学变换(膨胀)

Mat elementTest = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));

morphologyEx(tmp25, tmp25, cv::MORPH_ERODE, elementTest);

//边界的钢管识别(边界填充)

rectangle(tmp25, cv::Rect(0, 0, tmp25.cols, tmp25.rows), Scalar(255, 255, 255), 1);

//轮廓分析

std::vector < std::vector > contours;

findContours(tmp25, contours, RETR_LIST, CHAIN_APPROX_NONE);

vector vecCenters;

int minArea = f_area * 0.5f;

int maxArea = 5000;

float minCircularity = 0.47f;

float maxCircularity = std::numeric_limits::max();

for (size_t contourIdx = 0; contourIdx < contours.size(); contourIdx++)

{

//筛选条件

Moments moms = moments(contours[contourIdx]);

//area

double area = moms.m00;

if (area < minArea || area >= maxArea)

continue;

//circularity

double perimeter = arcLength(contours[contourIdx], true);

double ratio = 4 * CV_PI * area / (perimeter * perimeter);

if (ratio < minCircularity || ratio >= maxCircularity)

continue;

Point2d center = Point2d(moms.m10 / moms.m00, moms.m01 / moms.m00);

cv::KeyPoint kpt(center, (float)(p_radius * 2.0f));

vecCenters.push_back(kpt);

}

drawKeypoints(srcClone, vecCenters, draw, Scalar(0, 255, 0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

return vecCenters;虽然找不到几个目标,但是本函数是最复杂的(最长)的,在实现的过程中包含了圆度和面积的分析。特别是算法预处理这块,明显是有针对性地优化若干目标项目。

四、算法衍生

这一次的实现,是比较系统且复杂的轮廓分析算法,从结果上来看,基本能够满足设计要求;从对于自己的提高来看,引导我深入地研究相关知识,增强了能力,主要是能够针对不同情况,有选择性地选择算法实验。

回顾我做过的一些案例,有很多是涉及到轮廓分析的,这里进行回顾和比对:

1、树叶测量

页面分析系统是基于OpenCV+MFC(RIBBON)的精度测量项目。

其关键的一个部分在于实现了3种标定方法,能够获得“像素-距离”的实际关系。

最终通过轮廓分析,获得每一片叶子的面积、周长等信息。

在这个例子中,轮廓分析的主要用途是做联通区域处理,而后区分的结果进行分析和进一步处理。从这个角度上来说,使用联通区域那两个函数更适合。

这个例子使用了Ribbon,这是难得的能够和OpenCV结合良好的框架。相关材料去除敏感信息后出了相关教程。

https://edu.51cto.com/course/16030.html

2、石材大板

使用了类似“树叶分析”的程序框架,但是重点完全不一样。“石材大板”是石料行业中,需要采用计算机的方法对进出库的石材进行有效面积计算的过程(后续应该还可以进一步引导切割)。由于和工业深度融合,该项目对精度、可靠性、可扩充性要求都比较高。

我依然是使用OpenCV+MFC(Ribbon)来完成本项目,并且顺利交付。现在看来,当时的很多算法是臃肿的,界面由于需要有实现很多“辅助线”,最终的实现也不是很巧妙。这里进行介绍,能够帮助大家了解在工业上面,(传统)图像处理项目的基本方法。比较而言,钢管识别的实现体系要现代许多,但是对应起来,只能计数码,不能度量。

3、中药项目

比较早的一个项目,基于OpenCV+MFC,对黑箱采集的图片进行精度测量。

其中也使用了标定的过程。当时这个项目是给合肥一个学校做的,用于标准的制定。现在看来,实现过程中从算法到界面都已经全面过时了。但是当时这个项目仍然是做成功的,因为我采用的视觉经典测量的方法是可以解释的。我相信肯定也有这样的商品,就是做成一个黑箱,而后来测量。

4、答题卡项目

答题卡项目不是完全的轮廓分析,应该说是基于二值区域的投影分析,这些都是不同尺度上的应用。我分别使用c++和mfc进行了实现。现在想来,答题卡这个项目,如果实现pybind++的调用,结合手机,变成“小猿答题”这样的app,似乎很有趣味。

从中我们也可以看出,轮廓(团块)分析的确是强有力的分析工具,在OpenCV中也提供了不同层次的实现,非常值得我们深入研究、灵活运用。

在我之前做过的项目中,应该说以精度策略和数量策略为主,这可能是市场对轮廓这块的具体需求。

五、设计杂谈

【想结合算法的设计实现,谈一些务虚的东西】

为了提高算法能力,达到预定目的,我对OpenCV本身进行了较深入研究,应该说有“新发现,新认识”。

5.1、算法库的涉及范围广泛,需要进一步挖掘

OpenCV到底有多少算法,那些算法进行了优质实现?这些内容,如果不去进行具体研究,是很难得出明确结论的。这一次在findblob、hough的具体研究中,我发现OpenCV从算法本身、实现方法、实现细节,都是有很多值得深入研究的。

在之前很长,我都满足于对算法进行初步试用、认识较为模糊。这一次,为了效率,比如完整的、深刻地认识算法原理,并且“举重若轻”地提出解决方案。

这种方式,在将来是“新常态”;我也需要在一次又一次的“淬炼”中成为真正的专家。

5.2、算法库影响广泛、代码规范,都是将来发展重要依托

在OpenCV PR的过程中,我接触到了“规范的代码”,这潜移默化地改变了我的编码习惯。现在很多方面,我的工作是模糊的,毕竟不是做专门的工作。但是正确的东西就是正确的东西。

必须增强自己在算法实现过程中的影响力、锻炼正确的方法,这些都是未来的重要依托。

5.3、Github的维护方式,是

进一步“刻意练习”的重要依托

“可以练习”强调的是focus feed-back fix ,这在Github上面有非常好的体现,一定要寻找真正的专家,并且就普遍关心的问题进行深入的工作,这样才能进入能力提高“正循环”。

来自为知笔记(Wiz)

🎎 相关推荐

wps文档为什么一打开就是绿色背景色 背景变成了绿色方法
确保你的站点安全
🎯 365BT体育app

确保你的站点安全

📅 10-08 👀 3925
深圳电工证考试费用大揭秘:你花的钱值吗?
🎯 365BT体育app

深圳电工证考试费用大揭秘:你花的钱值吗?

📅 12-31 👀 2480