稀疏直接法

主要用的g2o的方法。自己定义了一个新的一元边。边的误差项是测量值和由估计得来的x,y对应的灰度值之间的误差。导数为灰度对像素坐标的导数乘以像素坐标对yi*李代数的导数的负数。灰度对于像素坐标的导数矩阵为1*2的矩阵。比如像素坐标为u,v.第一个数就是灰度关于u的导数,为u+1,v对应的灰度值和u-1,v对应的灰度值之差再除以2.v同理。
而像素坐标对yi*李代数的导数为2*6的雅克比矩阵。这个导数可以转化为两个导数的乘积,一个是像素坐标对空间点的导数,一个是空间点对yi*李代数的导数。
像素坐标和空间点有这样的关系
u=x*fx/z+cx
v=y*fy/z+cy.
u对x,y,z进行求导分别为fx/z,0,-x*fx/(z*z)
v对x,y,z进行求导分别为0,fy/z,-y*fy/(z*z).
而空间点x,y,z对yi*李代数的导数为[I,-空间点的反对称矩阵】
这样两者相乘就可以了。
因为求解误差项的时候和求解灰度对于像素坐标的导数的时候都要用到估计值的灰度值,所以要有一个灰度值函数,这个灰度值函数是对图像进行双线性插值得到的。所谓的双线性插值就是
a+bx+cy+dxy.
这里的a可以为(1-xx)*(1-yy),b=xx*(1-yy),c=yy(1-xx),d=xx*yy.其中xx=x-deltax,y=y=deltay.
g2o的顶点就是估计值,可以用_vertices[0]赋值,赋值之后就用这个值计算估计值,有估计值就可以计算误差等。进而迭代找到最优的估计值。

现在来看整个程序是怎么实现的。

1.读图和设置一些需要的变量。
定义图像数据路径,定义associate.txt文件路径,定义图像矩阵color,depth,gray,之后fin可以把aaociate里的每一行来读取相对应的彩色图和深度图。
定义fx,fy,cx,cy,depth_scale.fx,fy,cx,cy都是相机内参矩阵的组成部分,depth_scale为深度图缩放因子。有前四项可以得到K,depth_scale之后待用。
定义Tcw类型和初值,Eigen::Isometry3d::Identity().
定义prev_color,之后就把第一张图片设置成参考图。

2.做一个for循环,对第一帧提取FAST特征点,去掉邻近边缘处的点
在这个循环里,不断地读取associate.txt里对应的数据集下的彩色图和深度图,然后赋值给color和depth.但只有第一张图片为prev_color,也只对第一张图片提取关键点。提取关键点之后,对关键点进行筛选,阈值是20.筛选之后,得到这些关键点的空间点坐标和灰度值,组成一个结构体,放到测量值里。
其中得到空间点要经过
z=d/depth_scale,
x=(u-cx)*z/fx
y=(u-cy)*z/fy
其中d是深度值,需要在深度图上读取,记住坐标是先y后x.而且是(y)[int x]
得到灰度值,首先需要得到灰度图,灰度图是由彩色图得到的。用cv::cvtColor函数。
cv::cvtColor ( color, gray, cv::COLOR_BGR2GRAY );
然后从灰度图里读取像素坐标对应的灰度值,也是先v后u的,而且是(v)[u],其实应该都是u,v,但是这里都表示成了x,y.
float grayscale = float ( gray.ptr<uchar> ( cvRound ( kp.pt.y ) ) [ cvRound ( kp.pt.x ) ] );

3.构造稀疏直接法位姿估计函数poseEstimationDirect函数
这里的变量只需要测量值measurements,下一张图片的灰度图&gray,相机内参矩阵K,和要求的Tcw就可以了。
这个函数没有什么特别的,无非还是先设置估计的值的类型,求解器,求解的方法,这里是列文伯格。图模型optimizer,图模型求解方法列文伯格,图模型设置调试输出.setVerbose(true)。
主要来看我们自己造的边。
这个边类里面有几个变量,分别是空间点坐标,fx,fy,cx,cy,*image.空间点坐标之后放的是测量值的空间点坐标,也就是第一张图像的关键点对应的空间点坐标。*image放的是下一张图像的灰度图。
计算误差的时候会把估计值复制给v.然后v是位姿,把空间点映射成第二张图片的空间点,然后经过内参矩阵,映射之后的空间点转换为第二张图片上的像素坐标,对这些像素坐标进行筛选,阈值为4.如果不在范围内,误差值设为0,level设为1.如果在范围内,误差为这些误差值对应的灰度值和测量值的灰度值相减。基于灰度不变假设。
而在边类的计算雅克比矩阵的函数linearizeOplus函数里,如果level=1,就是之前计算得到的像素坐标不在范围内,最终的雅各比矩阵设为0.最终雅克比矩阵形式为1*6的,为
_jacobianOplusXi=Eigen::Matrix<double,1,6>::Zero().
同样,这里吧位姿估计值赋值给vtx,然后计算得到在第二张图片上的关键点的空间点坐标xyz_trans.然后计算得到最终的雅克比矩阵。
然后在protected里定义灰度值函数。
这里灰度值数据访问形式为
uchar* data = & image_->data[ int ( y ) * image_->step + int ( x ) ];
deltax为floor(x),deltay=floor(y).1,x,y,xy分别为data[0],data[1],data[image_->step],data[image_->step+1]
这个灰度值函数定义为内联函数,方便计算。
最终在public里要定义类变量的类型和初值。这里就是空间点坐标,内参,灰度图了。
然后看函数执行过程
先设置位姿的类型和初值,然后设置位姿的估计值形式为se3quat形式,是由Tcw的旋转矩阵和位移矩阵构成的。setId(0),然后把这个顶点添加到图模型里。
然后构造边,边是一个个进行构造的,每个测量值都可以构造一个边。所以构造一个循环
for (Measurement m:measurements)
{
设置边的类型,边的初值是由m.pos_wolrd,内参,新的灰度图构造的。
边连接的顶点就是pose,测量值就是m.grayscale,信息矩阵就是1*1的单位矩阵,id就是id++.然后图模型把这条边给加上。
记着顶点和边都是指针,定义的时候要带*号,赋初值的时候要带new.

4.画图,这里画图是把第一种图片和之后的其他图片做对比,而且把图片中的每个关键点都用圆圈标注,两张图片对应的关键点连线。
要同时展示两张图片,img_show的行要是图片行的两倍,列还是图片的列。
cv::Mat img_show(color.rows*2,color.cols,CV_8UC3);
把第一种图片prev_color复制到img_show的,从0,0到color.cols,color.rows.
而color则复制到img_show,从0.color.rows开始,行列为color.cols,color.rows.
对于测量值的每一项,既是第一张图片的关键点的空间点坐标和灰度值组成的。
可以知道在第一张图片关键点的空间点坐标,由此得第一张图片关键点的像素坐标pixel_prev,由Tcw可以得关键点在第二张图片的空间点坐标,由此的特征点在第二张图片的像素坐标pixel_now。
筛选如果像素坐标小于0或者像素坐标超出图片行或列,跳出循环。
计算b,g,r值,因为用圆圈标注的时候需要用到b,g,r的值。
值都为255*float ( rand() ) /RAND_MAX;
标注函数是cv::circle,第一种图像标注的变量为img_show,像素坐标,8,cv::Scalar(b,g,r),2
第二张图片标注用img_show,关键点在第二张图片上的像素坐标u,v但是v要加上函数color.rows,8,cv::Scalar(b,g,r),2.
连线,用cv::line函数,变量为img_show,第一张图片像素坐标,第二张像素坐标(v+color.rows),cv::Scalr(b,g,r),1.
展示图像用cv::imshow()
cv::waitKey(0);
这是暂停,按任意键执行下个循环。

来源:http://www.cnblogs.com/talugirl/p/7388586.html

半稠密法

半稠密直接法和稀疏直接法求解过程基本上是一样的,只是稀疏直接法提取的是fast关键点,一般是几千个,而半稠密直接法提取的是梯度明显的像素,一般是几万个,这里是提取了一万多个。
所谓的梯度明显的像素,就是像素的灰度值同它周围的像素有明显的区别,这里是拿(v)[u+1]和(v)[u-1],还有(v+1)[u]和(v-1)[u]处的像素的灰度值进行比较的,之前造的边的图像关于像素坐标的导数也是这么求的。
比如设这两个比较值为a,b,如果a*a+b*b>=50,说明u,v处的像素梯度是明显的。
具体程序中
1.主要是在对第一张图片的处理上,for(index==0)
造两个循环,x和y,筛选了一些像素坐标,阈值是10.
定义delta值为灰度的两个比较值的组合
for(int x=10;x<gray.cols-10;x++)
for(int y=10;y<gray.rows-10;y++)
{
Eigen::Vector2d delta(
gray.ptr<uchar>(y)[x+1]-gray.ptr<uchar>(y)[x-1],
gray.ptr<uchar>(y+1)[x]-gray.ptr<uchar>(y-1)[x]
);
如果delta.norm()小于50,就跳出这个循环,这个x,y值就不要了。如果大于等于50,继续循环
再读取x,y对应的深度值,如果深度值为0,这个x,y也不要了。如果不为0,继续。
ushort d=depth.ptr<ushort>(y)[x];
if(d==0)
continue;
这时候满足条件的像素坐标x,y就筛选出来了。求出这些像素坐标的空间点坐标和灰度值,组成测量结构待用。
Eigen::Vector3d p3d=project2Dto3D(x,y,d,fx,fy,cx,cy,depth_scale);
float grayscale=float(gray.ptr<uchar>(y)[x]);
measurements.push_back(Measurement(p3d,grayscale));
用g2o求解的相机位姿。

来源:http://www.cnblogs.com/talugirl/p/7388577.html

ch8 -- directMethod的更多相关文章

  1. Mongodb Manual阅读笔记:CH8 复制集

    8 复制 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔 ...

  2. [Database.System.Concepts(6th.Edition.2010)].Abraham.Silberschatz. Ch8学习笔记

    Database Ch8.relational design 8.1 features of good design 8.1.1 larger alternatives why design is g ...

  3. linux 私房菜 CH8 linux 磁盘与文件系统管理

    索引式文件系统 superblock 记录此系统的整体信息,包括 inode/block 的总量.使用量.剩余量,以及文件系统的格式与相关信息等: inode 记录档案的属性,一个档案占用一个 ino ...

  4. [HDFS Manual] CH8 HDFS Snapshots

    HDFS Snapshots HDFS Snapshots 1. 概述 1.1 Snapshottable目录 1.2 快照路径 2. 带快照的更新 3. 快照操作 3.1 管理操作 3.2 用户操作 ...

  5. 【学习笔记】Learning OpenCV3——Ch8 working with video

    Reading Video with the cv::VideoCapture Object 对象创建的三种方法: // 1. Input filename cv::VideoCapture::Vid ...

  6. ch8 -- useLK

    useLK 光流法跟踪FAST角点 执行    ./useLK ../../data 运行程序. 光流法需要include<opencv2/video/tracking.hpp>,用到列表 ...

  7. 【读书笔记】构建之法(CH7~CH8)

    MSF九大原则: 1. 推动信息共享与沟通:“谐”,Alert 2. 为共同的远景而工作:目标明确—用户/老板 3. 充分授权和信任: 4. 各司其职,对项目共同负责: 5. 交付增量的价值: 6. ...

  8. Core java for impatient 笔记 ch8 流

    流stream 使用了数据视图,让你可以在比集合更高的概念上指定操作使用流,你只需要将操作的调度留给实现,例如,假设你要计算某个属性的平均值,你只需要指定数据源和属性,然后流类库会优化计算,比如使用多 ...

  9. ch8 固定宽度、流式、弹性布局

    假设浏览器窗口设置为1250px:wrapper的宽度为960px:content的宽度为920px:确保了wrapper居中时两边有20px的间距:  secondary的宽度为230px:  pr ...

随机推荐

  1. 实现两个窗口通信方法-postMessage

    此方案可解决跨域而且跨Iframe,而且http和https之间的交互 首先来看一下基本的语法 otherWindow.postMessage(message, targetOrigin, [tran ...

  2. mysql调优参考笔记

    之前一位童鞋发的: 5版邮件,在用户量很大的情况下,如果做了分布式,如果在后端mysql上执行:   mysql> show global status like 'Thread%';   Th ...

  3. 2488 绿豆蛙的归宿(拓扑+dp)

    488 绿豆蛙的归宿  时间限制: 1 s  空间限制: 64000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 随着新版百度空间的上线,Blog宠物绿豆 ...

  4. js中eval详解

    先来说eval的用法,内容比较简单,熟悉的可以跳过   eval函数接收一个参数s,如果s不是字符串,则直接返回s.否则执行s语句.如果s语句执行结果是一个值,则返回此值,否则返回undefined. ...

  5. 标准模板库(STL)学习指南之sort排序

    对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算法也基本固定下来,不需要你再去花费心思 ...

  6. [转]基于phantomJS实现web性能监控

    1.web性能监控背景描述 上期分享的<Web性能监控自动化探索之路–初识WebPageTest>从依赖webpagetest的角度给出了做性能日常检查的方案,但由于依赖结构相对复杂我们需 ...

  7. 办公软件-Excel:Microsoft Office Excel 2003百科

    ylbtech-办公软件-Excel:Microsoft Office Excel 2003百科 Microsoft® Office Excel 2003 是一种电子表格程序,可提供对于 XML 的支 ...

  8. 杂项-Log:log4net

    ylbtech-杂项-Log:log4net log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台.文件.数据库等) ...

  9. 《Kubernetes权威指南第2版》学习(四)kubernetes基本概念和术语

    1: etcd是干什么的: 键-值存储仓库,用来配置共享和服务发现. k8s把Node, pod,replication controller, Services看做是资源对象,这些资源对象可以通过K ...

  10. php-fpm包的安装与配置

    实验环境:CentOS7 [root@~ localhost]#yum -y install php-fpm php-fpm包:用于将php运行于fpm模式 #在安装php-fpm时,一般同时安装如下 ...