zoukankan      html  css  js  c++  java
  • V-LOAM源码解析(二)

    转载请注明出处:本文转自zhch_pan的博客http://www.cnblogs.com/zhchp-blog/

    本博客为本人之前做项目时做的源码阅读工作,po到网上希望帮助其他人更好的理解V-LOAM的工程实现,有些地方代码做了修改,可能和原工程有出入,但对于该工程的整体流程理解没有妨碍。

    源码下载链接:https://github.com/Jinqiang/demo_lidar


    节点:visualOdometry

    功能:订阅"/image_points_last""/depth_cloud"消息,将图像特征与三维点云匹配,获得图像特征点深度值,然后采用非线性优化的方法迭代收敛得到两帧图像之间的变换矩阵,即融合了三维点云信息的视觉里程计。

      1 #include <math.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <ros/ros.h>
      5 
      6 #include <nav_msgs/Odometry.h>
      7 #include <sensor_msgs/Imu.h>
      8 
      9 #include <tf/transform_datatypes.h>
     10 #include <tf/transform_listener.h>
     11 #include <tf/transform_broadcaster.h>
     12 
     13 #include "cameraParameters.h"
     14 #include "pointDefinition.h"
     15 
     16 const double PI = 3.1415926;
     17 
     18 pcl::PointCloud<ImagePoint>::Ptr imagePointsCur(new pcl::PointCloud<ImagePoint>());
     19 pcl::PointCloud<ImagePoint>::Ptr imagePointsLast(new pcl::PointCloud<ImagePoint>());
     20 pcl::PointCloud<ImagePoint>::Ptr startPointsCur(new pcl::PointCloud<ImagePoint>());
     21 pcl::PointCloud<ImagePoint>::Ptr startPointsLast(new pcl::PointCloud<ImagePoint>());
     22 pcl::PointCloud<pcl::PointXYZHSV>::Ptr startTransCur(new pcl::PointCloud<pcl::PointXYZHSV>());
     23 pcl::PointCloud<pcl::PointXYZHSV>::Ptr startTransLast(new pcl::PointCloud<pcl::PointXYZHSV>());
     24 pcl::PointCloud<pcl::PointXYZHSV>::Ptr ipRelations(new pcl::PointCloud<pcl::PointXYZHSV>());
     25 pcl::PointCloud<pcl::PointXYZHSV>::Ptr ipRelations2(new pcl::PointCloud<pcl::PointXYZHSV>());
     26 pcl::PointCloud<pcl::PointXYZ>::Ptr imagePointsProj(new pcl::PointCloud<pcl::PointXYZ>());
     27 pcl::PointCloud<DepthPoint>::Ptr depthPointsCur(new pcl::PointCloud<DepthPoint>());
     28 pcl::PointCloud<DepthPoint>::Ptr depthPointsLast(new pcl::PointCloud<DepthPoint>());
     29 pcl::PointCloud<DepthPoint>::Ptr depthPointsSend(new pcl::PointCloud<DepthPoint>());
     30 
     31 std::vector<int> ipInd;
     32 std::vector<float> ipy2;
     33 
     34 std::vector<float>* ipDepthCur = new std::vector<float>();
     35 std::vector<float>* ipDepthLast = new std::vector<float>();
     36 
     37 double imagePointsCurTime;
     38 double imagePointsLastTime;
     39 
     40 int imagePointsCurNum = 0;
     41 int imagePointsLastNum = 0;
     42 
     43 int depthPointsCurNum = 0;
     44 int depthPointsLastNum = 0;
     45 
     46 pcl::PointCloud<pcl::PointXYZI>::Ptr depthCloud(new pcl::PointCloud<pcl::PointXYZI>());
     47 pcl::KdTreeFLANN<pcl::PointXYZI>::Ptr kdTree(new pcl::KdTreeFLANN<pcl::PointXYZI>());
     48 
     49 double depthCloudTime;
     50 int depthCloudNum = 0;
     51 
     52 std::vector<int> pointSearchInd;
     53 std::vector<float> pointSearchSqrDis;
     54 
     55 double transformSum[6] = {0};
     56 double angleSum[3] = {0};
     57 
     58 int imuPointerFront = 0;
     59 int imuPointerLast = -1;
     60 const int imuQueLength = 200;
     61 bool imuInited = false;
     62 
     63 double imuRollCur = 0, imuPitchCur = 0, imuYawCur = 0;
     64 double imuRollLast = 0, imuPitchLast = 0, imuYawLast = 0;
     65 
     66 double imuYawInit = 0;
     67 double imuTime[imuQueLength] = {0};
     68 double imuRoll[imuQueLength] = {0};
     69 double imuPitch[imuQueLength] = {0};
     70 double imuYaw[imuQueLength] = {0};
     71 
     72 ros::Publisher *voDataPubPointer = NULL;
     73 tf::TransformBroadcaster *tfBroadcasterPointer = NULL;
     74 ros::Publisher *depthPointsPubPointer = NULL;
     75 ros::Publisher *imagePointsProjPubPointer = NULL;
     76 ros::Publisher *imageShowPubPointer;
     77 
     78 const int showDSRate = 2;
     79 
     80 void accumulateRotation(double cx, double cy, double cz, double lx, double ly, double lz, 
     81                         double &ox, double &oy, double &oz)
     82 {
     83     /*R_wl=[ccy 0 scy;0 1 0;-scy 0 ccy]*[1 0 0;0 ccx -scx;0 scx ccx]*[ccz -scz 0;scz ccz 0;0 0 1];(表示以world为参考坐标系)
     84      *R_cl=[clz -slz 0;slz clz 0;0 0 1]*[1 0 0;0 clx -slx;0 slx clx]*[cly 0 sly;0 1 0;-sly 0 cly];(表示以current为参考坐标系)
     85      *R_wc=R_wl*(R_cl).';
     86      *最后求出来(-sin(rx))=cos(cx)*cos(cz)*sin(lx) - cos(lx)*cos(ly)*sin(cx) - cos(cx)*cos(lx)*sin(cz)*sin(ly)
     87      *而程序中是(-sin(rx))= cos(lx)*cos(cx)*sin(ly)*sin(cz) - cos(cx)*cos(cz)*sin(lx) - cos(lx)*cos(ly)*sin(cx);(程序里的srx=(-sin(rx)))
     88      *可以发现两个公式之间差了lx,ly,lz的负号,所以accumulateRotation()函数传入的是transform[0]~[2]的负值
     89      *至于为什么-sinx等于上式,可以通过看R_wl,发现第二行第三列的元素为-sinx,因此两个旋转矩阵相乘后,对应位置上的元素就对应着新的pitch角的sin 值
     90     */
     91   double srx = cos(lx)*cos(cx)*sin(ly)*sin(cz) - cos(cx)*cos(cz)*sin(lx) - cos(lx)*cos(ly)*sin(cx);
     92   ox = -asin(srx);
     93 
     94   double srycrx = sin(lx)*(cos(cy)*sin(cz) - cos(cz)*sin(cx)*sin(cy)) + cos(lx)*sin(ly)*(cos(cy)*cos(cz) 
     95                 + sin(cx)*sin(cy)*sin(cz)) + cos(lx)*cos(ly)*cos(cx)*sin(cy);
     96   double crycrx = cos(lx)*cos(ly)*cos(cx)*cos(cy) - cos(lx)*sin(ly)*(cos(cz)*sin(cy) 
     97                 - cos(cy)*sin(cx)*sin(cz)) - sin(lx)*(sin(cy)*sin(cz) + cos(cy)*cos(cz)*sin(cx));
     98   oy = atan2(srycrx / cos(ox), crycrx / cos(ox));
     99 
    100   double srzcrx = sin(cx)*(cos(lz)*sin(ly) - cos(ly)*sin(lx)*sin(lz)) + cos(cx)*sin(cz)*(cos(ly)*cos(lz) 
    101                 + sin(lx)*sin(ly)*sin(lz)) + cos(lx)*cos(cx)*cos(cz)*sin(lz);
    102   double crzcrx = cos(lx)*cos(lz)*cos(cx)*cos(cz) - cos(cx)*sin(cz)*(cos(ly)*sin(lz) 
    103                 - cos(lz)*sin(lx)*sin(ly)) - sin(cx)*(sin(ly)*sin(lz) + cos(ly)*cos(lz)*sin(lx));
    104   oz = atan2(srzcrx / cos(ox), crzcrx / cos(ox));
    105 }
    106 
    107 void diffRotation(double cx, double cy, double cz, double lx, double ly, double lz, 
    108                   double &ox, double &oy, double &oz)
    109 {
    110   double srx = cos(cx)*cos(cy)*(sin(ly)*sin(lz) + cos(ly)*cos(lz)*sin(lx)) 
    111              - cos(cx)*sin(cy)*(cos(ly)*sin(lz) - cos(lz)*sin(lx)*sin(ly)) - cos(lx)*cos(lz)*sin(cx);
    112   ox = -asin(srx);
    113 
    114   double srycrx = cos(cx)*sin(cy)*(cos(ly)*cos(lz) + sin(lx)*sin(ly)*sin(lz)) 
    115                 - cos(cx)*cos(cy)*(cos(lz)*sin(ly) - cos(ly)*sin(lx)*sin(lz)) - cos(lx)*sin(cx)*sin(lz);
    116   double crycrx = sin(cx)*sin(lx) + cos(cx)*cos(cy)*cos(lx)*cos(ly) + cos(cx)*cos(lx)*sin(cy)*sin(ly);
    117   oy = atan2(srycrx / cos(ox), crycrx / cos(ox));
    118 
    119   double srzcrx = cos(cx)*cos(lx)*cos(lz)*sin(cz) - (cos(cz)*sin(cy) 
    120                 - cos(cy)*sin(cx)*sin(cz))*(sin(ly)*sin(lz) + cos(ly)*cos(lz)*sin(lx)) 
    121                 - (cos(cy)*cos(cz) + sin(cx)*sin(cy)*sin(cz))*(cos(ly)*sin(lz) - cos(lz)*sin(lx)*sin(ly));
    122   double crzcrx = (sin(cy)*sin(cz) + cos(cy)*cos(cz)*sin(cx))*(sin(ly)*sin(lz) 
    123                 + cos(ly)*cos(lz)*sin(lx)) + (cos(cy)*sin(cz) - cos(cz)*sin(cx)*sin(cy))*(cos(ly)*sin(lz) 
    124                 - cos(lz)*sin(lx)*sin(ly)) + cos(cx)*cos(cz)*cos(lx)*cos(lz);
    125   oz = atan2(srzcrx / cos(ox), crzcrx / cos(ox));
    126 }
    127 
    128 void imagePointsHandler(const sensor_msgs::PointCloud2ConstPtr& imagePoints2)
    129 {
    130   imagePointsLastTime = imagePointsCurTime;
    131   imagePointsCurTime = imagePoints2->header.stamp.toSec();
    132 
    133   imuRollLast = imuRollCur;
    134   imuPitchLast = imuPitchCur;
    135   imuYawLast = imuYawCur;
    136   //transform用于记录帧与帧之间的转移矩阵,transformSum记录当前帧与初始帧的转移矩阵,
    137   double transform[6] = {0};
    138   if (imuPointerLast >= 0) {
    139       //将该帧图像到来之前的所有IMU信息提取出来
    140     while (imuPointerFront != imuPointerLast) {
    141       if (imagePointsCurTime < imuTime[imuPointerFront]) {
    142         break;
    143       }
    144       imuPointerFront = (imuPointerFront + 1) % imuQueLength;
    145     }
    146 
    147     if (imagePointsCurTime > imuTime[imuPointerFront]) {
    148       imuRollCur = imuRoll[imuPointerFront];
    149       imuPitchCur = imuPitch[imuPointerFront];
    150       imuYawCur = imuYaw[imuPointerFront];
    151     } else {
    152       int imuPointerBack = (imuPointerFront + imuQueLength - 1) % imuQueLength;
    153       double ratioFront = (imagePointsCurTime - imuTime[imuPointerBack]) 
    154                         / (imuTime[imuPointerFront] - imuTime[imuPointerBack]);
    155       double ratioBack = (imuTime[imuPointerFront] - imagePointsCurTime) 
    156                        / (imuTime[imuPointerFront] - imuTime[imuPointerBack]);
    157 
    158       //通过插值得到img时刻的roll,pitch,yaw值
    159       imuRollCur = imuRoll[imuPointerFront] * ratioFront + imuRoll[imuPointerBack] * ratioBack;
    160       imuPitchCur = imuPitch[imuPointerFront] * ratioFront + imuPitch[imuPointerBack] * ratioBack;
    161       if (imuYaw[imuPointerFront] - imuYaw[imuPointerBack] > PI) {
    162         imuYawCur = imuYaw[imuPointerFront] * ratioFront + (imuYaw[imuPointerBack] + 2 * PI) * ratioBack;
    163       } else if (imuYaw[imuPointerFront] - imuYaw[imuPointerBack] < -PI) {
    164         imuYawCur = imuYaw[imuPointerFront] * ratioFront + (imuYaw[imuPointerBack] - 2 * PI) * ratioBack;
    165       } else {
    166         imuYawCur = imuYaw[imuPointerFront] * ratioFront + imuYaw[imuPointerBack] * ratioBack;
    167       }
    168     }
    169 
    170     if (imuInited) {
    171       //transform[0] -= imuPitchCur - imuPitchLast;
    172       //transform[1] -= imuYawCur - imuYawLast;
    173       //transform[2] -= imuRollCur - imuRollLast;
    174     }
    175   }
    176 
    177   pcl::PointCloud<ImagePoint>::Ptr imagePointsTemp = imagePointsLast;
    178   imagePointsLast = imagePointsCur;
    179   imagePointsCur = imagePointsTemp;
    180 
    181   imagePointsCur->clear();
    182   pcl::fromROSMsg(*imagePoints2, *imagePointsCur);
    183 
    184   imagePointsLastNum = imagePointsCurNum;
    185   imagePointsCurNum = imagePointsCur->points.size();
    186 
    187   pcl::PointCloud<ImagePoint>::Ptr startPointsTemp = startPointsLast;
    188   startPointsLast = startPointsCur;
    189   startPointsCur = startPointsTemp;
    190 
    191   pcl::PointCloud<pcl::PointXYZHSV>::Ptr startTransTemp = startTransLast;
    192   startTransLast = startTransCur;
    193   startTransCur = startTransTemp;
    194 
    195   std::vector<float>* ipDepthTemp = ipDepthLast;
    196   ipDepthLast = ipDepthCur;
    197   ipDepthCur = ipDepthTemp;
    198 
    199   int j = 0;
    200   pcl::PointXYZI ips;
    201   pcl::PointXYZHSV ipr;
    202   ipRelations->clear();
    203   ipInd.clear();
    204 
    205   //这里是以imagePointsLast为基准进行查找,有些imagePointsCur中的点不会被查询到
    206   for (int i = 0; i < imagePointsLastNum; i++) {
    207     bool ipFound = false;
    208     //查找是否有匹配到的特征点
    209     for (; j < imagePointsCurNum; j++) {
    210       if (imagePointsCur->points[j].ind == imagePointsLast->points[i].ind) {
    211         ipFound = true;
    212       }
    213       if (imagePointsCur->points[j].ind >= imagePointsLast->points[i].ind) {
    214         break;
    215       }
    216     }
    217 
    218     //如果发现匹配的特征点,尝试获取深度信息
    219     if (ipFound) {
    220       ipr.x = imagePointsLast->points[i].u;
    221       ipr.y = imagePointsLast->points[i].v;
    222       ipr.z = imagePointsCur->points[j].u;
    223       ipr.h = imagePointsCur->points[j].v;
    224 
    225       ips.x = 10 * ipr.x;
    226       ips.y = 10 * ipr.y;
    227       ips.z = 10;
    228       
    229       if (depthCloudNum > 10) {
    230         kdTree->nearestKSearch(ips, 3, pointSearchInd, pointSearchSqrDis);
    231 
    232         double minDepth, maxDepth;
    233         if (pointSearchSqrDis[0] < 0.5 && pointSearchInd.size() == 3) {
    234           pcl::PointXYZI depthPoint = depthCloud->points[pointSearchInd[0]];
    235           double x1 = depthPoint.x * depthPoint.intensity / 10;
    236           double y1 = depthPoint.y * depthPoint.intensity / 10;
    237           double z1 = depthPoint.intensity;
    238           minDepth = z1;
    239           maxDepth = z1;
    240 
    241           depthPoint = depthCloud->points[pointSearchInd[1]];
    242           double x2 = depthPoint.x * depthPoint.intensity / 10;
    243           double y2 = depthPoint.y * depthPoint.intensity / 10;
    244           double z2 = depthPoint.intensity;
    245           minDepth = (z2 < minDepth)? z2 : minDepth;
    246           maxDepth = (z2 > maxDepth)? z2 : maxDepth;
    247 
    248           depthPoint = depthCloud->points[pointSearchInd[2]];
    249           double x3 = depthPoint.x * depthPoint.intensity / 10;
    250           double y3 = depthPoint.y * depthPoint.intensity / 10;
    251           double z3 = depthPoint.intensity;
    252           minDepth = (z3 < minDepth)? z3 : minDepth;
    253           maxDepth = (z3 > maxDepth)? z3 : maxDepth;
    254           //目前只知道该特征点在相机坐标系下的归一化坐标[u,v](即[X/Z,Y/Z,1]),
    255           //通过计算ipr.s获得对应于该特征点的深度值,即系数Z,则Z*u和Z*v就可获得该特征点在相机坐标系下实际的X,Y,Z坐标
    256           double u = ipr.x;
    257           double v = ipr.y;
    258           ipr.s = (x1*y2*z3 - x1*y3*z2 - x2*y1*z3 + x2*y3*z1 + x3*y1*z2 - x3*y2*z1) 
    259                 / (x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2 + u*y1*z2 - u*y2*z1
    260                 - v*x1*z2 + v*x2*z1 - u*y1*z3 + u*y3*z1 + v*x1*z3 - v*x3*z1 + u*y2*z3 
    261                 - u*y3*z2 - v*x2*z3 + v*x3*z2);
    262           ipr.v = 1;
    263 
    264           if (maxDepth - minDepth > 2) {
    265             ipr.s = 0;
    266             ipr.v = 0;
    267           } else if (ipr.s - maxDepth > 0.2) {
    268             ipr.s = maxDepth;
    269           } else if (ipr.s - minDepth < -0.2) {
    270             ipr.s = minDepth;
    271           }
    272         } else {
    273           ipr.s = 0;
    274           ipr.v = 0;
    275         }
    276       } else {
    277         ipr.s = 0;
    278         ipr.v = 0;
    279       }
    280       //如果无法从点云获取深度信息,三角测量?
    281       if (fabs(ipr.v) < 0.5) {
    282         double disX = transformSum[3] - startTransLast->points[i].h;
    283         double disY = transformSum[4] - startTransLast->points[i].s;
    284         double disZ = transformSum[5] - startTransLast->points[i].v;
    285         //若移动距离大于1m
    286         if (sqrt(disX * disX + disY * disY + disZ * disZ) > 1) {
    287 
    288           double u0 = startPointsLast->points[i].u;
    289           double v0 = startPointsLast->points[i].v;
    290           double u1 = ipr.x;
    291           double v1 = ipr.y;
    292 
    293           double srx0 = sin(-startTransLast->points[i].x);
    294           double crx0 = cos(-startTransLast->points[i].x);
    295           double sry0 = sin(-startTransLast->points[i].y);
    296           double cry0 = cos(-startTransLast->points[i].y);
    297           double srz0 = sin(-startTransLast->points[i].z);
    298           double crz0 = cos(-startTransLast->points[i].z);
    299 
    300           double srx1 = sin(-transformSum[0]);
    301           double crx1 = cos(-transformSum[0]);
    302           double sry1 = sin(-transformSum[1]);
    303           double cry1 = cos(-transformSum[1]);
    304           double srz1 = sin(-transformSum[2]);
    305           double crz1 = cos(-transformSum[2]);
    306 
    307           double tx0 = -startTransLast->points[i].h;
    308           double ty0 = -startTransLast->points[i].s;
    309           double tz0 = -startTransLast->points[i].v;
    310 
    311           double tx1 = -transformSum[3];
    312           double ty1 = -transformSum[4];
    313           double tz1 = -transformSum[5];
    314 
    315           double x1 = crz0 * u0 + srz0 * v0;
    316           double y1 = -srz0 * u0 + crz0 * v0;
    317           double z1 = 1;
    318 
    319           double x2 = x1;
    320           double y2 = crx0 * y1 + srx0 * z1;
    321           double z2 = -srx0 * y1 + crx0 * z1;
    322 
    323           double x3 = cry0 * x2 - sry0 * z2;
    324           double y3 = y2;
    325           double z3 = sry0 * x2 + cry0 * z2;
    326 
    327           double x4 = cry1 * x3 + sry1 * z3;
    328           double y4 = y3;
    329           double z4 = -sry1 * x3 + cry1 * z3;
    330 
    331           double x5 = x4;
    332           double y5 = crx1 * y4 - srx1 * z4;
    333           double z5 = srx1 * y4 + crx1 * z4;
    334 
    335           double x6 = crz1 * x5 - srz1 * y5;
    336           double y6 = srz1 * x5 + crz1 * y5;
    337           double z6 = z5;
    338 
    339           u0 = x6 / z6;
    340           v0 = y6 / z6;
    341 
    342           x1 = cry1 * (tx1 - tx0) + sry1 * (tz1 - tz0);
    343           y1 = ty1 - ty0;
    344           z1 = -sry1 * (tx1 - tx0) + cry1 * (tz1 - tz0);
    345 
    346           x2 = x1;
    347           y2 = crx1 * y1 - srx1 * z1;
    348           z2 = srx1 * y1 + crx1 * z1;
    349 
    350           double tx = crz1 * x2 - srz1 * y2;
    351           double ty = srz1 * x2 + crz1 * y2;
    352           double tz = z2;
    353 
    354           double delta = sqrt((v0 - v1) * (v0 - v1) + (u0 - u1) * (u0 - u1))
    355                        * cos(atan2(tz * v1 - ty, tz * u1 - tx) - atan2(v0 - v1, u0 - u1));
    356           double depth = sqrt((tz * u0 - tx) * (tz * u0 - tx) + (tz * v0 - ty) * (tz * v0 - ty)) / delta;
    357 
    358           if (depth > 0.5 && depth < 100) {
    359             ipr.s = depth;
    360             ipr.v = 2;
    361           }
    362         }
    363 
    364         //每一个匹配上的特征点对都会被打上一个ipr.v标签,ipr.v=0代表未从点云获得深度,ipr.v=1
    365         //代表从点云获得深度,ipr.v=2代表此时可以通过三角测量获得该特征点的深度值。
    366         /*
    367          *ipDepthLast)[i]存储的是第i个特征点的三角测量值,若该特征点从未被三角测量过,
    368          *ipDepthLast)[i]=-1;若该特征点在一段时间内能一直被观测到,且没有从点云中获得
    369          *深度信息,则不断通过三角测量的融合收敛该特征点的深度值;若在这个过程中某几帧中能从
    370          *点云获得该特征点的深度,则使用点云的深度信息,三角测量的结果仍通过计算出的转移矩阵
    371          *进行维护,仍然存储在*ipDepthLast)[i]中,一旦无法从点云获得深度,则仍使用
    372          *ipDepthLast)[i]中保存的三角测量进行融合
    373          */
    374         if (ipr.v == 2) {
    375           if ((*ipDepthLast)[i] > 0) {
    376               //这一步进行的是多次三角测量的融合,低通滤波
    377             ipr.s = 3 * ipr.s * (*ipDepthLast)[i] / (ipr.s + 2 * (*ipDepthLast)[i]);
    378           }
    379           (*ipDepthLast)[i] = ipr.s;
    380         } else if ((*ipDepthLast)[i] > 0) {
    381           ipr.s = (*ipDepthLast)[i];
    382           ipr.v = 2;
    383         }
    384       }
    385 
    386       ipRelations->push_back(ipr);
    387       ipInd.push_back(imagePointsLast->points[i].ind);
    388     }
    389   }
    390 
    391   //迭代收敛获得两帧图像间的转移矩阵
    392   int iterNum = 100;
    393   pcl::PointXYZHSV ipr2, ipr3, ipr4;
    394   int ipRelationsNum = ipRelations->points.size();
    395   int ptNumNoDepthRec = 0;
    396   int ptNumWithDepthRec = 0;
    397   double meanValueWithDepthRec = 100000;
    398   for (int iterCount = 0; iterCount < iterNum; iterCount++) {
    399     ipRelations2->clear();
    400     ipy2.clear();
    401     int ptNumNoDepth = 0;
    402     int ptNumWithDepth = 0;
    403     double meanValueNoDepth = 0;
    404     double meanValueWithDepth = 0;
    405     for (int i = 0; i < ipRelationsNum; i++) {
    406       ipr = ipRelations->points[i];
    407 
    408       double u0 = ipr.x;
    409       double v0 = ipr.y;
    410       double u1 = ipr.z;
    411       double v1 = ipr.h;
    412 
    413       double srx = sin(transform[0]);
    414       double crx = cos(transform[0]);
    415       double sry = sin(transform[1]);
    416       double cry = cos(transform[1]);
    417       double srz = sin(transform[2]);
    418       double crz = cos(transform[2]);
    419       double tx = transform[3];
    420       double ty = transform[4];
    421       double tz = transform[5];
    422 
    423       if (fabs(ipr.v) < 0.5) {
    424     /*
    425      * 这里R矩阵使用欧拉角roll,pitch yaw来表示的,下面六个公式是论文公式(6)在对roll,pitch,yaw和tx,ty,tz求偏导
    426      *transform[0]存储的是绕x轴旋转的角度,transform[1]存绕y轴角度,transform[2]存绕z轴角度
    427      *这里计算的R、T矩阵是k-1时刻旋转到k时刻的R、T矩阵,注意这个主次关系,参考坐标系是current,即k时刻坐标系
    428      *从k-1旋转到k的顺序是:z轴->x轴->y轴,注意顺序
    429      *R_cl=[crz -srz 0;srz crz 0;0 0 1]*[1 0 0;0 crx -srx;0 srx crx]*[cry 0 sry;0 1 0;-sry 0 cry];
    430     */
    431         ipr2.x = v0*(crz*srx*(tx - tz*u1) - crx*(ty*u1 - tx*v1) + srz*srx*(ty - tz*v1)) 
    432                - u0*(sry*srx*(ty*u1 - tx*v1) + crz*sry*crx*(tx - tz*u1) + sry*srz*crx*(ty - tz*v1)) 
    433                + cry*srx*(ty*u1 - tx*v1) + cry*crz*crx*(tx - tz*u1) + cry*srz*crx*(ty - tz*v1);
    434 
    435         ipr2.y = u0*((tx - tz*u1)*(srz*sry - crz*srx*cry) - (ty - tz*v1)*(crz*sry + srx*srz*cry) 
    436                + crx*cry*(ty*u1 - tx*v1)) - (tx - tz*u1)*(srz*cry + crz*srx*sry) 
    437                + (ty - tz*v1)*(crz*cry - srx*srz*sry) + crx*sry*(ty*u1 - tx*v1);
    438 
    439         ipr2.z = -u0*((tx - tz*u1)*(cry*crz - srx*sry*srz) + (ty - tz*v1)*(cry*srz + srx*sry*crz)) 
    440                - (tx - tz*u1)*(sry*crz + cry*srx*srz) - (ty - tz*v1)*(sry*srz - cry*srx*crz) 
    441                - v0*(crx*crz*(ty - tz*v1) - crx*srz*(tx - tz*u1));
    442 
    443         ipr2.h = cry*crz*srx - v0*(crx*crz - srx*v1) - u0*(cry*srz + crz*srx*sry + crx*sry*v1) 
    444                - sry*srz + crx*cry*v1;
    445 
    446         ipr2.s = crz*sry - v0*(crx*srz + srx*u1) + u0*(cry*crz + crx*sry*u1 - srx*sry*srz) 
    447                - crx*cry*u1 + cry*srx*srz;
    448 
    449         ipr2.v = u1*(sry*srz - cry*crz*srx) - v1*(crz*sry + cry*srx*srz) + u0*(u1*(cry*srz + crz*srx*sry) 
    450                - v1*(cry*crz - srx*sry*srz)) + v0*(crx*crz*u1 + crx*srz*v1);
    451     //将六个变量值代入论文(公式6)计算得到残差值
    452         double y2 = (ty - tz*v1)*(crz*sry + cry*srx*srz) - (tx - tz*u1)*(sry*srz - cry*crz*srx) 
    453                   - v0*(srx*(ty*u1 - tx*v1) + crx*crz*(tx - tz*u1) + crx*srz*(ty - tz*v1)) 
    454                   + u0*((ty - tz*v1)*(cry*crz - srx*sry*srz) - (tx - tz*u1)*(cry*srz + crz*srx*sry) 
    455                   + crx*sry*(ty*u1 - tx*v1)) - crx*cry*(ty*u1 - tx*v1);
    456 
    457         if (ptNumNoDepthRec < 50 || iterCount < 25 || fabs(y2) < 2 * meanValueWithDepthRec / 10000) {
    458           double scale = 100;
    459           ipr2.x *= scale;
    460           ipr2.y *= scale;
    461           ipr2.z *= scale;
    462           ipr2.h *= scale;
    463           ipr2.s *= scale;
    464           ipr2.v *= scale;
    465           y2 *= scale;
    466 
    467           ipRelations2->push_back(ipr2);
    468           ipy2.push_back(y2);
    469 
    470           ptNumNoDepth++;
    471         } else {
    472           ipRelations->points[i].v = -1;
    473         }
    474       } else if (fabs(ipr.v - 1) < 0.5 || fabs(ipr.v - 2) < 0.5) {
    475 
    476         double d0 = ipr.s;
    477 
    478         ipr3.x = d0*(cry*srz*crx + cry*u1*srx) - d0*u0*(sry*srz*crx + sry*u1*srx) 
    479                - d0*v0*(u1*crx - srz*srx);
    480 
    481         ipr3.y = d0*(crz*cry + crx*u1*sry - srx*srz*sry) - d0*u0*(crz*sry - crx*u1*cry + srx*srz*cry);
    482 
    483         ipr3.z = -d0*(sry*srz - cry*srx*crz) - d0*u0*(cry*srz + srx*sry*crz) - crx*d0*v0*crz;
    484 
    485         ipr3.h = 1;
    486 
    487         ipr3.s = 0;
    488 
    489         ipr3.v = -u1;
    490 
    491         double y3 = tx - tz*u1 + d0*(crz*sry - crx*cry*u1 + cry*srx*srz) - d0*v0*(crx*srz + srx*u1) 
    492                   + d0*u0*(cry*crz + crx*sry*u1 - srx*sry*srz);
    493 
    494         ipr4.x = d0*(cry*v1*srx - cry*crz*crx) + d0*u0*(crz*sry*crx - sry*v1*srx) 
    495                - d0*v0*(crz*srx + v1*crx);
    496 
    497         ipr4.y = d0*(srz*cry + crz*srx*sry + crx*v1*sry) + d0*u0*(crz*srx*cry - srz*sry + crx*v1*cry);
    498 
    499         ipr4.z = d0*(sry*crz + cry*srx*srz) + d0*u0*(cry*crz - srx*sry*srz) - crx*d0*v0*srz;
    500 
    501         ipr4.h = 0;
    502 
    503         ipr4.s = 1;
    504 
    505         ipr4.v = -v1;
    506 
    507         double y4 = ty - tz*v1 - d0*(cry*crz*srx - sry*srz + crx*cry*v1) + d0*v0*(crx*crz - srx*v1) 
    508                   + d0*u0*(cry*srz + crz*srx*sry + crx*sry*v1);
    509 
    510         if (ptNumWithDepthRec < 50 || iterCount < 25 || 
    511             sqrt(y3 * y3 + y4 * y4) < 2 * meanValueWithDepthRec) {
    512           ipRelations2->push_back(ipr3);
    513           ipy2.push_back(y3);
    514 
    515           ipRelations2->push_back(ipr4);
    516           ipy2.push_back(y4);
    517 
    518           ptNumWithDepth++;
    519           meanValueWithDepth += sqrt(y3 * y3 + y4 * y4);
    520         } else {
    521           ipRelations->points[i].v = -1;
    522         }
    523       }
    524     }
    525     //加 0.01 是为了防止 ptNumWithDepth 为 0
    526     meanValueWithDepth /= (ptNumWithDepth + 0.01);
    527     ptNumNoDepthRec = ptNumNoDepth;
    528     ptNumWithDepthRec = ptNumWithDepth;
    529     meanValueWithDepthRec = meanValueWithDepth;
    530 
    531     int ipRelations2Num = ipRelations2->points.size();
    532     if (ipRelations2Num > 10) {
    533       cv::Mat matA(ipRelations2Num, 6, CV_32F, cv::Scalar::all(0));
    534       cv::Mat matAt(6, ipRelations2Num, CV_32F, cv::Scalar::all(0));
    535       cv::Mat matAtA(6, 6, CV_32F, cv::Scalar::all(0));
    536       cv::Mat matB(ipRelations2Num, 1, CV_32F, cv::Scalar::all(0));
    537       cv::Mat matAtB(6, 1, CV_32F, cv::Scalar::all(0));
    538       cv::Mat matX(6, 1, CV_32F, cv::Scalar::all(0));
    539 
    540       for (int i = 0; i < ipRelations2Num; i++) {
    541         ipr2 = ipRelations2->points[i];
    542 
    543         matA.at<float>(i, 0) = ipr2.x;
    544         matA.at<float>(i, 1) = ipr2.y;
    545         matA.at<float>(i, 2) = ipr2.z;
    546         matA.at<float>(i, 3) = ipr2.h;
    547         matA.at<float>(i, 4) = ipr2.s;
    548         matA.at<float>(i, 5) = ipr2.v;
    549         matB.at<float>(i, 0) = -0.2 * ipy2[i];
    550       }
    551       cv::transpose(matA, matAt);
    552       matAtA = matAt * matA;
    553       matAtB = matAt * matB;
    554       //根据《14讲》式(6.21),这里用的是高斯牛顿法而不是LM算法
    555       cv::solve(matAtA, matAtB, matX, cv::DECOMP_QR);
    556 
    557       //if (fabs(matX.at<float>(0, 0)) < 0.1 && fabs(matX.at<float>(1, 0)) < 0.1 && 
    558       //    fabs(matX.at<float>(2, 0)) < 0.1) {
    559         transform[0] += matX.at<float>(0, 0);
    560         transform[1] += matX.at<float>(1, 0);
    561         transform[2] += matX.at<float>(2, 0);
    562         transform[3] += matX.at<float>(3, 0);
    563         transform[4] += matX.at<float>(4, 0);
    564         transform[5] += matX.at<float>(5, 0);
    565       //}
    566 
    567       float deltaR = sqrt(matX.at<float>(0, 0) * 180 / PI * matX.at<float>(0, 0) * 180 / PI
    568                    + matX.at<float>(1, 0) * 180 / PI * matX.at<float>(1, 0) * 180 / PI
    569                    + matX.at<float>(2, 0) * 180 / PI * matX.at<float>(2, 0) * 180 / PI);
    570       float deltaT = sqrt(matX.at<float>(3, 0) * 100 * matX.at<float>(3, 0) * 100
    571                    + matX.at<float>(4, 0) * 100 * matX.at<float>(4, 0) * 100
    572                    + matX.at<float>(5, 0) * 100 * matX.at<float>(5, 0) * 100);
    573 
    574       if (deltaR < 0.00001 && deltaT < 0.00001) {
    575         break;
    576       }
    577 
    578       //ROS_INFO ("iter: %d, deltaR: %f, deltaT: %f", iterCount, deltaR, deltaT);
    579     }
    580   }
    581 
    582   if (!imuInited) {
    583     imuYawInit = imuYawCur;
    584     transform[0] -= imuPitchCur;
    585     transform[2] -= imuRollCur;
    586 
    587     imuInited = true;
    588   }
    589 
    590   //rx,ry,rz表示当前帧与初始帧的pitch,yaw,roll角度
    591   double rx, ry, rz;
    592   accumulateRotation(transformSum[0], transformSum[1], transformSum[2], 
    593                     -transform[0], -transform[1], -transform[2], rx, ry, rz);
    594 
    595   if (imuPointerLast >= 0) {
    596     double drx, dry, drz;
    597     diffRotation(imuPitchCur, imuYawCur - imuYawInit, imuRollCur, rx, ry, rz, drx, dry, drz);
    598 
    599     transform[0] -= 0.1 * drx;
    600     /*if (dry > PI) {
    601       transform[1] -= 0.1 * (dry - 2 * PI);
    602     } else if (imuYawCur - imuYawInit - ry < -PI) {
    603       transform[1] -= 0.1 * (dry + 2 * PI);
    604     } else {
    605       transform[1] -= 0.1 * dry;
    606     }*/
    607     transform[2] -= 0.1 * drz;
    608 
    609     accumulateRotation(transformSum[0], transformSum[1], transformSum[2], 
    610                       -transform[0], -transform[1], -transform[2], rx, ry, rz);
    611   }
    612 
    613   double x1 = cos(rz) * transform[3] - sin(rz) * transform[4];
    614   double y1 = sin(rz) * transform[3] + cos(rz) * transform[4];
    615   double z1 = transform[5];
    616 
    617   double x2 = x1;
    618   double y2 = cos(rx) * y1 - sin(rx) * z1;
    619   double z2 = sin(rx) * y1 + cos(rx) * z1;
    620 
    621   //当前帧与上一帧的位移量通过rx,ry,rz的旋转,计算当前帧和初始帧的位移增量,叠加到transformSum[]中
    622   //该增量计算得到的是last帧相对于current帧在世界坐标系下的位移,所以current相对于Last在世界坐标系下的位移为负值,所以是减去
    623   double tx = transformSum[3] - (cos(ry) * x2 + sin(ry) * z2);
    624   double ty = transformSum[4] - y2;
    625   double tz = transformSum[5] - (-sin(ry) * x2 + cos(ry) * z2);
    626   //当前帧与初始帧的转移矩阵保存在transformSum中,transformSum中存的是将当前帧旋转到起始帧的旋转矩阵
    627   transformSum[0] = rx;
    628   transformSum[1] = ry;
    629   transformSum[2] = rz;
    630   transformSum[3] = tx;
    631   transformSum[4] = ty;
    632   transformSum[5] = tz;
    633 
    634   pcl::PointXYZHSV spc;
    635   spc.x = transformSum[0];
    636   spc.y = transformSum[1];
    637   spc.z = transformSum[2];
    638   spc.h = transformSum[3];
    639   spc.s = transformSum[4];
    640   spc.v = transformSum[5];
    641 
    642   double crx = cos(transform[0]);
    643   double srx = sin(transform[0]);
    644   double cry = cos(transform[1]);
    645   double sry = sin(transform[1]);
    646 
    647   j = 0;
    648   //这里是以imagePointsCur为基准进行查找,会遍历imagePointsCur中的每一个点
    649   for (int i = 0; i < imagePointsCurNum; i++) {
    650     bool ipFound = false;
    651     for (; j < imagePointsLastNum; j++) {
    652       if (imagePointsLast->points[j].ind == imagePointsCur->points[i].ind) {
    653         ipFound = true;
    654       }
    655       if (imagePointsLast->points[j].ind >= imagePointsCur->points[i].ind) {
    656         break;
    657       }
    658     }
    659 
    660     if (ipFound) {
    661       /*
    662         *如果在连续的多帧特征图像之间,imagePointsCur中的某个特征点能够与上一帧
    663         *imagePointsLast匹配到,代表该特征点能够被连续观测到,则将该特征点第一次出现在这些连续帧
    664         *的坐标以及该坐标相对于初始帧的转移矩阵保存在startPointsCur中,用作三角测量时的第一帧
    665         *特征点;若该特征点一旦与前一帧匹配失败,就表示该特征点为一系列特征点帧中的一个新出现的
    666         *特征点,则将该特征点当前的坐标与转移矩阵保存在startPointsCur,认为它第一次出现,并在后续帧中
    667         *若能一直观测到该特征点,startPointsCur中仍保存第一次出现的坐标与转移矩阵
    668        */
    669       startPointsCur->push_back(startPointsLast->points[j]);
    670       startTransCur->push_back(startTransLast->points[j]);
    671 
    672       if ((*ipDepthLast)[j] > 0) {
    673       /*
    674       *transform[]里存的就是T_cl,所以将Last坐标系的点按照zxy(从右往左看)的顺序旋转,再加上位移就变换到了current坐标系
    675       *而R_lc就是把transform[0]~transform[2]的pitch,yaw,roll角取负值然后按照yxz(从右往左看)的顺序变换就可得到
    676       *这里有一点注意的是,将transform[0]~[2]按照yxz相乘得到的R_lc和直接将R_cl取转置得到的R_lc差了三个角度的负值
    677       *所以通过旋转相乘得到R_lc时transform[0]~[2]要先取负值
    678       */
    679         double ipz = (*ipDepthLast)[j];
    680         double ipx = imagePointsLast->points[j].u * ipz;
    681         double ipy = imagePointsLast->points[j].v * ipz;
    682 
    683         x1 = cry * ipx + sry * ipz;
    684         y1 = ipy;
    685         z1 = -sry * ipx + cry * ipz;
    686 
    687         x2 = x1;
    688         y2 = crx * y1 - srx * z1;
    689         z2 = srx * y1 + crx * z1;
    690 
    691         ipDepthCur->push_back(z2 + transform[5]);
    692       } else {
    693         ipDepthCur->push_back(-1);
    694       }
    695     } else {
    696       startPointsCur->push_back(imagePointsCur->points[i]);
    697       startTransCur->push_back(spc);
    698       ipDepthCur->push_back(-1);
    699     }
    700   }
    701   startPointsLast->clear();
    702   startTransLast->clear();
    703   ipDepthLast->clear();
    704 
    705   angleSum[0] -= transform[0];
    706   angleSum[1] -= transform[1];
    707   angleSum[2] -= transform[2];
    708 
    709   /* rz,rx,ry分别对应着标准右手坐标系中的roll,pitch,yaw角,通过查看createQuaternionMsgFromRollPitchYaw()的函数定义可以发现.
    710    * 当pitch和yaw角给负值后,四元数中的y和z会变成负值,x和w不受影响.由四元数定义可以知道,x,y,z是指旋转轴在三个轴上的投影,w影响
    711    * 旋转角度,所以由createQuaternionMsgFromRollPitchYaw()计算得到四元数后,其在一般右手坐标系中的x,y,z分量对应到该应用场景下
    712    * 的坐标系中,geoQuat.x对应实际坐标系下的z轴分量,geoQuat.y对应x轴分量,geoQuat.z对应实际的y轴分量,而由于rx和ry在计算四元数
    713    * 时给的是负值,所以geoQuat.y和geoQuat.z取负值,这样就等于没变
    714   */
    715 
    716   geometry_msgs::Quaternion geoQuat = tf::createQuaternionMsgFromRollPitchYaw(rz, -rx, -ry);
    717   //geometry_msgs::Quaternion geoQuat = tf::createQuaternionMsgFromRollPitchYaw(rz, rx, ry);
    718 
    719   nav_msgs::Odometry voData;
    720   voData.header.frame_id = "/camera_init";
    721   voData.child_frame_id = "/camera";
    722   voData.header.stamp = imagePoints2->header.stamp;
    723   voData.pose.pose.orientation.x = -geoQuat.y;
    724   voData.pose.pose.orientation.y = -geoQuat.z;
    725   //voData.pose.pose.orientation.x = geoQuat.y;
    726   //voData.pose.pose.orientation.y = geoQuat.z;
    727   voData.pose.pose.orientation.z = geoQuat.x;
    728   voData.pose.pose.orientation.w = geoQuat.w;
    729   voData.pose.pose.position.x = tx;
    730   voData.pose.pose.position.y = ty;
    731   voData.pose.pose.position.z = tz;
    732   voData.twist.twist.angular.x = angleSum[0];
    733   voData.twist.twist.angular.y = angleSum[1];
    734   voData.twist.twist.angular.z = angleSum[2];
    735   voDataPubPointer->publish(voData);
    736 
    737   tf::StampedTransform voTrans;
    738   voTrans.frame_id_ = "/camera_init";
    739   voTrans.child_frame_id_ = "/camera";
    740   voTrans.stamp_ = imagePoints2->header.stamp;
    741   voTrans.setRotation(tf::Quaternion(-geoQuat.y, -geoQuat.z, geoQuat.x, geoQuat.w));
    742   //voTrans.setRotation(tf::Quaternion(geoQuat.y, geoQuat.z, geoQuat.x, geoQuat.w));
    743   voTrans.setOrigin(tf::Vector3(tx, ty, tz));
    744   tfBroadcasterPointer->sendTransform(voTrans);
    745 
    746   pcl::PointCloud<DepthPoint>::Ptr depthPointsTemp = depthPointsLast;
    747   depthPointsLast = depthPointsCur;
    748   depthPointsCur = depthPointsTemp;
    749 
    750   DepthPoint ipd;
    751   depthPointsCur->clear();
    752 
    753   ipd.u = transformSum[0];
    754   ipd.v = transformSum[1];
    755   ipd.depth = transformSum[2];
    756   ipd.ind = -2;
    757   depthPointsCur->push_back(ipd);
    758 
    759   ipd.u = transformSum[3];
    760   ipd.v = transformSum[4];
    761   ipd.depth = transformSum[5];
    762   ipd.ind = -1;
    763   depthPointsCur->push_back(ipd);
    764 
    765   depthPointsLastNum = depthPointsCurNum;
    766   depthPointsCurNum = 2;
    767 
    768   j = 0;
    769   pcl::PointXYZ ipp;
    770   depthPointsSend->clear();
    771   imagePointsProj->clear();
    772   for (int i = 0; i < ipRelationsNum; i++) {
    773     if (fabs(ipRelations->points[i].v - 1) < 0.5 || fabs(ipRelations->points[i].v - 2) < 0.5) {
    774 
    775       ipd.u = ipRelations->points[i].z;
    776       ipd.v = ipRelations->points[i].h;
    777       //这一步是对标号为ind的特征点深度进行的一个粗略估计,后面如果该特征点可以直接从点云或者三角测量获得深度值,
    778       //则这个估计值失效,如果后面不能得到该特征深度值,则仍使用该估计值
    779       ////////////////////////////////////////////////////////////////////
    780       /*double ipz = ipRelations->points[i].s;
    781       double ipx = ipRelations->points[i].x * ipz;
    782       double ipy = ipRelations->points[i].y * ipz;
    783 
    784       double x1 = cry * ipx + sry * ipz;
    785       double y1 = ipy;
    786       double z1 = -sry * ipx + cry * ipz;
    787 
    788       double x2 = x1;
    789       double y2 = crx * y1 - srx * z1;
    790       double z2 = srx * y1 + crx * z1;
    791       ipd.depth = z2 + transform[5];
    792       */
    793       ////////////////////////////////////////////////////////////////////
    794 
    795       ipd.depth = ipRelations->points[i].s + transform[5];
    796       ipd.label = ipRelations->points[i].v;
    797       ipd.ind = ipInd[i];
    798 
    799       depthPointsCur->push_back(ipd);
    800       depthPointsCurNum++;
    801 
    802       for (; j < depthPointsLastNum; j++) {
    803         if (depthPointsLast->points[j].ind < ipInd[i]) {
    804           depthPointsSend->push_back(depthPointsLast->points[j]);
    805         } else if (depthPointsLast->points[j].ind > ipInd[i]) {
    806           break;
    807         }
    808       }
    809 
    810       ipd.u = ipRelations->points[i].x;
    811       ipd.v = ipRelations->points[i].y;
    812       ipd.depth = ipRelations->points[i].s;
    813 
    814       //现在有Last帧和Cur帧,depthPointsSend中存储的是对Last帧中特征点深度的估计和确切计算到的深度
    815       depthPointsSend->push_back(ipd);
    816 
    817       ipp.x = ipRelations->points[i].x * ipRelations->points[i].s;
    818       ipp.y = ipRelations->points[i].y * ipRelations->points[i].s;
    819       ipp.z = ipRelations->points[i].s;
    820 
    821       imagePointsProj->push_back(ipp);
    822     }
    823   }
    824 
    825   sensor_msgs::PointCloud2 depthPoints2;
    826   pcl::toROSMsg(*depthPointsSend, depthPoints2);
    827   depthPoints2.header.frame_id = "camera2";
    828   depthPoints2.header.stamp = ros::Time().fromSec(imagePointsLastTime);
    829   depthPointsPubPointer->publish(depthPoints2);
    830 
    831   sensor_msgs::PointCloud2 imagePointsProj2;
    832   pcl::toROSMsg(*imagePointsProj, imagePointsProj2);
    833   imagePointsProj2.header.frame_id = "camera2";
    834   imagePointsProj2.header.stamp = ros::Time().fromSec(imagePointsLastTime);
    835   imagePointsProjPubPointer->publish(imagePointsProj2);
    836 }
    837 
    838 void depthCloudHandler(const sensor_msgs::PointCloud2ConstPtr& depthCloud2)
    839 {
    840   depthCloudTime = depthCloud2->header.stamp.toSec();
    841 
    842   depthCloud->clear();
    843   pcl::fromROSMsg(*depthCloud2, *depthCloud);
    844   depthCloudNum = depthCloud->points.size();
    845   //将整个点云投影到焦距为单位距离=10的平面上
    846   if (depthCloudNum > 10) {
    847     for (int i = 0; i < depthCloudNum; i++) {
    848       depthCloud->points[i].intensity = depthCloud->points[i].z;
    849       depthCloud->points[i].x *= 10 / depthCloud->points[i].z;
    850       depthCloud->points[i].y *= 10 / depthCloud->points[i].z;
    851       depthCloud->points[i].z = 10;
    852     }
    853 
    854     kdTree->setInputCloud(depthCloud);
    855   }
    856 }
    857 
    858 void imuDataHandler(const sensor_msgs::Imu::ConstPtr& imuData)
    859 {
    860   double roll, pitch, yaw;
    861   tf::Quaternion orientation;
    862   tf::quaternionMsgToTF(imuData->orientation, orientation);
    863   tf::Matrix3x3(orientation).getRPY(roll, pitch, yaw);
    864 
    865   imuPointerLast = (imuPointerLast + 1) % imuQueLength;
    866 
    867   imuTime[imuPointerLast] = imuData->header.stamp.toSec() - 0.1068;
    868   imuRoll[imuPointerLast] = roll;
    869   imuPitch[imuPointerLast] = pitch;
    870   imuYaw[imuPointerLast] = yaw;
    871 }
    872 
    873 void imageDataHandler(const sensor_msgs::Image::ConstPtr& imageData) 
    874 {
    875   cv_bridge::CvImagePtr bridge = cv_bridge::toCvCopy(imageData, "bgr8");
    876 
    877   int ipRelationsNum = ipRelations->points.size();
    878   for (int i = 0; i < ipRelationsNum; i++) {
    879     if (fabs(ipRelations->points[i].v) < 0.5) {
    880         //这里运用《14讲》公式5.5将归一化坐标平面上的点变换到图像平面,这里的相减是因为在featureTrack部分将图像坐标
    881         //变到归一化图像平面时加了个负号,又考虑到显示的图像是缩小一倍后的,所以要再除以showDSRate
    882       cv::circle(bridge->image, cv::Point((kImage[2] - ipRelations->points[i].z * kImage[0]) / showDSRate,
    883                 (kImage[5] - ipRelations->points[i].h * kImage[4]) / showDSRate), 1, CV_RGB(255, 0, 0), 2);
    884     } else if (fabs(ipRelations->points[i].v - 1) < 0.5) {
    885       cv::circle(bridge->image, cv::Point((kImage[2] - ipRelations->points[i].z * kImage[0]) / showDSRate,
    886                 (kImage[5] - ipRelations->points[i].h * kImage[4]) / showDSRate), 1, CV_RGB(0, 255, 0), 2);
    887     } else if (fabs(ipRelations->points[i].v - 2) < 0.5) {
    888       cv::circle(bridge->image, cv::Point((kImage[2] - ipRelations->points[i].z * kImage[0]) / showDSRate,
    889                 (kImage[5] - ipRelations->points[i].h * kImage[4]) / showDSRate), 1, CV_RGB(0, 0, 255), 2);
    890     } /*else {
    891       cv::circle(bridge->image, cv::Point((kImage[2] - ipRelations->points[i].z * kImage[0]) / showDSRate,
    892                 (kImage[5] - ipRelations->points[i].h * kImage[4]) / showDSRate), 1, CV_RGB(0, 0, 0), 2);
    893     }*/
    894   }
    895 
    896   sensor_msgs::Image::Ptr imagePointer = bridge->toImageMsg();
    897   imageShowPubPointer->publish(imagePointer);
    898 }
    899 
    900 int main(int argc, char** argv)
    901 {
    902   ros::init(argc, argv, "visualOdometry");
    903   ros::NodeHandle nh;
    904 
    905   ros::Subscriber imagePointsSub = nh.subscribe<sensor_msgs::PointCloud2>
    906                                    ("/image_points_last", 5, imagePointsHandler);
    907 
    908   ros::Subscriber depthCloudSub = nh.subscribe<sensor_msgs::PointCloud2> 
    909                                   ("/depth_cloud", 5, depthCloudHandler);
    910 
    911   /*
    912    * whether you need IMU information
    913   */
    914   //ros::Subscriber imuDataSub = nh.subscribe<sensor_msgs::Imu> ("/imu/data", 5, imuDataHandler);
    915 
    916   ros::Publisher voDataPub = nh.advertise<nav_msgs::Odometry> ("/cam_to_init", 5);
    917   voDataPubPointer = &voDataPub;
    918 
    919   tf::TransformBroadcaster tfBroadcaster;
    920   tfBroadcasterPointer = &tfBroadcaster;
    921 
    922   ros::Publisher depthPointsPub = nh.advertise<sensor_msgs::PointCloud2> ("/depth_points_last", 5);
    923   depthPointsPubPointer = &depthPointsPub;
    924 
    925   ros::Publisher imagePointsProjPub = nh.advertise<sensor_msgs::PointCloud2> ("/image_points_proj", 1);
    926   imagePointsProjPubPointer = &imagePointsProjPub;
    927 
    928   ros::Subscriber imageDataSub = nh.subscribe<sensor_msgs::Image>("/image/show", 1, imageDataHandler);
    929 
    930   ros::Publisher imageShowPub = nh.advertise<sensor_msgs::Image>("/image/show_2", 1);
    931   imageShowPubPointer = &imageShowPub;
    932 
    933   ros::spin();
    934 
    935   return 0;
    936 }
  • 相关阅读:
    神秘现象?多种情况比较
    [备忘]C++BUILDER的文件操作
    缘起
    [备忘]一个二维数组的冒泡排序
    无可救药地买入NDSL
    递归的实质
    [网游计划第九、十天]能力有限,做些小品
    大学有救
    struts2+convertion实现struts.xml的零配置
    BSD下的超级终端
  • 原文地址:https://www.cnblogs.com/zhchp-blog/p/8735184.html
Copyright © 2011-2022 走看看