圆点标定板的标志点提取、标定实验总结

〇、环境

OpenCV 3.4+https://opencv.org/releases/
Matlab 带有Matlab calib toolbox:http://www.vision.caltech.edu/bouguetj/calib_doc/
(注:Matlab calib toolbox的好处就在于,你可以直接编辑、修改它的函数,以及看它的操作流程,同时在你的程序里也可以直接调用它的函数,自动化处理实验数据)
VS2015 msvc 的64位编译器 

一、总述&背景

Matlab只能标定棋盘格类型的靶标。尝试用OepnCV去标定圆点靶标,进行一系列的实验过程。
之前看到了一篇写了标定的文章,但是没给源码,决定自己动手试一试。
https://blog.csdn.net/a361251388leaning/article/details/54171233

先放出结论:用OpenCV进行圆点靶标的标定是挺准确的。同样它也考虑到了去透视投影变换去处理问题。而且这种方法只是作为它自己的方法的一种补救手段(说明它自己的方法效果更好),我们可以放心大胆的使用OpenCV的圆点标定。

二、调研&原理

圆点靶标相对于棋盘格靶标来说,具有一定的局限性,同时又有其独特的优势。

优点:在针对一些诸如投影仪和相机的标定过程中,需要知道特征点中心的投影仪投射的光的信息(如相移法)。但是我们的棋盘格由于是特征点是角点,所以不容易获得特征点中心的光信息。这是圆点靶标相对于棋盘格的一个优势。如华中科技大学的一篇关于相机和投影仪的标定文章《Accurate calibration method for a structured light system》,目前圆点标定板在三维扫描仪中应用更加广泛。

缺点:缺点也十分明显,圆点靶标摆放的位姿在与相机光轴不垂直的情况下,特征点的中心拍摄图像的特征点的中心(或者说是重心)这个时候不论用Steger方法提取光点中心,还是用OpenCV原生的blob方法获取斑点中心,效果理论上来说应该都不是可靠的,或者说精度较高的。在实际的拍摄过程中,我们不可能保证圆点靶标的位姿与相机光轴垂直。

针对上述的缺点进行了很多的研究。《机器视觉》(张广军)详细阐述了圆点在相机下的成像模型,写明了一般的椭圆(圆斑也是一种椭圆)在经过透视投影变换后的数学模型,但是未给出如何获得标志点的中心的方法。《光栅投影 三维精密测量》(达飞鹏)中不仅提到了如何获得圆点的中心,也提出了一种矫正圆点提取不准确的方法——采用同心圆环进行标定,通过圆环数学模型解出圆心的实际位置,可以得到更好的圆点中心,但是需要特殊形式的靶标。《Robust Detection and Ordering of Ellipses on a Calibration Pattern》(LPGC Luis Alvarez等人的讲义)中提到了如何用椭圆霍夫变换结合切线的方法获得更加精密的圆心坐标。但是同样的,一个是无法确定椭圆中心就是圆的中心,还一个问题就是用Hough变换去算圆的中心(或者说一系列基于图像边缘的方法获得中心),如果不采用作者类似的比较复杂的方法去获得中心,结果都将会有较大的偏差,且图像大了之后这样的方法将严重影响执行效率(因为复杂)。还有一些依据几何关系的方法,一篇中文文献《视觉标定中圆心投影点精确定位
》,感觉理解起来挺容易,但是上手也不好弄,而且采用边缘的方法个人还是觉得误差稍微较大。。在《光栅投影 三维精密测量》里也提到了一种基于边缘的方法,实现起来也较为复杂。
OpenCV原生的圆点提取尽管不是十分的鲁棒(有时候不容易检测出圆点的位置),但背后也有很复杂的原理,诸如网格分析以及聚类等。

实验以双目系统为例,参考了《Mastering Opencv》第三章的marklessAR的一些小技巧,思想很简单,我们首先用blobdetecto提取标定板四个角点的圆点的中心,然后求出单应矩阵H,调用openCV的Warpperspective函数,基于H矩阵转换拍摄图像,获得“正视“的靶标图像,为了减少噪声影响,采用一层高斯滤波处理转换图像,之后调用OpenCV的findCirclesGrid函数获得各标志点的中心,最后再用H矩阵反算回去。注意,这里由于采用的是一个H矩阵,所以并不存在计算误差(即结果与H无关),单应矩阵H仅仅用来视角转变。

最后,我们将生成的点列存储进txt文件,然后通过Matlab导入,再用Matlab标定工具箱进行标定,便可以获得最后的标定结果,以及不确定度和精度评价(重投影误差),与OpenCV原生的圆点提取方法进行对比。

三、代码

C++:提取点

/*
	By J.A 2019.6.12

	提取圆点靶标圆的中心,为了实现较好的标定手法,需要提高我们的提点的准确度
	圆形在透视投影变换之后,不再是一个圆形,而是椭圆形。
	一般的方法用于获取椭圆的中心,但是椭圆的中心不是圆的中心。
	所以我们需要先提取四个最远端的特征点的坐标,求解H矩阵,并进行透视畸变矫正。
	之后针对矫正图,调用OpenCV的函数获得圆点靶标的特征点的中心。
	最后将提到的点重建到图像平面(反透视投影变换, 这样我们获得的圆心才是真正的圆心。

	注:
	1、	Halcon的标定板,采用一个五边形作为外框,外框是一种线特征,不会随着透视投影产生位置畸变。(实际上,外框如果是一系列棋盘格构成的也行)。
		在这种情况下,我们可以先识别外框,然后依然依照上述的思想,获得特征点的坐标。据传,这也是Halcon的标定所采用的方法,由于本方法提取的坐标一开始并不是准确的,所以难免产生误差
		可以预计,本方法相对于上述的方法精度低一些。但是我们可以采用迭代的思想,在变换完成求得h矩阵后,再进行之前的操作,获得更加细化的H矩阵,效率上不高,但是效果应该可以做到相当
	2、 OpenCV寻找圆点标定板的函数 调用的是featuredector寻找点的中心,需要进行阈值化操作,并采用一定的过滤手段,由于我们的靶标上反射的光均匀程度不一,而且我们的相机也有一定的噪声
		个人建议首先采用一定大小的高斯滤波对矫正了透视投影畸变的图案进行滤波,以使灰度值变均匀,同时也不太影响我们的中心提取。结合圆中心提取的思想,我们也可以用steger方法获得更加
		精准的圆心,从而提高标定的精度
	3、	在诸如相移法等一些涉及到投影仪和相机的标定过程中,我们需要能够知道特征点的具体的其他信息,这个时候采用角点靶标(张正友)的方法就不合适了,必须采用圆点靶标,从而能够获得圆
		心的相位信息,提高整体测量系统的精度。
*/

//openCV 标准头文件
#include <opencv2\core.hpp>
#include <opencv2\features2d.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>
#include <opencv2\calib3d.hpp>

//c++ 标准头文件
#include <iostream>
#include <vector>
#include <string>
#include <fstream>

#include <direct.h>
#include <io.h>

//嗯 尽管不是一个好习惯,但是我还是用了(方便&人生苦短)
using namespace std;
using namespace cv;

//一些全局变量
const int WINDOW_SIZE_HEIGHT = 61;
const int WINDOW_SIZE_WIDTH = 61;
int g_rough_center_cnt = 0;

//用于参数回调
struct Params
{
	Mat p_ori_img;
	vector<KeyPoint> point;
	string this_window_name;
};

//靶标的具体尺寸信息,注意单位全部为mm
struct Calib_Board
{
	Size sp
评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值