Kalibr源码学习(一): 重投影误差
Kalibr源码学习(一): 重投影误差
给自己挖一个大坑, 从标定结果来学习Kalibr的标定源码, 这里基本以KB模型为例, 也就是标定时, kalibr的模型设定为 --model pinhole-equi
, 这里以重投影误差开始,希望能坚持;
重投影误差标定结果
首先以重投影误差的txt文档的结果开始,
可以看到上面的标定结果中, 重投影误差显示为 reprojection error: [-0.000002, -0.000000] +- [0.535272, 0.572115]
这里的两项对应的分别是 reprojection error: [x方向的重投影误差均值, y方向的重投影误差均值] +- [x方向重投影误差方差, y方向重投影误差方差]
其对应的代码片
为:
//获取当前检测的角点,重投影坐标, 重投影误差
corners, reprojs, rerrs = getReprojectionErrors(cself, cidx) if len(rerrs)>0://获取重投影误差的均值me和方差seme, se = getReprojectionErrorStatistics(rerrs)//打印输出到txt文档中print >> dest, "\t reprojection error: [%f, %f] +- [%f, %f]" % (me[0], me[1], se[0], se[1])print >> dest
这里可以再说以下计算均值和方差的python代码:
在这里插入代码片
```def getReprojectionErrorStatistics(all_rerrs):#传入值是所有的误差 errors, 这里代码里面举出的例子usage是错误的,传入的应该是error,不是重投影if not len(all_rerrs)>0:raise RuntimeError("rerrs has invalid dimension")gc.disable() #append speed uprerr_matrix=list();for view_id, view_rerrs in enumerate(all_rerrs):if view_rerrs is not None: #if cam sees target in this viewfor rerr in view_rerrs:if not (rerr==np.array([None,None])).all(): #if corner was observedrerr_matrix.append(rerr) #将误差值统一放入到rerr_matrix中rerr_matrix = np.array(rerr_matrix)gc.enable()mean = np.mean(rerr_matrix, 0, dtype=np.float)#计算均值std = np.std(rerr_matrix, 0, dtype=np.float)#计算方差return mean, std
重投影误差图像显示
这个图对应的代码为:
def plotAllReprojectionErrors(cself, cam_id, fno=1, noShow=False, clearFigure=True, title=""):# left: observations and projecitons# right: scatterplot of reprojection errorsall_corners, reprojections, rerrs_xy = getReprojectionErrors(cself, cam_id)resolution = (cself.cameras[cam_id].geometry.projection().ru(), cself.cameras[cam_id].geometry.projection().rv())#创建图像values = np.arange(len(cself.views))/np.double(len(cself.views))cmap = pl.cm.jet(values,alpha=0.5)#子图一用来画重投影后的坐标 省略a=pl.subplot(121)#子图二用来画重投影误差sub = pl.subplot(122)for view_id, rerrs in enumerate(rerrs_xy):if rerrs is not None: #if this camerea sees the target in this viewcolor = cmap[view_id,:]pl.plot(rerrs[:,0], rerrs[:,1], 'x', lw=3, mew=3, color=color)# 主要是这里,x代表的是重投影的x误差, y表示的是重投影的y值误差, 以 error_x 为横坐标, 以error_y为纵坐标,画图pl.axis('equal')pl.grid('on')pl.xlabel('error x (pix)')pl.ylabel('error y (pix)')#省略...
这里重点说一下获取重投影误差的函数, 经过层层调用, 最后计算出的其实是将三维点投影到图像上
//将传入的三维点投影到图像上
template<typename DISTORTION_T>
template<typename DERIVED_P, typename DERIVED_K>
bool PinholeProjection<DISTORTION_T>::euclideanToKeypoint(const Eigen::MatrixBase<DERIVED_P> & p,const Eigen::MatrixBase<DERIVED_K> & outKeypointConst) const {EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_P>, 3);EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_K>, 2);Eigen::MatrixBase<DERIVED_K> & outKeypoint = const_cast<Eigen::MatrixBase<DERIVED_K> &>(outKeypointConst);//shinan note: 转换到归一化相机平面 --> 加畸变 -->转换到像素平面outKeypoint.derived().resize(2);double rz = 1.0 / p[2];outKeypoint[0] = p[0] * rz;outKeypoint[1] = p[1] * rz;//加畸变_distortion.distort(outKeypoint);outKeypoint[0] = _fu * outKeypoint[0] + _cu;outKeypoint[1] = _fv * outKeypoint[1] + _cv;return isValid(outKeypoint) && p[2] > 0;
}
其中加畸变函数如下:
//将传入的归一化相机坐标系的三维点按照公式加畸变
template<typename DERIVED_Y>
void EquidistantDistortion::distort(const Eigen::MatrixBase<DERIVED_Y> & yconst) const {EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE_OR_DYNAMIC(Eigen::MatrixBase<DERIVED_Y>, 2);Eigen::MatrixBase<DERIVED_Y> & y = const_cast<Eigen::MatrixBase<DERIVED_Y> &>(yconst);y.derived().resize(2);double r, theta, theta2, theta4, theta6, theta8, thetad, scaling;r = sqrt(y[0] * y[0] + y[1] * y[1]);theta = atan(r);theta2 = theta * theta;theta4 = theta2 * theta2;theta6 = theta4 * theta2;theta8 = theta4 * theta4;thetad = theta* (1 + _k1 * theta2 + _k2 * theta4 + _k3 * theta6 + _k4 * theta8);scaling = (r > 1e-8) ? thetad / r : 1.0;y[0] *= scaling;y[1] *= scaling;
}
总结
这里有一点就是这里的重投影误差的均值很小, 主要的原因可以从上面的彩色图中看出, 重投影误差有正有负,均值会出现互相抵消的状态; 总体来讲是以(-0.000002, -0.000000)为中心, 方差分别是0.535272, 0.572115的正态分布;
所以说,均值不可信,方差大概率更靠谱一些: 如下面标定的很好的结果中:
reprojection error: [0.000000, 0.000001] ± [0.115878, 0.107625]
方差仅为0.1, 其对应的重投影误差的值也都偏小:
根据3*sigma原则, 要想让大部分的重投影误差小于1个像素, 那么其所对应的方差应该是小于0.33.
Kalibr源码学习(一): 重投影误差相关推荐
- Opencascade源码学习之模型数据——TKGeomBase模块文件介绍
Opencascade源码学习之模型数据--TKGeomBase模块文件介绍 1.AdvApp2Var 2.AppCont 3.AppDef 4.AppParCurves 5.Approx 6.Bnd ...
- 【Android 源码学习】SharedPreferences 源码学习
第一章:SharedPreferences 源码学习 文章目录 第一章:SharedPreferences 源码学习 Android SharedPreferences的缺陷 MMKV.Jetpack ...
- JDK11源码学习05 | HashMap类
JDK11源码学习05 | HashMap类 JDK11源码学习01 | Map接口 JDK11源码学习02 | AbstractMap抽象类 JDK11源码学习03 | Serializable接口 ...
- AFNetworking源码学习 1
简介: AFNetworking是iOS.macOS.watchOS和tvOS的一个令人愉快的网络库.它建立在基础URL加载系统之上,扩展了构建到Cocoa中的强大的网络高级抽象.它有一个模块化的体系 ...
- [阿里DIN] 从论文源码学习 之 embedding层如何自动更新
[阿里DIN] 从论文源码学习 之 embedding层如何自动更新 文章目录 [阿里DIN] 从论文源码学习 之 embedding层如何自动更新 0x00 摘要 0x01 DIN源码 1.1 问题 ...
- Opencascade源码学习之模型算法_TKO模块文件介绍
Opencascade源码学习之模型数据_TKO模块文件介绍 1.TKO 1.BOPAlgo 2.BOPDS 3.BOPTools 4.BRepAlgoAPI 5.IntTools 1.TKO 1.B ...
- PHP 源码学习之线程安全
PHP 源码学习之线程安全 了解线程安全之前,我们先回顾几点基础知识点,是我们后面分析学习的基础. 变量的作用域 从作用域上来说,C语言可以定义4种不同的变量:全局变量,静态全局变量,局部变量,静态局 ...
- Hadoop HDFS源码学习之NameNode部分
NameNode源码学习 文章目录 NameNode源码学习 一.文件系统目录树(第一关系) 2.1 INode相关类 2.2 快照特性的实现 2.3 FSEditLog类 2.4 FSImage类 ...
- Opencascade源码学习之模型数据
Opencascade源码学习之模型数据 1.模型数据 2.几何工具 1.插值和拟合 1.分析一组点 2.基本插值和近似 3.2D 插值 4.3D 插值 5.2D 拟合 6.3D 拟合 7.曲面拟合 ...
最新文章
- CSS3 transform
- php开发者大会报名,2017 PHP 全球开发者大会
- React中的方法调用
- CodeForces - 1141CPolycarp Restores Permutation搜索+剪枝
- mysql命令(command)
- ae连续流动的线条_贡献 | AE片头制作绝对经验
- GC参考手册 —— GC 调优(基础篇)
- raster | R中的栅格操作符(下)[翻译]
- [Redis]Redis的数据类型
- 腾讯体育php面试题,腾讯php程序员面试题目及答案分享!
- 从零开始研发GPS接收机连载——3、用HackRF软件无线电平台作为GPS模拟器
- 写给非网工的CCNA教程(8)跨LAN的通信
- 计算n阶行列式的C语言实现
- 【成像】【4】产生连续波Terahertz辐射
- 递归算法与非递归算法的转化
- 用户体验设计师常用的21款工具和应用
- Vue微信网页微信支付
- [FPGA]1 MRCC与SRCC学习
- (FFMpeg学习笔记):FFmpeg下载、ffmpeg.exe与ffplay.exe的基本使用
- IT资源汇总全分享,学习资料免费领取处
热门文章
- bzoj 1664: [Usaco2006 Open]County Fair Events 参加节日庆祝(DP)
- bzoj 1821: [JSOI2010]Group 部落划分
- C++ STL bitset类常用函数的使用
- 集群间动态扩展和删除hdfs的datanode和hbase的regionserver
- docker安装常用组件(mysql,redis,postgres,rancher,Portainer,蝉道,JIRA,sonarqube,Confluence,pgadmin4,harbor)
- samba配置过程(附网络凭据的解决方法)
- PYUIC和PYRRC作为外部工具的配置
- [codewars] - int32 to IPv4 二进制十进制 ip地址转换
- \n 屏幕换行 源码换行
- 原来竟然还有这种局部变量!