stereodom.hpp
Go to the documentation of this file.
00001 
00037 #ifndef __STEREODOM_H__
00038 #define __STEREODOM_H__
00039 
00040 #include <ros/ros.h>
00041 #include <opencv2/opencv.hpp>
00042 #include <tf/tf.h>
00043 #include <sensor_msgs/CameraInfo.h>
00044 #include <sensor_msgs/Image.h>
00045 #include <message_filters/subscriber.h>
00046 #include <message_filters/time_synchronizer.h>
00047 #include <sensor_msgs/PointCloud.h>
00048 #include <sensor_msgs/PointCloud2.h>
00049 #include <sensor_msgs/point_cloud_conversion.h>
00050 #include <image_transport/image_transport.h>
00051 #include <image_transport/subscriber_filter.h>
00052 #include <tf/transform_broadcaster.h>
00053 #include <cv_bridge/cv_bridge.h>
00054 
00055 // Dynamic Reconfigure Parameters
00056 #include <dynamic_reconfigure/server.h>
00057 #include <viodom/stereodomConfig.h>
00058 
00059 #include "imufilter.hpp"
00060 #include "robustmatcher.hpp"
00061 
00069 bool score_comparator(const cv::KeyPoint& p1, const cv::KeyPoint& p2)
00070 {
00071     return p1.response > p2.response;
00072 }
00073 
00078 class Stereodom
00079 {
00080 public:
00087     Stereodom(std::string &nodeName, std::string &leftCam, std::string &rightCam, std::string &imuTopic):
00088         imu_(0.005, imuTopic, 3.0),
00089         it_(nh_),
00090         leftImgSubs_(it_, leftCam + "/image_raw", 1),
00091         leftInfoSubs_(nh_, leftCam + "/camera_info", 1),
00092         rightImgSubs_(it_, rightCam + "/image_raw", 1),
00093         rightInfoSubs_(nh_, rightCam + "/camera_info", 1),
00094         fDetector_(/*5*/),
00095         fExtractor_(16/*32*/),
00096         stereoSync_(leftImgSubs_, rightImgSubs_, 10),
00097         cameraInfoSync_(leftInfoSubs_, rightInfoSubs_, 10)
00098     {
00099         std::cout << "Subscribed to:" << "\n";
00100         std::cout << leftImgSubs_.getTopic() << "\n";
00101         std::cout << rightImgSubs_.getTopic() << "\n";
00102         std::cout << leftInfoSubs_.getTopic() << "\n";
00103         std::cout << rightInfoSubs_.getTopic() << "\n";
00104         std::cout << imuTopic << "\n";
00105 
00106         //cv::namedWindow("viodom");
00107 
00108         // Get node parameters
00109         ros::NodeHandle lnh("~");
00110         if(!lnh.getParam("publish_pc", publishPc_))
00111             publishPc_ = false;
00112         if(!lnh.getParam("max_features", maxFeatures_))
00113             maxFeatures_ = 200;
00114         if(maxFeatures_ < 100)
00115         {
00116             maxFeatures_ = 200;
00117             std::cout << "max_features should be above 100. Setting default value (200)" << std::endl;
00118         }
00119         if(!lnh.getParam("flow_threshold", flowThreshold_))
00120             flowThreshold_ = 5.0;
00121         if(!lnh.getParam("min_matches", minMatches_))
00122             minMatches_ = 15;
00123         if(!lnh.getParam("downsampling", downsampling_))
00124             downsampling_ = 1;
00125         if(!lnh.getParam("src_frame_id", srcFrameId_))
00126             srcFrameId_ = "world";
00127         if(!lnh.getParam("tgt_frame_id", tgtFrameId_))
00128             tgtFrameId_ = "base_link";
00129 
00130         // Dynamic reconfigure callback
00131         Stereodom::dyn_rec_f_ = boost::bind(&Stereodom::dynRecCallback, this, _1, _2);
00132         Stereodom::dyn_rec_server_.setCallback(Stereodom::dyn_rec_f_);
00133 
00134         // Init subscriber synchronizers
00135         stereoSync_.registerCallback(boost::bind(&Stereodom::stereoCallback, this, _1, _2));
00136         cameraInfoSync_.registerCallback(boost::bind(&Stereodom::cameraInfoCallback, this, _1, _2));
00137 
00138         // Init publishers
00139         transformPub_ = nh_.advertise<geometry_msgs::TransformStamped>(nodeName+"/viodom_transform", 1);
00140         if(publishPc_)
00141             pcPub_ = nh_.advertise<sensor_msgs::PointCloud2>(nodeName+"/point_cloud", 1);
00142 
00143         // Init odometry
00144         odomInit_ = false;
00145         calibInit_ = false;
00146         odomC_.setIdentity();
00147         odomCkf_.setIdentity();
00148         odom_.setIdentity();
00149 
00150         // Init cam2baselink TFs
00151         Tcam22imu0_.setOrigin(tf::Vector3(-0.039, 0.0089, 0.0009));
00152         Tcam22imu0_.setRotation(tf::Quaternion(0.00065, 0.0014, -0.0031, 0.9999));
00153         Timu02base_.setOrigin(tf::Vector3(0.12, 0.0, -0.06));
00154         tf::Quaternion q_imu0;
00155         q_imu0.setRPY(-1.96, 0.0, -1.57);
00156         Timu02base_.setRotation(q_imu0);
00157     }
00158 
00160     ~Stereodom(void)
00161     {
00162     }
00163 
00164 private:
00165 
00172     bool convertRectifyImages(const sensor_msgs::ImageConstPtr& leftImg,
00173                               const sensor_msgs::ImageConstPtr& rightImg,
00174                               cv::Mat& imgL, cv::Mat& imgR)
00175     {
00176         // Convert to OpenCV format without copy
00177         cv_bridge::CvImageConstPtr cvbLeft, cvbRight;
00178         try
00179         {
00180             cvbLeft = cv_bridge::toCvShare(leftImg);
00181             cvbRight = cv_bridge::toCvShare(rightImg);
00182         }
00183         catch (cv_bridge::Exception& e)
00184         {
00185             ROS_ERROR("cv_bridge exception: %s", e.what());
00186             return false;
00187         }
00188 
00189         // Rectify both images
00190         cv::remap(cvbLeft->image, imgL, mapL1_, mapL2_, cv::INTER_LINEAR);
00191         cv::remap(cvbRight->image, imgR, mapR1_, mapR2_, cv::INTER_LINEAR);
00192         return true;
00193     }
00194 
00202     void kptsBucketing(std::vector<cv::KeyPoint>& srcKpts, std::vector<cv::KeyPoint>& dstKpts,
00203                        int width, int height)
00204     {
00205         const int maxFeatBuck = maxFeatures_/6;
00206         int buckets[6] = {maxFeatBuck, maxFeatBuck, maxFeatBuck, maxFeatBuck, maxFeatBuck, maxFeatBuck};
00207         for(size_t i=0; i<srcKpts.size(); i++)
00208         {
00209             int id;
00210 
00211             // Check keypoint y coord
00212             if(srcKpts[i].pt.y <= height/2)
00213                 id = 0;
00214             else
00215                 id = 3;
00216 
00217             // Check keypoint x coord
00218             if(srcKpts[i].pt.x <= width/3)
00219                 id += 0;
00220             else if(srcKpts[i].pt.x <= 2*width/3)
00221                 id += 1;
00222             else
00223                 id += 2;
00224 
00225             // Assign to corresponding bucket
00226             if(buckets[id] > 0)
00227             {
00228                 buckets[id]--;
00229                 dstKpts.push_back(srcKpts[i]);
00230             }
00231         }
00232     }
00233 
00242     void selectKeypoints(cv::Mat& imgLeft, cv::Mat& imgRight,
00243                          std::vector<cv::KeyPoint>& keypointsLeft,
00244                          std::vector<cv::KeyPoint>& keypointsRight)
00245     {
00246         // Detect key-points in both images
00247         std::vector<cv::KeyPoint> kptsL, kptsR;
00248         fDetector_.detect(imgLeft, kptsL);
00249         fDetector_.detect(imgRight, kptsR);
00250 
00251         // Sort keypoints according to their score
00252         std::sort(kptsL.begin(), kptsL.end(), score_comparator);
00253         std::sort(kptsR.begin(), kptsR.end(), score_comparator);
00254 
00255         // Distribute maxFeatures_ in buckets
00256         const int width = imgLeft.cols;
00257         const int height = imgLeft.rows;
00258         kptsBucketing(kptsL, keypointsLeft, width, height);
00259         kptsBucketing(kptsR, keypointsRight, width, height);
00260     }
00261 
00270     void extractDescriptors(cv::Mat& imgL, cv::Mat& imgR,
00271                             std::vector<cv::KeyPoint>& keypointsLeft,
00272                             std::vector<cv::KeyPoint>& keypointsRight,
00273                             cv::Mat& descriptorsLeft, cv::Mat& descriptorsRight)
00274     {
00275         fExtractor_.compute(imgL, keypointsLeft, descriptorsLeft);
00276         fExtractor_.compute(imgR, keypointsRight, descriptorsRight);
00277     }
00278 
00287     bool stereoMatching(std::vector<cv::KeyPoint>& keypointsLeft,
00288                         std::vector<cv::KeyPoint>& keypointsRight,
00289                         cv::Mat& descriptorsLeft, cv::Mat& descriptorsRight,
00290                         std::vector<cv::DMatch>& stereoMatches, std::vector<cv::Point3f>& pcl)
00291     {
00292         std::vector<cv::DMatch> matches;
00293         try
00294         {
00295             matcher_.match(keypointsRight, descriptorsRight, keypointsLeft, descriptorsLeft,
00296                            matches, false);
00297         }
00298         catch(std::exception e)
00299         {
00300             ROS_ERROR("Matching error!");
00301             odomInit_ = false;
00302             return false;
00303         }
00304 
00305         // Generate stereo point cloud
00306         float f = PR_.at<double>(0,0), cx = PR_.at<double>(0,2), cy = PR_.at<double>(1,2), b = -PR_.at<double>(0,3)/f;
00307         float d, k1 = 1/f, k2 = f*b;
00308         for (size_t i = 0; i < matches.size(); i++)
00309         {
00310             const cv::DMatch& match = matches[i];
00311             const cv::Point2f& pL = keypointsLeft[match.trainIdx].pt;
00312             const cv::Point2f& pR = keypointsRight[match.queryIdx].pt;
00313             d = pL.x-pR.x;
00314             // If key-points y-coords are close enough (stabilized in roll,pitch)
00315             // and x-coords are far enough (sufficient disparity), it's a match!
00316             if(fabs(pR.y-pL.y) <= 5 && d > 2.0)
00317             {
00318                 stereoMatches.push_back(match);
00319 
00320                 // Calculate 3D point
00321                 cv::Point3f p;
00322                 p.z = k2/d;
00323                 p.x = (pL.x-cx)*p.z*k1;
00324                 p.y = (pL.y-cy)*p.z*k1;
00325                 pcl.push_back(p);
00326             }
00327         }
00328         return true;
00329     }
00330 
00337     double computeFeatureFlow(const std::vector<cv::DMatch> &matches,
00338                               const std::vector<cv::KeyPoint> &trainKpts,
00339                               const std::vector<cv::KeyPoint> &queryKpts)
00340     {
00341         int idT, idQ;
00342         double xDiff, yDiff, totalFlow = 0.0;
00343 
00344         for(size_t i=0; i<matches.size(); i++)
00345         {
00346             idT = matches[i].trainIdx;
00347             idQ = matches[i].queryIdx;
00348             xDiff = trainKpts[idT].pt.x - queryKpts[idQ].pt.x;
00349             yDiff = trainKpts[idT].pt.y - queryKpts[idQ].pt.y;
00350             totalFlow += sqrt(xDiff * xDiff + yDiff * yDiff);
00351         }
00352 
00353         return totalFlow / matches.size();
00354     }
00355 
00367     bool leftMatching(std::vector<cv::KeyPoint>& keypointsCurr,
00368                       std::vector<cv::KeyPoint>& keypointsPrev,
00369                       cv::Mat& descriptorsCurr, cv::Mat& descriptorsPrev,
00370                       std::vector<cv::DMatch>& stereoMatchesPrev, std::vector<cv::Point3f>& pclPrev,
00371                       double& flow, std::vector<cv::Point3f>& points3d,
00372                       std::vector<cv::Point2f>& projections)
00373     {
00374         std::vector<cv::DMatch> matches;
00375         try
00376         {
00377             matcher_.match(keypointsCurr, descriptorsCurr, keypointsPrev, descriptorsPrev, matches);
00378         }
00379         catch(std::exception e)
00380         {
00381             ROS_ERROR("Matching error!");
00382             odomInit_ = false;
00383             return false;
00384         }
00385 
00386         // Compute features flow
00387         flow = computeFeatureFlow(matches, keypointsPrev, keypointsCurr);
00388 
00389         // Establish matching between previous and current left images
00390         for(size_t i=0; i<stereoMatchesPrev.size(); i++)
00391         {
00392             int idLP = stereoMatchesPrev[i].trainIdx;
00393             for(size_t j=0; j<matches.size(); j++)
00394             {
00395                 if(matches[j].trainIdx == idLP)
00396                 {
00397                     points3d.push_back(pclPrev[i]);
00398                     projections.push_back(keypointsCurr[matches[j].queryIdx].pt);
00399                     break;
00400                 }
00401             }
00402         }
00403 
00404         //std::cout << "Keypoints: current (" << kptsLeftC_.size() << "), previous (" << kptsLeftP_.size() << ")\n";
00405         //std::cout << "Previous matches: " << leftMatches.size() << " (flow " << flow << ") -> " << points3d.size() << std::endl;
00406         return true;
00407     }
00408 
00414     void openCVToTf(const cv::Mat& t, const cv::Mat& R, tf::Transform& tf)
00415     {
00416         tf::Vector3 translationTf(t.at<double>(0,0), t.at<double>(1,0), t.at<double>(2,0));
00417 
00418         tf::Matrix3x3 rotationTf;
00419         for(int i = 0; i < 3; ++i)
00420             for(int j = 0; j < 3; ++j)
00421                 rotationTf[i][j] = R.at<double>(i,j);
00422 
00423         tf.setOrigin(translationTf);
00424         tf.setBasis(rotationTf);
00425     }
00426 
00432     void tfToOpenCV(const tf::Transform& tf, cv::Mat& t, cv::Mat& R)
00433     {
00434         t.at<double>(0,0) = tf.getOrigin().getX();
00435         t.at<double>(1,0) = tf.getOrigin().getY();
00436         t.at<double>(2,0) = tf.getOrigin().getZ();
00437 
00438         tf::Matrix3x3 rotationTf = tf.getBasis();
00439         for(int i = 0; i < 3; ++i)
00440             for(int j = 0; j < 3; ++j)
00441                 R.at<double>(i,j) = rotationTf[i][j];
00442     }
00443 
00449     bool leftPnP(std::vector<cv::Point3f>& points3d, std::vector<cv::Point2f>& projections,
00450                  tf::Transform& deltaT)
00451     {
00452         cv::Mat R, T, inliers;
00453         T = cv::Mat::zeros(3, 1, CV_64FC1);
00454 
00455         // Use IMU angles since last key-frame as initial approximation of rotation in solvePnP
00456         tf::Matrix3x3 dR;
00457         double rx, ry, rz;
00458         imu_.getAngleIntegration(rx, ry, rz);
00459         dR.setRPY(-ry, -rz, -rx);
00460         cv::Mat rot1(3, 3, CV_64FC1), rot2;
00461         rot1.at<double>(0,0) = dR[0][0]; rot1.at<double>(0,1) = dR[0][1]; rot1.at<double>(0,2) = dR[0][2];
00462         rot1.at<double>(1,0) = dR[1][0]; rot1.at<double>(1,1) = dR[1][1]; rot1.at<double>(1,2) = dR[1][2];
00463         rot1.at<double>(2,0) = dR[2][0]; rot1.at<double>(2,1) = dR[2][1]; rot1.at<double>(2,2) = dR[2][2];
00464         cv::Rodrigues(rot1, rot2);
00465 
00466         // Solve PnP using RANSAC and EPNP algorithm
00467         try
00468         {
00469             cv::solvePnPRansac(points3d, projections, KL_, cv::Mat(), rot2, T, true, 150, 2, 100, inliers, CV_EPNP);
00470             cv::Rodrigues(rot2, R);
00471         }
00472         catch(std::exception e)
00473         {
00474             ROS_ERROR("PnP error!");
00475             odomInit_ = false;
00476             return false;
00477         }
00478 
00479         // Convert to tf::Transform
00480         openCVToTf(T, R, deltaT);
00481 
00482         return true;
00483     }
00484 
00487     void compensateIMU(tf::Transform& odom)
00488     {
00489         double rxImu, ryImu, rzImu, rxOdom, ryOdom, rzOdom;
00490         imu_.getAngles(rxImu, ryImu, rzImu);
00491         tf::Matrix3x3(odom.getRotation()).getRPY(rxOdom, ryOdom, rzOdom);
00492         tf::Quaternion qCompensated;
00493         qCompensated.setRPY(rxImu, -(ryImu+0.4), rzOdom);
00494         odom.setRotation(qCompensated);
00495     }
00496 
00501     tf::Transform camera2baselink(const tf::Transform& odomC)
00502     {
00503         tf::Transform odom = Timu02base_*Tcam22imu0_*odomC*Tcam22imu0_.inverse()*Timu02base_.inverse();
00504         return odom;
00505     }
00506 
00511     tf::Transform baselink2camera(const tf::Transform& odom)
00512     {
00513         tf::Transform odomC = Tcam22imu0_.inverse()*Timu02base_.inverse()*odom*Timu02base_*Tcam22imu0_;
00514         return odomC;
00515     }
00516 
00520     void publishTf(const tf::Transform& odom)
00521     {
00522         // Publish TF
00523         tfBr_.sendTransform(
00524                     tf::StampedTransform(odom, ros::Time::now(),
00525                                          srcFrameId_, tgtFrameId_));
00526         // Publish pose
00527         geometry_msgs::TransformStamped outTransform;
00528         outTransform.header.frame_id = srcFrameId_;
00529         outTransform.header.stamp = ros::Time::now();
00530         tf::Quaternion qPose = odom.getRotation();
00531         outTransform.transform.rotation.x = qPose.x();
00532         outTransform.transform.rotation.y = qPose.y();
00533         outTransform.transform.rotation.z = qPose.z();
00534         outTransform.transform.rotation.w = qPose.w();
00535         tf::Vector3 pPose = odom.getOrigin();
00536         outTransform.transform.translation.x = pPose.x();
00537         outTransform.transform.translation.y = pPose.y();
00538         outTransform.transform.translation.z = pPose.z();
00539         transformPub_.publish(outTransform);
00540     }
00541 
00545     void publishPointCloud(const std::vector<cv::Point3f> pcl, const std_msgs::Header header)
00546     {
00547         // Fill PointCloud message
00548         sensor_msgs::PointCloud outCloud;
00549         outCloud.points.resize(pcl.size());
00550         outCloud.header = header;
00551         for(size_t i=0; i<outCloud.points.size(); i++)
00552         {
00553             outCloud.points[i].x = pcl[i].x;
00554             outCloud.points[i].y = pcl[i].y;
00555             outCloud.points[i].z = pcl[i].z;
00556         }
00557 
00558         // Convert PointCloud to PointCloud2
00559         sensor_msgs::PointCloud2 outCloud2;
00560         sensor_msgs::convertPointCloudToPointCloud2(outCloud, outCloud2);
00561 
00562         // Publish point cloud
00563         pcPub_.publish(outCloud2);
00564     }
00565 
00570     void updatePreviousStuff(const cv::Mat& imgL, const cv::Mat& imgR)
00571     {
00572         // Save current images as previous ones for next comparison
00573         imgL.copyTo(imgLP_);
00574         imgR.copyTo(imgRP_);
00575 
00576         // Save current key-points and descriptors
00577         kptsLeftP_ = kptsLeftC_;
00578         kptsRightP_ = kptsRightC_;
00579         descLeftC_.copyTo(descLeftP_);
00580         descRightC_.copyTo(descRightP_);
00581 
00582         // Save stereo matching results, 2D projections and 3D point cloud
00583         stereoMatchesP_ = stereoMatchesC_;
00584         pclP_ = pclC_;
00585 
00586         // Reset angle rate integration
00587         imu_.resetAngleIntegration();
00588     }
00589 
00594     void stereoCallback(const sensor_msgs::ImageConstPtr& leftImg,
00595                         const sensor_msgs::ImageConstPtr& rightImg)
00596     {
00597         double flow = 0.0;
00598 
00599         // Processing does not start until first calibration is received
00600         if(!calibInit_)
00601         {
00602             ROS_WARN("calibInit = false, exiting callback");
00603             return;
00604         }
00605 
00606         // Processing does not start until imu_ is initialized
00607         if(!imu_.isInit())
00608         {
00609             ROS_WARN("imu.isInit = false, exiting callback");
00610             return;
00611         }
00612 
00613         // Convert to OpenCV format and rectify both images
00614         cv::Mat imgL, imgR;
00615         if(!convertRectifyImages(leftImg, rightImg, imgL, imgR))
00616             return;
00617 
00618         // Detect key-points in the images
00619         kptsLeftC_.clear();     kptsRightC_.clear();
00620         selectKeypoints(imgL, imgR, kptsLeftC_, kptsRightC_);
00621         //std::cout << "Keypoints: left (" << kptsLeftC_.size() << "), right (" << kptsRightC_.size() << ")\n";
00622 
00623         // Extract feature descriptors
00624         extractDescriptors(imgL, imgR, kptsLeftC_, kptsRightC_, descLeftC_, descRightC_);
00625 
00626         // Stereo matching and 3D point cloud generation
00627         pclC_.clear();
00628         stereoMatchesC_.clear();
00629         if(!stereoMatching(kptsLeftC_, kptsRightC_, descLeftC_, descRightC_, stereoMatchesC_, pclC_))
00630             return;
00631         //std::cout << "Stereo matches: " stereoMatchesC_.size() << std::endl;
00632 
00633         // If not the first frame, compute odometry
00634         if(odomInit_)
00635         {
00636             // Matching between previous left key-frame and current left image
00637             std::vector<cv::Point3f> points3d;
00638             std::vector<cv::Point2f> projections;
00639             if(!leftMatching(kptsLeftC_, kptsLeftP_, descLeftC_, descLeftP_,
00640                              stereoMatchesP_, pclP_, flow, points3d, projections))
00641                 return;
00642 
00643             // If there are enough matches
00644             if(points3d.size() >= minMatches_)
00645             {
00646                 // Compute PnP between previous key-frame and current frame
00647                 tf::Transform deltaT;
00648                 if(!leftPnP(points3d, projections, deltaT))
00649                     return;
00650 
00651                 odomC_ = odomCkf_ * deltaT.inverse();
00652                 imgL.copyTo(imgC_);
00653                 odom_ = camera2baselink(odomC_);
00654 
00655                 // Compensate IMU roll and pitch angles in base_link frame
00656                 compensateIMU(odom_);
00657 
00658                 // Transform back to camera frame to compensate odomC_ accordingly
00659                 odomC_ = baselink2camera(odom_);
00660 
00661                 if(flow > flowThreshold_)
00662                 {
00663                     // Save key-frame transform and image
00664                     odomCkf_ = odomC_;
00665                     imgL.copyTo(imgCkf_);
00666                 }
00667 
00668                 //Publish transform
00669                 publishTf(odom_);
00670 
00671                 // Publish current 3D point cloud
00672                 if(publishPc_)
00673                     publishPointCloud(pclC_, leftImg->header);
00674             }
00675             else
00676                 ROS_WARN_STREAM("Not enough matches! (" << points3d.size() << ")");
00677         }
00678         else
00679             ROS_WARN("odomInit = false");
00680 
00681         // If new key-frame or first image pair
00682         if(flow > flowThreshold_ || !odomInit_)
00683         {
00684             updatePreviousStuff(imgL, imgR);
00685         }
00686 
00687         // Set the init flag to true
00688         odomInit_ = true;
00689     }
00690 
00695     void cameraInfoCallback(const sensor_msgs::CameraInfoConstPtr& leftInfo,
00696                             const sensor_msgs::CameraInfoConstPtr& rightInfo)
00697     {
00698         if(!calibInit_)
00699         {
00700             // Store stereo camera parameters
00701             RL_ = cv::Mat(3, 3, CV_64FC1, (void *)leftInfo->R.elems).clone();
00702             PL_ = cv::Mat(3, 4, CV_64FC1, (void *)leftInfo->P.elems).clone();
00703             RR_ = cv::Mat(3, 3, CV_64FC1, (void *)rightInfo->R.elems).clone();
00704             PR_ = cv::Mat(3, 4, CV_64FC1, (void *)rightInfo->P.elems).clone();
00705 
00706             // Obtain the corresponding PL and PR of the downsampled images
00707             PL_.at<double>(0,0) = PL_.at<double>(0,0)/(float)downsampling_;
00708             PL_.at<double>(0,2) = PL_.at<double>(0,2)/(float)downsampling_;
00709             PL_.at<double>(0,3) = PL_.at<double>(0,3)/(float)downsampling_;
00710             PL_.at<double>(1,1) = PL_.at<double>(1,1)/(float)downsampling_;
00711             PL_.at<double>(1,2) = PL_.at<double>(1,2)/(float)downsampling_;
00712             PR_.at<double>(0,0) = PR_.at<double>(0,0)/(float)downsampling_;
00713             PR_.at<double>(0,2) = PR_.at<double>(0,2)/(float)downsampling_;
00714             PR_.at<double>(0,3) = PR_.at<double>(0,3)/(float)downsampling_;
00715             PR_.at<double>(1,1) = PR_.at<double>(1,1)/(float)downsampling_;
00716             PR_.at<double>(1,2) = PR_.at<double>(1,2)/(float)downsampling_;
00717 
00718             // Initialize left and right image remapping (rectification and undistortion)
00719             cv::initUndistortRectifyMap(cv::Mat(3, 3, CV_64FC1, (void *)leftInfo->K.elems),
00720                                         cv::Mat(4, 1, CV_64FC1, (void *)leftInfo->D.data()),
00721                                         RL_, PL_,
00722                                         cv::Size(leftInfo->width/(float)downsampling_, leftInfo->height/(float)downsampling_),
00723                                         CV_16SC2, mapL1_, mapL2_);
00724             cv::initUndistortRectifyMap(cv::Mat(3, 3, CV_64FC1, (void *)rightInfo->K.elems),
00725                                         cv::Mat(4, 1, CV_64FC1, (void *)rightInfo->D.data()),
00726                                         RR_, PR_,
00727                                         cv::Size(rightInfo->width/(float)downsampling_, rightInfo->height/(float)downsampling_),
00728                                         CV_16SC2, mapR1_, mapR2_);
00729 
00730             // Store single camera calibration after rectification (no distortion)
00731             KL_ = cv::Mat(3, 3, CV_64FC1);
00732             KL_.at<double>(0,0) = PL_.at<double>(0,0); KL_.at<double>(0,1) = PL_.at<double>(0,1); KL_.at<double>(0,2) = PL_.at<double>(0,2);
00733             KL_.at<double>(1,0) = PL_.at<double>(1,0); KL_.at<double>(1,1) = PL_.at<double>(1,1); KL_.at<double>(1,2) = PL_.at<double>(1,2);
00734             KL_.at<double>(2,0) = PL_.at<double>(2,0); KL_.at<double>(2,1) = PL_.at<double>(2,1); KL_.at<double>(2,2) = PL_.at<double>(2,2);
00735             KR_ = cv::Mat(3, 3, CV_64FC1);
00736             KR_.at<double>(0,0) = PR_.at<double>(0,0); KR_.at<double>(0,1) = PR_.at<double>(0,1); KR_.at<double>(0,2) = PR_.at<double>(0,2);
00737             KR_.at<double>(1,0) = PR_.at<double>(1,0); KR_.at<double>(1,1) = PR_.at<double>(1,1); KR_.at<double>(1,2) = PR_.at<double>(1,2);
00738             KR_.at<double>(2,0) = PR_.at<double>(2,0); KR_.at<double>(2,1) = PR_.at<double>(2,1); KR_.at<double>(2,2) = PR_.at<double>(2,2);
00739 
00740             // Set calibration flag to true
00741             calibInit_ = true;
00742         }
00743     }
00744 
00747     void dynRecCallback(viodom::stereodomConfig &config, uint32_t level)
00748     {
00749         ROS_INFO("Reconfiguring");
00750         downsampling_ = config.downsampling;
00751         maxFeatures_ = config.max_features;
00752         flowThreshold_ = config.flow_threshold;
00753         minMatches_ = config.min_matches;
00754     }
00755 
00756     //void showMatchesImage(const std::vector<cv::DMatch>& matches)
00757     //{
00758     //    cv::Mat image;
00759     //    cv::drawMatches(imgC, kptsLeftC, imgLP, kptsLeftP, matches, image);
00760     //    cv::imshow("viodom", image);
00761     //    cv::waitKey(5);
00762     //}
00763 
00764     std::vector<cv::KeyPoint> kptsLeftP_, kptsLeftC_;   
00765     std::vector<cv::KeyPoint> kptsRightP_, kptsRightC_; 
00766     cv::Mat descLeftP_, descLeftC_;                     
00767     cv::Mat descRightP_, descRightC_;                   
00769     cv::FastFeatureDetector fDetector_;                 
00770     cv::BriefDescriptorExtractor fExtractor_;           
00772     RobustMatcher matcher_;                             
00774     std::vector<cv::DMatch> stereoMatchesP_, stereoMatchesC_;   
00775     std::vector<cv::Point3f> pclP_, pclC_;              
00777     ros::NodeHandle nh_;                                
00778     image_transport::ImageTransport it_;                
00779     image_transport::SubscriberFilter leftImgSubs_, rightImgSubs_;  
00780     message_filters::Subscriber<sensor_msgs::CameraInfo> leftInfoSubs_, rightInfoSubs_;     
00782     message_filters::TimeSynchronizer<sensor_msgs::Image, sensor_msgs::Image> stereoSync_;  
00783     message_filters::TimeSynchronizer<sensor_msgs::CameraInfo, sensor_msgs::CameraInfo> cameraInfoSync_;    
00785     ros::Publisher transformPub_;                       
00786     ros::Publisher pcPub_;                              
00788     bool odomInit_;                 
00789     bool calibInit_;                
00791     // Node params
00792     bool publishPc_;                
00793     int maxFeatures_;               
00794     double flowThreshold_;          
00795     int minMatches_;                
00796     int downsampling_;              
00797     std::string srcFrameId_;        
00798     std::string tgtFrameId_;        
00799     tf::Transform Tcam22imu0_, Timu02base_;     
00800     double kfTrTh_, kfRotTh_;       
00802     cv::Mat KL_, PL_, RL_;          
00803     cv::Mat KR_, PR_, RR_;          
00805     cv::Mat mapL1_, mapL2_, mapR1_, mapR2_;     
00807     tf::Transform odom_, odomC_, odomCkf_;      
00808     cv::Mat imgC_, imgCkf_;                     
00809     cv::Mat imgRP_, imgLP_;                     
00811     tf::TransformBroadcaster tfBr_;             
00813     ImuFilter imu_;                             
00815     dynamic_reconfigure::Server<viodom::stereodomConfig> dyn_rec_server_;           
00816     dynamic_reconfigure::Server<viodom::stereodomConfig>::CallbackType dyn_rec_f_;  
00817 };
00818 
00819 
00820 #endif
00821 


viodom
Author(s): Fernando Caballero , Francisco J. Perez Grau
autogenerated on Thu Jun 6 2019 20:17:02