目录
前言
效果展示
检测库
简介
安装库
用法
测试
论文算法步骤简读
1. lsd 检测
2. lsd group
3. 生成初始 ellipse
4. 聚类
前言
椭圆检测是工业中比较常用的一种检测需求。目前常用的基于传统图像处理的椭圆检测方法是霍夫变换,但是霍变换的检测率比较低,很难满足工业场景。而基于深度学习的椭圆检测,只能用于特定场景下的椭圆检测,检测场景和标注数据有很大的关系,很难做到通用。
我无意中看到一篇椭圆检测的论文《An Efficient High-quality Ellipse Detection》,是基于传统图像处理算法进行的椭圆检测。效果很不错,对于标准椭圆的检测率很高,并且通用性很不错。但是论文作者只提供了基于matlab的源码,这么好的论文也没有人翻译成 c++ 库,所以我在理解原论文的基础上,经过一些调参和优化,实现了一个 c++ 版本的椭圆检测库(MIT LICENSE)效果和效率都很不错。
效果展示
先上图。
另外可以用我做的demo体验效果。线上体验:http://ellipsedetect.xyz/,或者小程序搜索 “椭圆识别“。
检测库
简介
椭圆检测库地址:
https://github.com/memory-overflow/standard-ellipse-detectiongithub.com/memory-overflow/standard-ellipse-detection
该库适用于边界清晰的椭圆检测、最好需要检测的的椭圆的大小在 200 * 200 像素以上,太小可能会有漏检,所以称之为标准椭圆检测。
安装库
库的的安装可以参考仓库的 wiki进行安装,注意 opencv 的版本一定要用 3.4.x。由于库使用了 shared_ptr,需要开启 c++11 及以上标准。
用法
该库的用法也很简单,您不必了解论文的具体实现细节。代码中引用头文件#include "ellipse_detection/detect.h"
,然后 zgh::detectEllipse(...) 调用。
接口说明
bool zgh::detectEllipse(
INPUT const uint8_t *image,
int height,
int width,
OUTPUT std::vector<std::shared_ptr<Ellipse> > &ells,
int polarity = 0,
double line_width = 2.0);
- 输入参数:
- image 图像原始数据,灰度图,彩色图需要先转换成灰度图,并且转换成一维数组输入
- height 图像高度
- width 图像宽度
- polarity 表示椭圆极性,-1、0、1, 默认为 0,检测所有极性,-1 表示只检测内部亮,外部暗的椭圆,1 表示只检测内部暗,外部亮的椭圆,0 表示不关注椭圆的内外部亮度关系,检测所有椭圆。
- line_width 椭圆边界的线宽,单位像素,推荐使用默认值,2 像素。
- 输出
- ells 检测到的椭圆列表
关于 Ellipse 结构的说明
Pointd o; // 椭圆中心点坐标
double a, b; // 短半轴长度,长半轴长度
double phi; // 椭圆偏角,单位为弧度
int polarity; // 椭圆极性
double goodness; // 椭圆评分
double coverangle; // 椭圆角度完整程度
std::vector<Pixel> inliers; // 构成的像素点
测试
提供了1个测试工具,可以查看效果。需要桌面版的操作系统才能显示图片,如果是服务器版本的操作系统,需要注释掉 imshow 部分。
cmake3 .. -DBUILD_TESTING=ON
make
./bin/testdetect [image_dir1] [image_dir2] [image_dir3] ...
论文算法步骤简读
如果对于论文的具体实现比较感兴趣,可以查看该部分内容。
该椭圆检测方法,主要分成如下4个步骤:
- lsd: 首先通过 lsd 检测算法生成很多细小的线段。
- lsd group: 通过搜索方法,将细小的线段连接成弧线。
- inital ellipse: 通过组合两条弧线,可以进行椭圆拟合,得到初始椭圆集。
- 聚类:对初始椭圆进行聚类,然后进行进一步的完整度评估,筛选出高完整度、高评分的椭圆。
1. lsd 检测
lsd 是一种传统的线段检测算法。它是基于梯度排序以后,通过查找近似矩形区域来获得线段。通过 lsd 可以提取图像中的细小线段,以下图为例子,
经过 lsd 检测算法后如下图,不同的颜色代表一条不同的线段。
2. lsd group
lsd group 的目的是为了把多个首尾相连的,并且斜率差在一定范围内的线段聚集成一组,组成一段弧。就也是通过搜索的方法找到连续的如下结构
如果有多条线段可以选择,采用一种像素投票机制,选择角度阈值内像素最多的线段。
如下图,相同颜色的线段组成了一组弧。
3. 生成初始 ellipse
选择任意两条弧线,只要满足一定的条件,那么这两个弧线就可能匹配组成一个椭圆。
找到所有的这样的一组弧以后,我们可以通过组成这些弧的所有像素点拟合出来一个椭圆(最小二乘法)。最后得到一个初始椭圆集。
4. 聚类
初始椭圆集里面,有很多相似的椭圆(椭圆心,长短轴,偏角都比较接近),对初始椭圆进行聚类,采用均值漂移聚类方法,对椭圆心,长短轴,偏角,分别进程聚类,得到更少,更具有代表性的椭圆。然后对这些椭圆进行最后的验证,筛选掉完整度不高的椭圆,得到椭圆检测的结果。