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
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_(),
00095 fExtractor_(16),
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
00107
00108
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
00131 Stereodom::dyn_rec_f_ = boost::bind(&Stereodom::dynRecCallback, this, _1, _2);
00132 Stereodom::dyn_rec_server_.setCallback(Stereodom::dyn_rec_f_);
00133
00134
00135 stereoSync_.registerCallback(boost::bind(&Stereodom::stereoCallback, this, _1, _2));
00136 cameraInfoSync_.registerCallback(boost::bind(&Stereodom::cameraInfoCallback, this, _1, _2));
00137
00138
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
00144 odomInit_ = false;
00145 calibInit_ = false;
00146 odomC_.setIdentity();
00147 odomCkf_.setIdentity();
00148 odom_.setIdentity();
00149
00150
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
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
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
00212 if(srcKpts[i].pt.y <= height/2)
00213 id = 0;
00214 else
00215 id = 3;
00216
00217
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
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
00247 std::vector<cv::KeyPoint> kptsL, kptsR;
00248 fDetector_.detect(imgLeft, kptsL);
00249 fDetector_.detect(imgRight, kptsR);
00250
00251
00252 std::sort(kptsL.begin(), kptsL.end(), score_comparator);
00253 std::sort(kptsR.begin(), kptsR.end(), score_comparator);
00254
00255
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
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
00315
00316 if(fabs(pR.y-pL.y) <= 5 && d > 2.0)
00317 {
00318 stereoMatches.push_back(match);
00319
00320
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
00387 flow = computeFeatureFlow(matches, keypointsPrev, keypointsCurr);
00388
00389
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
00405
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
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
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
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
00523 tfBr_.sendTransform(
00524 tf::StampedTransform(odom, ros::Time::now(),
00525 srcFrameId_, tgtFrameId_));
00526
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
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
00559 sensor_msgs::PointCloud2 outCloud2;
00560 sensor_msgs::convertPointCloudToPointCloud2(outCloud, outCloud2);
00561
00562
00563 pcPub_.publish(outCloud2);
00564 }
00565
00570 void updatePreviousStuff(const cv::Mat& imgL, const cv::Mat& imgR)
00571 {
00572
00573 imgL.copyTo(imgLP_);
00574 imgR.copyTo(imgRP_);
00575
00576
00577 kptsLeftP_ = kptsLeftC_;
00578 kptsRightP_ = kptsRightC_;
00579 descLeftC_.copyTo(descLeftP_);
00580 descRightC_.copyTo(descRightP_);
00581
00582
00583 stereoMatchesP_ = stereoMatchesC_;
00584 pclP_ = pclC_;
00585
00586
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
00600 if(!calibInit_)
00601 {
00602 ROS_WARN("calibInit = false, exiting callback");
00603 return;
00604 }
00605
00606
00607 if(!imu_.isInit())
00608 {
00609 ROS_WARN("imu.isInit = false, exiting callback");
00610 return;
00611 }
00612
00613
00614 cv::Mat imgL, imgR;
00615 if(!convertRectifyImages(leftImg, rightImg, imgL, imgR))
00616 return;
00617
00618
00619 kptsLeftC_.clear(); kptsRightC_.clear();
00620 selectKeypoints(imgL, imgR, kptsLeftC_, kptsRightC_);
00621
00622
00623
00624 extractDescriptors(imgL, imgR, kptsLeftC_, kptsRightC_, descLeftC_, descRightC_);
00625
00626
00627 pclC_.clear();
00628 stereoMatchesC_.clear();
00629 if(!stereoMatching(kptsLeftC_, kptsRightC_, descLeftC_, descRightC_, stereoMatchesC_, pclC_))
00630 return;
00631
00632
00633
00634 if(odomInit_)
00635 {
00636
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
00644 if(points3d.size() >= minMatches_)
00645 {
00646
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
00656 compensateIMU(odom_);
00657
00658
00659 odomC_ = baselink2camera(odom_);
00660
00661 if(flow > flowThreshold_)
00662 {
00663
00664 odomCkf_ = odomC_;
00665 imgL.copyTo(imgCkf_);
00666 }
00667
00668
00669 publishTf(odom_);
00670
00671
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
00682 if(flow > flowThreshold_ || !odomInit_)
00683 {
00684 updatePreviousStuff(imgL, imgR);
00685 }
00686
00687
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
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
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
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
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
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
00757
00758
00759
00760
00761
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
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