参考资料
https://blog.csdn.net/app_12062011/article/details/51953030
https://blog.csdn.net/gggttt222/article/details/92976511
https://blog.csdn.net/Ketal_N/article/details/88829741
https://docs.opencv.org/3.4.11/d9/d0c/group__calib3d.html#gad1205c4b803a21597c7d6035f5efd775
结论
本次博客就是一个缝合怪,把自己看到的与opencv圆点棋盘相关的资料整理一下。当然也会在其中加入一些自己的理解,不然就是真的缝合怪了。
本博客将简单介绍一下findCirclesGrid使用的一些注意事项和技巧。
findCirclesGrid
1 opencv api介绍
首先来看一下opencv api的,毕竟这是最权威的材料。
bool cv::findCirclesGrid (
InputArray image, #输入图片,可以是单通道也可以是三通道
Size patternSize, # 棋盘格的大小,分别是每行有几个圆和每列有几个圆,后边会举例子
OutputArray centers, # 输出的圆心列表
int flags, # 共有三个参数,CALIB_CB_SYMMETRIC_GRID 表示棋盘格是对称的,CALIB_CB_ASYMMETRIC_GRID表示棋盘格是不对称的,CALIB_CB_CLUSTERING是一个特殊参数,在仿射变换比较严重时可以使用
const Ptr< FeatureDetector > & blobDetector, # 圆提取方法
CirclesGridFinderParameters parameters # 一些额外参数,但是文档里未介绍如何使用
)
根据以上api,不难发现一共有2个主要的地方需要额外注意:
- 圆形格的类型和大小
- 圆形的提取方法
接下来将主要围绕这两个问题展开。
2 圆形格的类型和大小
首先展示两种常用的圆形格,如下图所示(来源于参考资料);其中第一种时非对称圆形格(对应CALIB_CB_ASYMMETRIC_GRID),图中也已经展示了如何读取其大小;第二种时对称圆形格(对应CALIB_CB_SYMMETRIC_GRID ),此时大小就很明显了,7*7。通常情况下,对称和非对称并没有太大的区别,但是明显发现对称圆形格旋转后可能还是一样的,此时可能会对后方交会等等操作带来一些误解,因此通常而言都推荐使用非对称;除非本身旋转角度不大,那就无所谓。
另外需要额外注意的时,findCirclesGrid最终需要输出的时grid。一般情况下,当影像的倾角比较大的时候,可能会难以寻找grid。此时可以利用CALIB_CB_CLUSTERING。
CALIB_CB_CLUSTERING 会以层次Kmean方式聚类检测值,并计算检测点围成的凸包角点,并排序外部角点。同时,会根据排序后的2D外部角点和理想估计点,计算单应性H,再计算出所有监测点的投影点,再根据Knn选取跟理想估计点近似最近点,作为实际输出的圆形中点。(来源参考文献)
3 圆形的提取方法
通常,如果不加以特殊说明,findCirclesGrid提取圆形的时候使用默认const Ptr<FeatureDetector> &blobDetector = SimpleBlobDetector::create()
,其默认参数列表如下:
// 参考:https://blog.csdn.net/app_12062011/article/details/51953030
thresholdStep = 10; //二值化的阈值步长
minThreshold = 50; //二值化的起始阈值
maxThreshold = 220; //二值化的终止阈值
//重复的最小次数,只有属于灰度图像斑点的那些二值图像斑点数量大于该值时,该灰度图像斑点才被认为是特征点
minRepeatability = 2;
//最小的斑点距离,不同二值图像的斑点间距离小于该值时,被认为是同一个位置的斑点,否则是不同位置上的斑点
minDistBetweenBlobs = 10;
filterByColor = true; //斑点颜色的限制变量
blobColor = 0; //表示只提取黑色斑点;如果该变量为255,表示只提取白色斑点
filterByArea = true; //斑点面积的限制变量
minArea = 25; //斑点的最小面积
maxArea = 5000; //斑点的最大面积
filterByCircularity = false; //斑点圆度的限制变量,默认是不限制
minCircularity = 0.8f; //斑点的最小圆度
//斑点的最大圆度,所能表示的float类型的最大值
maxCircularity = std::numeric_limits<float>::max();
filterByInertia = true; //斑点惯性率的限制变量
//minInertiaRatio = 0.6;
minInertiaRatio = 0.1f; //斑点的最小惯性率
maxInertiaRatio = std::numeric_limits<float>::max(); //斑点的最大惯性率
filterByConvexity = true; //斑点凸度的限制变量
//minConvexity = 0.8;
minConvexity = 0.95f; //斑点的最小凸度
maxConvexity = std::numeric_limits<float>::max(); //斑点的最大凸度
单纯看以上参数,不难发现几个参数设置其实不一定总是合理。包括:手工设定阈值进行二值分割,以及手工设定阈值确定圆形的大小等等。
额外资料整理
博主gggttt222分享了一些有意思的东西,即圆形经过仿射变换时会变成椭圆,进而干扰标定精度。参考一下,我列出了一些论文,有空可以看看:
Accurate calibration method for a structured light system
《光栅投影 三维精密测量》(达飞鹏)
Geometric Correction of Circular Fiducials
Valication Code for Circular Correction
https://github.com/opencv/opencv/wiki/GSoC_2019#for-students-interested-in-applying