00001
00005 #include "videoslam.hpp"
00006
00007 struct timeval cycle_timer;
00008
00009
00010 int main(int argc, char** argv) {
00011
00012 ROS_INFO("Node launched.");
00013
00014 ros::init(argc, argv, "videoslam");
00015
00016 ros::NodeHandle private_node_handle("~");
00017
00018 videoslamData startupData;
00019
00020 bool inputIsValid = startupData.obtainStartingData(private_node_handle);
00021
00022 startupData.read_addr = argv[0];
00023 startupData.read_addr = startupData.read_addr.substr(0, startupData.read_addr.size()-12);
00024
00025 if (!inputIsValid) {
00026 ROS_INFO("Configuration invalid.");
00027 }
00028
00029 ROS_INFO("Startup data processed.");
00030
00031
00032
00033 ros::NodeHandle nh;
00034
00035 ROS_INFO("About to create shared pointer..");
00036 boost::shared_ptr < videoslamNode > videoslam_node (new videoslamNode (nh, startupData));
00037 ROS_INFO("Shared pointer created.");
00038
00039 globalNodePtr = &videoslam_node;
00040
00041 signal(SIGINT, mySigintHandler);
00042
00043 ROS_INFO("Node configured.");
00044
00045 ros::AsyncSpinner spinner(2);
00046
00047 spinner.start();
00048
00049 while (!wantsToShutdown) { };
00050
00051 mySigintHandler(1);
00052
00053 ros::shutdown();
00054
00055 ROS_INFO("Exiting.");
00056
00057 return 0;
00058
00059 }
00060
00061 bool videoslamData::obtainStartingData(ros::NodeHandle& nh) {
00062
00063 nh.param<std::string>("extrinsicsFile", extrinsicsFile, "extrinsicsFile");
00064
00065 if (extrinsicsFile == "extrinsicsFile") {
00066 ROS_ERROR("No extrinsics specified! Please provide extrinsic calibration data.");
00067 } else {
00068 ROS_INFO("Extrinsics at (%s) selected.", extrinsicsFile.c_str());
00069 }
00070
00071 nh.param<bool>("writePoses", writePoses, false);
00072 nh.param<bool>("clearTriangulations", clearTriangulations, false);
00073
00074 nh.param<double>("maxPoseDelay", maxPoseDelay, 1.0);
00075 nh.param<double>("terminationTime", terminationTime, -1.0);
00076 nh.param<double>("restartTime", restartTime, -1.0);
00077
00078
00079
00080
00081 nh.param<int>("evaluateParameters", evaluateParameters, 0);
00082
00083 nh.param<std::string>("flowSource", flowSource, "/thermalvis/flow/");
00084 nh.param<std::string>("mapperSource", mapperSource, "/thermalvis/mapper");
00085
00086 nh.param<bool>("publishPoints", publishPoints, false);
00087 nh.param<bool>("publishKeyframes", publishKeyframes, false);
00088
00089 return true;
00090 }
00091
00092 void mySigintHandler(int sig)
00093 {
00094 wantsToShutdown = true;
00095 ROS_WARN("Requested shutdown... terminating feeds...");
00096
00097 }
00098
00099 bool videoslamNode::checkConnectivity(unsigned int seq) {
00100
00101
00102
00103
00104
00105 unsigned int projectionsCount = 0;
00106
00107 unsigned int longTracksCount = 0;
00108
00109 for (unsigned int iii = 0; iii < featureTrackVector.size(); iii++) {
00110
00111 if (featureTrackVector.at(iii).locations.size() < 2) {
00112 continue;
00113 }
00114
00115 longTracksCount++;
00116
00117 for (unsigned int jjj = 0; jjj < featureTrackVector.at(iii).locations.size(); jjj++) {
00118
00119
00120
00121 if (featureTrackVector.at(iii).locations.at(jjj).imageIndex == seq) {
00122 projectionsCount++;
00123 }
00124 }
00125 }
00126
00127 if (configData.verboseMode) { ROS_INFO("Projections for current tracks #(%d) = (%d, %d)", seq, projectionsCount, longTracksCount); }
00128
00129
00130
00131 if (projectionsCount < 8) return false;
00132
00133 return true;
00134
00135 }
00136
00137 bool videoslamNode::updateKeyframePoses(const geometry_msgs::PoseStamped& pose_msg, bool fromICP) {
00138
00139 if (configData.verboseMode) { ROS_INFO("Entered <%s>", __FUNCTION__); }
00140
00141
00142
00143 if ( (storedPosesCount > 0) && !checkConnectivity(pose_msg.header.seq) ) {
00144 if (configData.verboseMode) { ROS_WARN("Frame (%d) has insufficient connectivity...", pose_msg.header.seq); }
00145 return false;
00146 }
00147
00148 if (configData.verboseMode) { ROS_WARN("Considering tracks frame (%d) as a keyframe (has sufficient connectivity)", pose_msg.header.seq); }
00149
00150 if (fromICP) {
00151
00152 unsigned int floatersCleared = 0;
00153
00154 for (unsigned int iii = 0; iii < storedPosesCount; iii++) {
00155
00156 if (!keyframeTypes[iii]) {
00157
00158 for (unsigned int jjj = iii; jjj < storedPosesCount-1; jjj++) {
00159 keyframePoses[jjj] = keyframePoses[jjj+1];
00160 keyframeTypes[jjj] = keyframeTypes[jjj+1];
00161 }
00162
00163 storedPosesCount--;
00164 iii--;
00165 floatersCleared++;
00166
00167 }
00168
00169
00170 }
00171
00172 if (configData.verboseMode && (floatersCleared > 0)) { ROS_INFO("Cleared (%d) poses (%d remain) because now have received ICP-based estimate.", floatersCleared, storedPosesCount); }
00173 }
00174
00175 if (((int)storedPosesCount) < configData.adjustmentFrames) {
00176 keyframePoses[storedPosesCount] = pose_msg;
00177 keyframeTypes[storedPosesCount] = fromICP;
00178 if (configData.verboseMode) { ROS_INFO("Adding keyframe pose with index (%d)", pose_msg.header.seq); }
00179 storedPosesCount++;
00180 return true;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 while (((int)storedPosesCount) >= ((int)configData.adjustmentFrames)) {
00205
00206 double maxDistance = 0.0;
00207 unsigned int maxIndex = 0;
00208
00209 for (unsigned int iii = 0; iii < storedPosesCount; iii++) {
00210 double dist = pow(pose_msg.pose.position.x - keyframePoses[iii].pose.position.x, 2.0) + pow(pose_msg.pose.position.y - keyframePoses[iii].pose.position.y, 2.0) + pow(pose_msg.pose.position.z - keyframePoses[iii].pose.position.z, 2.0);
00211
00212 if (dist >= maxDistance) {
00213 maxDistance = dist;
00214 maxIndex = iii;
00215 }
00216
00217 }
00218
00219 maxDistance = pow(maxDistance, 0.5);
00220
00221 if ( (maxDistance <= configData.maxDistance) && (configData.maxDistance != 0.0) ) {
00222 break;
00223 }
00224
00225 if (configData.verboseMode) { ROS_INFO("Removing frame (%d) because of distance (%f) > (%f)", keyframePoses[maxIndex].header.seq, maxDistance, configData.maxDistance); }
00226
00227 for (unsigned int iii = maxIndex; iii < storedPosesCount-1; iii++) {
00228 keyframePoses[iii] = keyframePoses[iii+1];
00229 keyframeTypes[iii] = keyframeTypes[iii+1];
00230 }
00231
00232 storedPosesCount--;
00233
00234 if (((int)storedPosesCount) == ((int)configData.adjustmentFrames-1)) {
00235 if (configData.verboseMode) { ROS_WARN("Appending most recent frame (%d) to keyframes in max loop", pose_msg.header.seq); }
00236 keyframePoses[storedPosesCount] = pose_msg;
00237 keyframeTypes[storedPosesCount] = fromICP;
00238 storedPosesCount++;
00239 return true;
00240 }
00241
00242 }
00243
00244
00245
00246 while (((int)storedPosesCount) >= ((int)configData.adjustmentFrames)) {
00247
00248 double minDistance = 9e99;
00249 unsigned int minIndex = 0;
00250
00251 for (unsigned int iii = 0; iii < storedPosesCount; iii++) {
00252
00253 double dist = 0.0;
00254 double div = 0.0;
00255
00256 if (iii > 0) {
00257 dist += pow(keyframePoses[iii].pose.position.x - keyframePoses[iii-1].pose.position.x, 2.0) + pow(keyframePoses[iii].pose.position.y - keyframePoses[iii-1].pose.position.y, 2.0) + pow(keyframePoses[iii].pose.position.z - keyframePoses[iii-1].pose.position.z, 2.0);
00258 div += 1.0;
00259 }
00260
00261 if(iii < (storedPosesCount-1)) {
00262 dist += pow(keyframePoses[iii].pose.position.x - keyframePoses[iii+1].pose.position.x, 2.0) + pow(keyframePoses[iii].pose.position.y - keyframePoses[iii+1].pose.position.y, 2.0) + pow(keyframePoses[iii].pose.position.z - keyframePoses[iii+1].pose.position.z, 2.0);
00263 div += 1.0;
00264 }
00265
00266 if (div == 0.0) {
00267 ROS_ERROR("Trying to update keyframe list but only one seems to exist!");
00268 }
00269
00270 dist /= div;
00271
00272 if (dist <= minDistance) {
00273 minDistance = dist;
00274 minIndex = iii;
00275 }
00276
00277 }
00278
00279 minDistance = pow(minDistance, 0.5);
00280
00281 if (configData.verboseMode) { ROS_WARN("Removing %dth frame (%d) which is least distant (%f)", minIndex, keyframePoses[minIndex].header.seq, minDistance); }
00282
00283 for (unsigned int iii = minIndex; iii < storedPosesCount-1; iii++) {
00284 keyframePoses[iii] = keyframePoses[iii+1];
00285 keyframeTypes[iii] = keyframeTypes[iii+1];
00286 }
00287
00288 storedPosesCount--;
00289
00290 }
00291
00292 if (configData.verboseMode) { ROS_WARN("Adding keyframe (%d) at end of function", pose_msg.header.seq); }
00293 keyframePoses[storedPosesCount] = pose_msg;
00294 keyframeTypes[storedPosesCount] = fromICP;
00295 storedPosesCount++;
00296
00297 return true;
00298
00299
00300 }
00301
00302 void videoslamNode::trimFeatureTrackVector() {
00303
00304 unsigned int jjj;
00305
00306 int preservationBuffer = 0;
00307
00308 int newestSafeIndex = max(lastTestedFrame-preservationBuffer, 0);
00309
00310
00311
00312 for (int iii = 0; iii < ((int)featureTrackVector.size()); iii++) {
00313
00314 jjj = 0;
00315
00316 while (jjj < featureTrackVector.at(iii).locations.size()) {
00317
00318 bool validImage = false;
00319
00320 if (((int)featureTrackVector.at(iii).locations.at(jjj).imageIndex) >= newestSafeIndex) {
00321 validImage = true;
00322 } else {
00323
00324 for (unsigned int kkk = 0; kkk < storedPosesCount; kkk++) {
00325 if (keyframePoses[kkk].header.seq == featureTrackVector.at(iii).locations.at(jjj).imageIndex) {
00326 validImage = true;
00327 break;
00328 }
00329 }
00330 }
00331
00332 if (!validImage) {
00333 featureTrackVector.at(iii).locations.erase(featureTrackVector.at(iii).locations.begin()+jjj);
00334 } else {
00335 jjj++;
00336 }
00337 }
00338
00339 if (featureTrackVector.at(iii).locations.size() == 0) {
00340 featureTrackVector.erase(featureTrackVector.begin()+iii);
00341 iii--;
00342 }
00343
00344 }
00345
00346
00347 }
00348
00349 void shiftPose(const geometry_msgs::Pose& pose_src, geometry_msgs::Pose& pose_dst, cv::Mat transformation) {
00350
00351
00352
00353
00354
00355 QuaternionDbl quat_src;
00356 quat_src = QuaternionDbl(pose_src.orientation.w, pose_src.orientation.x, pose_src.orientation.y, pose_src.orientation.z);
00357
00358
00359
00360 cv::Mat src_T, src_R, src_P;
00361
00362 quaternionToMatrix(quat_src, src_R);
00363
00364 src_T = cv::Mat::zeros(3,1,CV_64FC1);
00365 src_T.at<double>(0,0) = pose_src.position.x;
00366 src_T.at<double>(1,0) = pose_src.position.y;
00367 src_T.at<double>(2,0) = pose_src.position.z;
00368
00369 composeTransform(src_R, src_T, src_P);
00370
00371 cv::Mat dst_P, dst_R, dst_T;
00372
00373 dst_P = src_P * transformation;
00374
00375 decomposeTransform(dst_P, dst_R, dst_T);
00376
00377 QuaternionDbl quat_dst;
00378 matrixToQuaternion(dst_R, quat_dst);
00379
00380 pose_dst.orientation.w = quat_dst.w();
00381 pose_dst.orientation.x = quat_dst.x();
00382 pose_dst.orientation.y = quat_dst.y();
00383 pose_dst.orientation.z = quat_dst.z();
00384
00385 pose_dst.position.x = dst_T.at<double>(0,0);
00386 pose_dst.position.y = dst_T.at<double>(1,0);
00387 pose_dst.position.z = dst_T.at<double>(2,0);
00388
00389
00390
00391 }
00392
00393 bool interpolatePose(const geometry_msgs::Pose& pose1, ros::Time time1, const geometry_msgs::Pose& pose2, ros::Time time2, geometry_msgs::Pose& finalPose, ros::Time time3) {
00394
00395 double time_gap = time2.toSec() - time1.toSec();
00396 double prediction_gap = time3.toSec() - time1.toSec();
00397
00398 double biasFactor = prediction_gap / time_gap;
00399
00400 if (0) { ROS_INFO("times = (%f, %f, %f) : (%f, %f)", time1.toSec(), time2.toSec(), time3.toSec(), time_gap, prediction_gap); }
00401 if (0) { ROS_INFO("biasFactor = (%f)", biasFactor); }
00402
00403 if ( (abs(time_gap) > MAX_TIME_GAP_FOR_INTERP) || (abs(prediction_gap) > MAX_TIME_GAP_FOR_INTERP) ) {
00404 return false;
00405 }
00406
00407 finalPose.position.x = (1.0 - biasFactor) * pose1.position.x + biasFactor * pose2.position.x;
00408 finalPose.position.y = (1.0 - biasFactor) * pose1.position.y + biasFactor * pose2.position.y;
00409 finalPose.position.z = (1.0 - biasFactor) * pose1.position.z + biasFactor * pose2.position.z;
00410
00411
00412 QuaternionDbl quat_1, quat_2, quat_i;
00413
00414 quat_1 = QuaternionDbl(pose1.orientation.w, pose1.orientation.x, pose1.orientation.y, pose1.orientation.z);
00415 quat_2 = QuaternionDbl(pose2.orientation.w, pose2.orientation.x, pose2.orientation.y, pose2.orientation.z);
00416
00417 quat_i = quat_2.slerp(biasFactor, quat_1);
00418
00419 finalPose.orientation.x = quat_i.x();
00420 finalPose.orientation.y = quat_i.y();
00421 finalPose.orientation.z = quat_i.z();
00422 finalPose.orientation.w = quat_i.w();
00423
00424 return true;
00425 }
00426
00427 bool videoslamNode::findNearestPoses(int& index1, int& index2, const ros::Time& targetTime) {
00428
00429 int minPosInd = -1, minNegInd = -1, twoPosInd = -1, twoNegInd = -1;
00430
00431 int posAssigned = 0, negAssigned = 0;
00432
00433
00434 double minPosDiff = 9e99, twoPosDiff = 9e99, minNegDiff = 9e99, twoNegDiff = 9e99;
00435
00436
00437
00438 for (int iii = 0; iii < min(int(poseHistoryCounter), MAX_HISTORY); iii++) {
00439
00440
00441
00442 if (poseHistoryBuffer[iii % MAX_HISTORY].header.stamp.toSec() == 0.0) {
00443 continue;
00444 }
00445
00446 double diff = targetTime.toSec() - poseHistoryBuffer[iii % MAX_HISTORY].header.stamp.toSec();
00447
00448
00449
00450
00451
00452 if (diff > 0.0) {
00453 if (abs(diff) < minPosDiff) {
00454 twoPosDiff = minPosDiff;
00455 minPosDiff = abs(diff);
00456 twoPosInd = minPosInd;
00457 minPosInd = iii;
00458
00459 posAssigned++;
00460 } else if (posAssigned < 2) {
00461 twoPosDiff = abs(diff);
00462 twoPosInd = iii;
00463 posAssigned++;
00464
00465 }
00466 } else if (diff < 0.0) {
00467 if (abs(diff) < minNegDiff) {
00468 twoNegDiff = minNegDiff;
00469 minNegDiff = abs(diff);
00470 twoNegInd = minNegInd;
00471 minNegInd = iii;
00472
00473 } else if (negAssigned < 2) {
00474 twoNegDiff = abs(diff);
00475 twoNegInd = iii;
00476 negAssigned++;
00477 }
00478 } else {
00479 twoNegDiff = minNegDiff;
00480 minNegDiff = 0.0;
00481 twoNegInd = minNegInd;
00482 minNegInd = iii;
00483
00484 twoPosDiff = minPosDiff;
00485 minPosDiff = 0.0;
00486 twoPosInd = minPosInd;
00487 minPosInd = iii;
00488
00489 }
00490
00491 }
00492
00493 if ( (minPosInd >= 0) && (minNegInd >= 0) ) {
00494
00495 index1 = minPosInd;
00496 index2 = minNegInd;
00497
00498
00499
00500 return true;
00501
00502 } else {
00503
00504
00505
00506 if (minPosDiff >= twoNegDiff) {
00507
00508 index1 = minNegInd;
00509 index2 = twoNegInd;
00510
00511 } else if (minNegDiff >= twoPosDiff) {
00512
00513 index1 = twoPosInd;
00514 index2 = minPosInd;
00515
00516 } else {
00517 ROS_ERROR("Shouldn't be in here!!");
00518 }
00519
00520 }
00521
00522 return false;
00523
00524 }
00525
00526 bool videoslamNode::updateLocalPoseEstimates() {
00527
00528 double depthTime = poseHistoryBuffer[(poseHistoryCounter-1) % MAX_HISTORY].header.stamp.toSec();
00529
00530 if (0) { ROS_INFO("%s << depthTime = (%f)", __FUNCTION__, depthTime); }
00531
00532 if (0) { ROS_INFO("%s << depthTime = (%d) (%d) (%d)", __FUNCTION__, frameProcessedCounter, frameHeaderHistoryCounter, MAX_HISTORY); }
00533
00534 frameProcessedCounter = max(frameProcessedCounter, frameHeaderHistoryCounter - MAX_HISTORY);
00535
00536 for (unsigned int jjj = frameProcessedCounter; jjj < frameHeaderHistoryCounter; jjj++) {
00537
00538
00539 if (0) { ROS_WARN("Considering with (%d) and frameProcessedCounter (%d)", jjj, frameProcessedCounter); }
00540
00541 int minPosInd = -1, minNegInd = -1;
00542 if (!findNearestPoses(minPosInd, minNegInd, frameHeaderHistoryBuffer[jjj % MAX_HISTORY].stamp)) {
00543 if (0) { ROS_WARN("Surrounding depth frames were not able to be found!"); }
00544 return false;
00545 }
00546
00547 if (0) { ROS_WARN("Progressing.."); }
00548
00549 geometry_msgs::PoseStamped tracksFrameInterpolatedPose, tracksFrameShiftedPose;
00550 tracksFrameInterpolatedPose.header = frameHeaderHistoryBuffer[jjj % MAX_HISTORY];
00551
00552 if (0) { ROS_INFO("Considering frame (%d) with time = (%f)", jjj, frameHeaderHistoryBuffer[jjj % MAX_HISTORY].stamp.toSec()); }
00553 if (0) { ROS_INFO("Best matching indices were (%d) and (%d) : [%f] {%f} [%f]:", minPosInd, minNegInd, poseHistoryBuffer[minPosInd % MAX_HISTORY].header.stamp.toSec(), frameHeaderHistoryBuffer[jjj % MAX_HISTORY].stamp.toSec(), poseHistoryBuffer[minNegInd % MAX_HISTORY].header.stamp.toSec()); }
00554
00555 if (!interpolatePose(poseHistoryBuffer[minPosInd % MAX_HISTORY].pose, poseHistoryBuffer[minPosInd % MAX_HISTORY].header.stamp, poseHistoryBuffer[minNegInd % MAX_HISTORY].pose, poseHistoryBuffer[minNegInd % MAX_HISTORY].header.stamp, tracksFrameInterpolatedPose.pose, frameHeaderHistoryBuffer[jjj % MAX_HISTORY].stamp)) {
00556 if (configData.verboseMode) { ROS_WARN("Pose unable to be interpolated."); }
00557 return false;
00558 } else {
00559 if (configData.verboseMode) { ROS_WARN("Pose was interpolated."); }
00560 }
00561
00562 shiftPose(tracksFrameInterpolatedPose.pose, tracksFrameShiftedPose.pose, extrinsicCalib_P);
00563
00564 tracksFrameShiftedPose.header = tracksFrameInterpolatedPose.header;
00565
00566 main_mutex.lock();
00567 bool updated = updateKeyframePoses(tracksFrameShiftedPose, true);
00568 lastTestedFrame = tracksFrameShiftedPose.header.seq;
00569 if (configData.publishKeyframes) { drawKeyframes(camera_pub, keyframePoses, storedPosesCount); }
00570 main_mutex.unlock();
00571
00572
00573 if (updated) {
00574
00575 main_mutex.lock();
00576 if (configData.clearTriangulations) {
00577 for (unsigned int iii = 0; iii < featureTrackVector.size(); iii++) {
00578 featureTrackVector.at(iii).isTriangulated = false;
00579 }
00580 }
00581 triangulatePoints();
00582 main_mutex.unlock();
00583
00584 }
00585
00586 if (0) { ROS_INFO("Updated.. (%d)", updated); }
00587 frameProcessedCounter++;
00588
00589 }
00590
00591 return true;
00592
00593 }
00594
00595 void videoslamNode::triangulatePoints() {
00596 if (storedPosesCount >= 2) {
00597 vector<unsigned int> triangulatableIndices;
00598 vector<unsigned int> cameraIndices;
00599
00600 for (unsigned int iii = 0; iii < storedPosesCount; iii++) {
00601
00602 cameraIndices.push_back(keyframePoses[iii].header.seq);
00603 }
00604
00605
00606
00607
00608
00609
00610 int minProjections_ = minProjections(configData.pairsForTriangulation);
00611
00612
00613 findTriangulatableTracks(featureTrackVector, triangulatableIndices, cameraIndices, minProjections_);
00614
00615
00616
00617
00618
00619 int minimumlyProjectedTracks = 0;
00620 for (unsigned int zzz = 0; zzz < featureTrackVector.size(); zzz++) {
00621 if (featureTrackVector.at(zzz).locations.size() >= minProjections_) { minimumlyProjectedTracks++; }
00622 }
00623
00624 unsigned int actuallyTriangulated = 0;
00625 if (triangulatableIndices.size() > 0) {
00626 actuallyTriangulated = initialTrackTriangulation(featureTrackVector, triangulatableIndices, configData.cameraData, keyframePoses, storedPosesCount, configData.minSeparation, configData.maxSeparation, configData.pairsForTriangulation, configData.maxStandardDev, configData.maxReprojectionDisparity);
00627 }
00628
00629
00630
00631 if (configData.verboseMode) { ROS_INFO("Keyframe (%d): (%d) points triangulated out of (%d) valid, (%d) potential and (%d) total", keyframePoses[storedPosesCount-1].header.seq, actuallyTriangulated, ((int)triangulatableIndices.size()), minimumlyProjectedTracks, ((int)featureTrackVector.size())); }
00632
00633
00634 }
00635 }
00636
00637 bool videoslamNode::determinePose() {
00638
00639
00640
00641
00642
00643
00644 int idx1, idx2;
00645
00646 bool surrounded = findNearestPoses(idx1, idx2, frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp);
00647
00648
00649
00650
00651
00652 if (frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp.toSec() < poseHistoryBuffer[(poseHistoryCounter-1) % MAX_HISTORY].header.stamp.toSec()) {
00653 if (surrounded == false) ROS_WARN("No surrounding poses exist for tracks message, however, its timestamp is old, so assuming bag is being looped..");
00654 } else {
00655 if (surrounded == true) ROS_WARN("Surrounding poses exist for tracks message, but more recently received pose has very new timestamp, so assuming bag is being looped..");
00656 }
00657
00658 currentPose.header = frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY];
00659 currentPose.header.frame_id = "/world";
00660
00661 if (surrounded) {
00662 interpolatePose(poseHistoryBuffer[idx1 % MAX_HISTORY].pose, poseHistoryBuffer[idx1 % MAX_HISTORY].header.stamp, poseHistoryBuffer[idx2 % MAX_HISTORY].pose, poseHistoryBuffer[idx2 % MAX_HISTORY].header.stamp, currentPose.pose, frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp);
00663 } else {
00664 if (0) { ROS_WARN("No appropriate surrounding frames were found.."); }
00665
00666 if ( (idx1 < 0) || (idx2 < 0) ) {
00667 if ((configData.verboseMode) && (poseHistoryCounter > 1)) {
00668 ROS_ERROR("No pair of indices were able to be found to estimate a position!");
00669 cin.get();
00670 }
00671
00672 if (currentPose.pose.position.x == 9e99) {
00673 return false;
00674 }
00675
00676 } else {
00677 if (configData.verboseMode) { ROS_WARN("Estimating a position, but not based on surrounding poses..."); }
00678 interpolatePose(poseHistoryBuffer[idx1 % MAX_HISTORY].pose, poseHistoryBuffer[idx1 % MAX_HISTORY].header.stamp, poseHistoryBuffer[idx2 % MAX_HISTORY].pose, poseHistoryBuffer[idx2 % MAX_HISTORY].header.stamp, currentPose.pose, frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp);
00679 }
00680
00681
00682
00683 }
00684
00685 savedPose = currentPose;
00686
00687
00688 cv::Mat estimatedPose, t, R, c;
00689 Eigen::Quaternion<double> Q;
00690
00691 convertPoseFormat(currentPose.pose, t, Q);
00692 quaternionToMatrix(Q, R);
00693 composeTransform(R, t, c);
00694
00695
00696
00697
00698
00699
00700 framesProcessed++;
00701
00702 pnpError = -1.0;
00703 pnpInlierProp = -1.0;
00704
00705 main_mutex.lock();
00706
00707 bool res = estimatePoseFromKnownPoints(estimatedPose, configData.cameraData, featureTrackVector, frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].seq, c, 1, configData.pnpIterations, configData.maxReprojectionDisparity, configData.inliersPercentage, &pnpError, &pnpInlierProp, configData.debugTriangulation);
00708 main_mutex.unlock();
00709
00710 predictiveError = configData.maxAllowableError;
00711
00712 if (res) {
00713
00714 pnpSuccesses++;
00715
00716
00717
00718
00719
00720
00721 cv::Mat R_, t_;
00722 Eigen::Quaternion<double> Q_;
00723
00724 decomposeTransform(estimatedPose, R_, t_);
00725 matrixToQuaternion(R_, Q_);
00726 convertPoseFormat(t_, Q_, currentPose.pose);
00727
00728 pnpPose = currentPose;
00729
00730 if (configData.verboseMode) { ROS_INFO("Pose for index (%d) able to be estimated accurately using PnP... (%f, %f, %f)", frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].seq, currentPose.pose.position.x, currentPose.pose.position.y, currentPose.pose.position.z); }
00731
00732 } else {
00733 predictiveError = 9e99;
00734 if (configData.verboseMode) { ROS_WARN("Pose for index (%d) unable to be estimated accurately using PnP", frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].seq); }
00735 }
00736
00737
00738
00739
00740
00741
00742
00743 bundleTransShift = -1.0;
00744 bundleRotShift = -1.0;
00745
00746 usedTriangulations = -1;
00747 pointShift = -1.0;
00748
00749 if ( (configData.adjustmentIterations > 0) && (storedPosesCount >= 2)) {
00750
00751
00752
00753 main_mutex.lock();
00754 if (configData.verboseMode) { ROS_WARN("About to perform <predictiveBundleAdjustment> with (%d) cameras...", storedPosesCount); }
00755
00756 if (configData.writePoses) { std::cout.rdbuf( lStream.rdbuf() ); }
00757 predictiveError = predictiveBundleAdjustment(configData.cameraData, featureTrackVector, keyframePoses, keyframeTypes, storedPosesCount, currentPose, configData.adjustmentIterations, configData.debugSBA, configData.baMode, configData.baStep, &usedTriangulations, &pointShift);
00758 if (configData.writePoses) { std::cout.rdbuf( lBufferOld ); }
00759 main_mutex.unlock();
00760
00761 bundleTransShift = pow(pow(currentPose.pose.position.x-pnpPose.pose.position.x, 2.0) + pow(currentPose.pose.position.y-pnpPose.pose.position.y, 2.0) + pow(currentPose.pose.position.z-pnpPose.pose.position.z, 2.0), 0.5);
00762 bundleRotShift = pow(pow(currentPose.pose.orientation.w-pnpPose.pose.orientation.w, 2.0) + pow(currentPose.pose.orientation.x-pnpPose.pose.orientation.x, 2.0) + pow(currentPose.pose.orientation.y-pnpPose.pose.orientation.y, 2.0) + pow(currentPose.pose.orientation.z-pnpPose.pose.orientation.z, 2.0), 0.5);
00763
00764 main_mutex.lock();
00765 filterNearPoints(featureTrackVector, currentPose.pose.position.x, currentPose.pose.position.y, currentPose.pose.position.z);
00766 main_mutex.unlock();
00767
00768
00769
00770
00771
00772 }
00773
00774 if (configData.verboseMode) {
00775 if (predictiveError > configData.maxAllowableError) {
00776 ROS_INFO("predictiveError = ( PNP-FAIL )");
00777 } else if (predictiveError == -1.0) {
00778 ROS_INFO("predictiveError = ( SBA-FAIL )");
00779
00780 } else if (predictiveError == configData.maxAllowableError) {
00781 ROS_INFO("predictiveError = ( PNP-ONLY )");
00782 } else {
00783 ROS_INFO("predictiveError = ( %8.5f )", predictiveError);
00784 }
00785
00786
00787 }
00788
00789 if ((predictiveError < configData.maxAllowableError) && (predictiveError > -1.0)) {
00790 baAverage *= double(baSuccesses);
00791 dsAverage *= double(baSuccesses);
00792 baAverage += predictiveError;
00793 dsAverage += pow(pow(currentPose.pose.position.x-savedPose.pose.position.x, 2.0)+pow(currentPose.pose.position.y-savedPose.pose.position.y, 2.0)+pow(currentPose.pose.position.z-savedPose.pose.position.z, 2.0),0.5);
00794 baSuccesses++;
00795 baAverage /= double(baSuccesses);
00796 dsAverage /= double(baSuccesses);
00797 }
00798
00799 if ( ( (predictiveError > 0.0) && (predictiveError <= configData.maxAllowableError) ) ) {
00800
00801 return true;
00802
00803 } else {
00804 return false;
00805 }
00806
00807
00808
00809
00810
00811 }
00812
00813 void videoslamNode::publishPoints(ros::Time stamp, unsigned int seq) {
00814
00815 vector<cv::Point3d> testPoints3d;
00816
00817 if (0) { ROS_INFO("About to try and extract 3D points.."); }
00818
00819
00820 getPoints3dFromTracks(featureTrackVector, testPoints3d);
00821
00822
00823
00824
00825
00826
00827 cv::Point3d midPoint(0.0, 0.0, 0.0);
00828 for (unsigned int iii = 0; iii < testPoints3d.size(); iii++) {
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 double x, y, z;
00840 x = testPoints3d.at(iii).x;
00841 y = testPoints3d.at(iii).y;
00842 z = testPoints3d.at(iii).z;
00843
00844 midPoint.x += x / double(testPoints3d.size());
00845 midPoint.y += y / double(testPoints3d.size());
00846 midPoint.z += z / double(testPoints3d.size());
00847
00848 }
00849
00850 if (0) { ROS_INFO("Cloud midPoint = (%f, %f, %f)", midPoint.x, midPoint.y, midPoint.z); }
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867 pcl::PointCloud<pcl::PointXYZ> pointsToPublish;
00868
00869 for (unsigned int iii = 0; iii < testPoints3d.size(); iii++) {
00870 pointsToPublish.push_back(pcl::PointXYZ(testPoints3d.at(iii).x, testPoints3d.at(iii).y, testPoints3d.at(iii).z));
00871 }
00872
00873
00874
00875 if (configData.verboseMode) { ROS_INFO("Publishing (%d) points", ((int)pointsToPublish.size())); }
00876
00877 pcl::toROSMsg(pointsToPublish, pointCloud_message);
00878
00879 pointCloud_message.header.frame_id = "/world";
00880 pointCloud_message.header.stamp = stamp;
00881 pointCloud_message.header.seq = seq;
00882
00883
00884
00885 points_pub.publish(pointCloud_message);
00886 }
00887
00888 void videoslamNode::handle_pose(const geometry_msgs::PoseStamped& pose_msg) {
00889
00890 if (wantsToShutdown) return;
00891
00892
00893
00894 if (configData.terminationTime != -1.0) {
00895
00896 if (pose_msg.header.stamp.toSec() > configData.terminationTime) {
00897
00898 if ( (pose_msg.header.stamp.toSec() < configData.restartTime) || (configData.restartTime == -1.0) ) {
00899
00900 if (!hasTerminatedFeed && !configData.writePoses) {
00901 ROS_ERROR("Terminating feed: incoming poses timestamped after (%f)", configData.terminationTime);
00902 }
00903
00904 hasTerminatedFeed = true;
00905 return;
00906
00907 } else {
00908
00909 if (hasTerminatedFeed && !configData.writePoses) {
00910 ROS_ERROR("Restarting feed: incoming poses timestamped after (%f)", configData.restartTime);
00911 }
00912
00913 hasTerminatedFeed = false;
00914 }
00915
00916
00917 }
00918 }
00919
00920 latestReceivedPoseProcessed = false;
00921
00922 poseHistoryBuffer[poseHistoryCounter % MAX_HISTORY] = pose_msg;
00923 poseHistoryCounter++;
00924
00925 if (updateLocalPoseEstimates()) {
00926 if (0) { ROS_INFO("Successfully updated pose estimates..?"); }
00927 }
00928
00929 latestReceivedPoseProcessed = true;
00930
00931 if (0) { ROS_WARN("frameProcessedCounter = (%d) vs frameHeaderHistoryCounter (%d)", frameProcessedCounter, frameHeaderHistoryCounter); }
00932
00933 }
00934
00935
00936 void videoslamNode::integrateNewTrackMessage(const thermalvis::feature_tracksConstPtr& msg) {
00937
00938
00939
00940 featureTrack blankTrack;
00941
00942 unsigned int addedTracks = 0, addedProjections = 0;
00943
00944 for (unsigned int iii = 0; iii < msg->projection_count; iii++) {
00945
00946
00947 int trackPos = findTrackPosition(featureTrackVector, msg->indices[iii]);
00948
00949
00950
00951 if (trackPos == -1) {
00952
00953
00954 unsigned int jjj = 0;
00955
00956 if (featureTrackVector.size() > 0) {
00957 while (featureTrackVector.at(jjj).trackIndex < msg->indices[iii]) {
00958 jjj++;
00959
00960 if (jjj >= featureTrackVector.size()) {
00961 break;
00962 }
00963
00964 }
00965 }
00966
00967 blankTrack.trackIndex = msg->indices[iii];
00968 featureTrackVector.insert(featureTrackVector.begin()+jjj, blankTrack);
00969 addedTracks++;
00970
00971 trackPos = jjj;
00972
00973 }
00974
00975
00976
00977
00978 bool alreadyAdded = false;
00979 for (unsigned int jjj = 0; jjj < featureTrackVector.at(trackPos).locations.size(); jjj++) {
00980
00981 if (featureTrackVector.at(trackPos).locations.at(jjj).imageIndex == ((int) msg->cameras.at(iii))) {
00982 alreadyAdded = true;
00983
00984 break;
00985 }
00986
00987 }
00988
00989 if (!alreadyAdded) {
00990 cv::Point2f proj(((float) msg->projections_x.at(iii)), ((float) msg->projections_y.at(iii)));
00991 indexedFeature newFeature(msg->cameras.at(iii), proj);
00992
00993
00994 featureTrackVector.at(trackPos).addFeature(newFeature);
00995 addedProjections++;
00996
00997
00998 }
00999
01000 }
01001
01002 if (0) { ROS_INFO("Integrating (%d), Added (%d) new tracks and (%d) new projections", msg->header.seq, addedTracks, addedProjections); }
01003
01004
01005
01006 if (configData.debugMode) {
01007 cv::Mat trackMatrix;
01008
01009 if (createTrackMatrix(featureTrackVector, trackMatrix)) {
01010 cv::imshow("trackMatrix", trackMatrix);
01011 cv::waitKey(1);
01012 }
01013 }
01014
01015 }
01016
01017 void videoslamNode::handle_tracks(const thermalvis::feature_tracksConstPtr& msg) {
01018
01019 if ((msg->header.seq % 4) != 0) {
01020
01021 }
01022
01023
01024 if (wantsToShutdown) return;
01025
01026 if ((configData.evaluateParameters > 0) && (msg->header.seq > configData.evaluateParameters)) {
01027
01028 ROS_ERROR("Reached evaluation frame (%d/%d), shutting down...", msg->header.seq, configData.evaluateParameters);
01029 ROS_WARN("Summary(1): (%d, %d, %d, %d)", framesArrived, framesProcessed, pnpSuccesses, baSuccesses);
01030 ROS_WARN("Summary(2): (%f, %f, %f, %f)", double(pnpSuccesses)/double(framesProcessed), double(baSuccesses)/double(framesProcessed), baAverage, dsAverage);
01031
01032 wantsToShutdown = true;
01033 mySigintHandler(1);
01034
01035 return;
01036 }
01037
01038 if (!infoProcessed) {
01039 return;
01040 }
01041
01042 framesArrived++;
01043
01044
01045
01046 if (msg->indices.size() == 0) {
01047 ROS_WARN("No tracks in message.");
01048 return;
01049 }
01050
01051 latestTracksTime = msg->header.stamp.toSec();
01052
01053
01054 if (configData.verboseMode) { ROS_WARN("Handling new tracks seq (%d) at (%f)", msg->header.seq, latestTracksTime); }
01055
01056 frameHeaderHistoryBuffer[frameHeaderHistoryCounter % MAX_HISTORY] = msg->header;
01057 frameHeaderHistoryCounter++;
01058
01059 main_mutex.lock();
01060 integrateNewTrackMessage(msg);
01061 main_mutex.unlock();
01062
01063
01064
01065 main_mutex.lock();
01066
01067 if (configData.trimFeatureTracks) trimFeatureTrackVector();
01068
01069 main_mutex.unlock();
01070
01071 if (determinePose()) {
01072
01073
01074
01075 publishPose();
01076
01077 if (configData.publishPoints) { publishPoints(currentPose.header.stamp, currentPose.header.seq); }
01078
01079 double elapsed = latestTracksTime - poseHistoryBuffer[(poseHistoryCounter-1) % MAX_HISTORY].header.stamp.toSec();
01080
01081
01082
01083 if (elapsed > configData.maxPoseDelay) {
01084
01085 if (configData.verboseMode) { ROS_INFO("Considering video-based pose estimate as a keyframe..."); }
01086
01087
01088 main_mutex.lock();
01089 bool updated = updateKeyframePoses(currentPose, false);
01090 lastTestedFrame = currentPose.header.seq;
01091 if (configData.publishKeyframes) { drawKeyframes(camera_pub, keyframePoses, storedPosesCount); }
01092 main_mutex.unlock();
01093
01094 if (updated) {
01095
01096 main_mutex.lock();
01097 if (configData.clearTriangulations) {
01098 for (unsigned int iii = 0; iii < featureTrackVector.size(); iii++) {
01099 featureTrackVector.at(iii).isTriangulated = false;
01100 }
01101 }
01102 triangulatePoints();
01103 main_mutex.unlock();
01104
01105 }
01106
01107 }
01108
01109
01110 }
01111
01112
01113
01114 }
01115
01116 void videoslamNode::publishPose() {
01117
01118 thermalvis::pose_confidence confidence_msg;
01119 confidence_msg.source = configData.flowSource;
01120 confidence_msg.header = frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY];
01121
01122 pose_pub.publish(currentPose);
01123 if (configData.verboseMode) { ROS_INFO("Publishing currentPose (%d) of (%f, %f, %f)", currentPose.header.seq, currentPose.pose.position.x, currentPose.pose.position.y, currentPose.pose.position.z); }
01124
01125 confidence_msg.metric_count = 7;
01126
01127
01128
01129
01130 if (predictiveError == configData.maxAllowableError) {
01131 confidence_msg.scores.push_back(-1.0);
01132
01133 } else {
01134 confidence_msg.scores.push_back(predictiveError);
01135
01136 }
01137
01138 confidence_msg.scores.push_back(bundleTransShift);
01139 confidence_msg.scores.push_back(bundleRotShift);
01140 confidence_msg.scores.push_back(float(usedTriangulations));
01141 confidence_msg.scores.push_back(pointShift);
01142 confidence_msg.scores.push_back(pnpError);
01143 confidence_msg.scores.push_back(pnpInlierProp);
01144
01145
01146 confidence_pub.publish(confidence_msg);
01147
01148 if (configData.writePoses) {
01149
01150 printf("%f %d %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f %8.5f", currentPose.header.stamp.toSec(), currentPose.header.seq, currentPose.pose.position.x, currentPose.pose.position.y, currentPose.pose.position.z, currentPose.pose.orientation.w, currentPose.pose.orientation.x, currentPose.pose.orientation.y, currentPose.pose.orientation.z);
01151
01152 for (unsigned int iii = 0; iii < confidence_msg.metric_count; iii++) {
01153 printf(" %8.5f", confidence_msg.scores.at(iii));
01154 }
01155
01156 printf("\n");
01157
01158 }
01159
01160 }
01161
01162 void videoslamNode::main_loop(const ros::TimerEvent& event) {
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173 }
01174
01175 void videoslamNode::handle_info(const sensor_msgs::CameraInfoConstPtr& info_msg) {
01176
01177 if (wantsToShutdown) return;
01178
01179 if (!infoProcessed) {
01180
01181 ROS_INFO("Handling camera info...");
01182
01183 try {
01184
01185 configData.cameraData.K = cv::Mat::eye(3, 3, CV_64FC1);
01186
01187 for (unsigned int mmm = 0; mmm < 3; mmm++) {
01188 for (unsigned int nnn = 0; nnn < 3; nnn++) {
01189 configData.cameraData.K.at<double>(mmm, nnn) = info_msg->K[3*mmm + nnn];
01190 }
01191 }
01192
01193 cout << configData.cameraData.K << endl;
01194
01195 configData.cameraData.K_inv = configData.cameraData.K.inv();
01196
01197 configData.cameraData.cameraSize.width = info_msg->width;
01198 configData.cameraData.cameraSize.height = info_msg->height;
01199
01200 unsigned int maxDistortionIndex;
01201
01202 if (info_msg->distortion_model == "rational_polynomial") {
01203 maxDistortionIndex = 8;
01204 } else {
01205 maxDistortionIndex = 5;
01206 }
01207
01208 configData.cameraData.distCoeffs = cv::Mat::zeros(1, maxDistortionIndex, CV_64FC1);
01209 configData.cameraData.blankCoeffs = cv::Mat::zeros(1, maxDistortionIndex, CV_64FC1);
01210
01211 for (unsigned int iii = 0; iii < maxDistortionIndex; iii++) {
01212 configData.cameraData.distCoeffs.at<double>(0, iii) = info_msg->D[iii];
01213 }
01214
01215 cout << "Distortion: " << configData.cameraData.distCoeffs << endl;
01216
01217 configData.cameraData.newCamMat = cv::Mat::zeros(3, 3, CV_64FC1);
01218
01219 cv::Rect* validPixROI = 0;
01220
01221 double alpha = 0.00;
01222 bool centerPrincipalPoint = true;
01223
01224 configData.cameraData.newCamMat = getOptimalNewCameraMatrix(configData.cameraData.K, configData.cameraData.distCoeffs, configData.cameraData.cameraSize, alpha, configData.cameraData.cameraSize, validPixROI, centerPrincipalPoint);
01225
01226 cout << configData.cameraData.newCamMat << endl;
01227
01228 infoProcessed = true;
01229
01230 } catch (...) {
01231 ROS_ERROR("Some failure in reading in the camera parameters...");
01232 }
01233
01234 ROS_INFO("Camera information processed.");
01235
01236 }
01237
01238 }
01239
01240 void videoslamNode::serverCallback(thermalvis::videoslamConfig &config, uint32_t level) {
01241
01242 configData.cameraLatency = config.cameraLatency;
01243 configData.adjustmentFrames = config.adjustmentFrames;
01244 configData.debugMode = config.debugMode;
01245 configData.pairsForTriangulation = config.pairsForTriangulation;
01246 configData.dataTimeout = config.dataTimeout;
01247 configData.adjustmentIterations = config.adjustmentIterations;
01248 configData.verboseMode = config.verboseMode;
01249 configData.maxDistance = config.maxDistance;
01250 configData.minSeparation = config.minSeparation;
01251 configData.maxSeparation = config.maxSeparation;
01252 configData.maxStandardDev = config.maxStandardDev;
01253 configData.debugSBA = config.debugSBA;
01254 configData.debugTriangulation = config.debugTriangulation;
01255 configData.trimFeatureTracks = config.trimFeatureTracks;
01256 configData.baMode = config.baMode;
01257 configData.baStep = config.baStep;
01258 configData.maxAllowableError = config.maxAllowableError;
01259 configData.pnpIterations = config.pnpIterations;
01260 configData.inliersPercentage = config.inliersPercentage;
01261
01262 configData.maxReprojectionDisparity = config.maxReprojectionDisparity;
01263
01264
01265 }
01266
01267 videoslamNode::videoslamNode(ros::NodeHandle& nh, videoslamData startupData) {
01268
01269 ROS_INFO("X..");
01270
01271 configData = startupData;
01272
01273
01274
01275 if (configData.verboseMode) { ROS_INFO("Initializing node.."); }
01276
01277 sprintf(nodeName, "%s", ros::this_node::getName().c_str());
01278
01279 if (configData.writePoses) {
01280
01281 ROS_WARN("writePoses == true, therefore suppressing cout messages from SBA libraries..");
01282 lStream.open( "garbage.txt" );
01283 lBufferOld = std::cout.rdbuf();
01284 }
01285
01286
01287 framesArrived = 0;
01288 framesProcessed = 0;
01289 pnpSuccesses = 0;
01290 baSuccesses = 0;
01291 baAverage = 0.0;
01292 dsAverage = 0.0;
01293
01294 hasTerminatedFeed = false;
01295
01296 latestReceivedPoseProcessed = false;
01297
01298 currentPose.pose.position.x = 9e99;
01299
01300 extrinsicCalib_R = cv::Mat::eye(3,3,CV_64FC1);
01301 extrinsicCalib_T = cv::Mat::zeros(3,1,CV_64FC1);
01302
01303 if (configData.extrinsicsFile != "extrinsicsFile") {
01304
01305 if (configData.verboseMode) { ROS_INFO("Reading extrinsics file (%s)...", configData.extrinsicsFile.c_str()); }
01306
01307 try {
01308 cv::FileStorage fs(configData.extrinsicsFile, cv::FileStorage::READ);
01309 fs["R1"] >> extrinsicCalib_R;
01310 fs["T1"] >> extrinsicCalib_T;
01311 fs.release();
01312
01313 ROS_INFO("Extrinsics data read.");
01314
01315 if (extrinsicCalib_R.empty()){
01316 ROS_ERROR("Extrinsics file (%s) invalid! Please check path and filecontent...", configData.extrinsicsFile.c_str());
01317 wantsToShutdown = true;
01318 }
01319
01320 } catch (int e) {
01321 ROS_ERROR("Some failure in reading in the extrinsics (%s).", configData.extrinsicsFile.c_str());
01322 wantsToShutdown = true;
01323 }
01324 } else {
01325 if (configData.verboseMode) { ROS_INFO("No extrinsics provided."); }
01326 }
01327
01328
01329 composeTransform(extrinsicCalib_R, extrinsicCalib_T, extrinsicCalib_P);
01330
01331 if (configData.verboseMode) { ROS_INFO("Transforms complete."); }
01332
01333
01334
01335
01336
01337 frameProcessedCounter = 0;
01338 frameHeaderHistoryCounter = 0;
01339 poseHistoryCounter = 0;
01340
01341
01342
01343 decimation = DEFAULT_DRAWGRAPH_DECIMATION;
01344 bicolor = DEFAULT_DRAWGRAPH_BICOLOR;
01345
01346 distanceTravelled = 0.0;
01347
01348 storedPosesCount = 0;
01349
01350 sys.verbose = 0;
01351
01352 eye4 = cv::Mat::eye(4, 4, CV_64FC1);
01353
01354 lastTestedFrame = -1;
01355
01356 if (configData.verboseMode) { ROS_INFO("Initializing topics.."); }
01357
01358
01359
01360
01361
01362
01363
01364 char camera_pub_name[256];
01365 sprintf(camera_pub_name, "/thermalvis%s/cameras", nodeName);
01366 camera_pub = nh.advertise<visualization_msgs::Marker>( camera_pub_name, 1 );
01367
01368 char points_pub_name[256];
01369 sprintf(points_pub_name, "/thermalvis%s/points", nodeName);
01370 points_pub = nh.advertise<sensor_msgs::PointCloud2>(points_pub_name, 1);
01371
01372 char confidence_pub_name[256];
01373 sprintf(confidence_pub_name, "/thermalvis%s/confidence", nodeName);
01374
01375
01376
01377 ROS_INFO("Publishing confidence data at (%s)", confidence_pub_name);
01378 ros::AdvertiseOptions op = ros::AdvertiseOptions::create<thermalvis::pose_confidence>(confidence_pub_name, 1, &connected, &disconnected, ros::VoidPtr(), NULL);
01379 op.has_header = false;
01380 confidence_pub = nh.advertise(op);
01381
01382 publishPoints(ros::Time::now(), 0);
01383
01384 ROS_INFO("Setting up node.");
01385
01386 infoProcessed = false;
01387
01388 std::string topic_tracks = configData.flowSource + "tracks";
01389 ROS_INFO("Connecting to tracks topic. %s", topic_tracks.c_str());
01390 tracks_sub = nh.subscribe<thermalvis::feature_tracks>(topic_tracks, 1, &videoslamNode::handle_tracks, this);
01391
01392 std::string topic_info = configData.flowSource + "camera_info";
01393 ROS_INFO("Connecting to camera_info. %s", topic_info.c_str());
01394 info_sub = nh.subscribe<sensor_msgs::CameraInfo>(topic_info, 1, &videoslamNode::handle_info, this);
01395
01396 std::string topic_pose = configData.mapperSource + "pose";
01397 ROS_INFO("Connecting to pose topic. %s", topic_pose.c_str());
01398 pose_sub = nh.subscribe(topic_pose, 1, &videoslamNode::handle_pose, this);
01399
01400 ROS_INFO("Node setup.");
01401
01402 sprintf(pose_pub_name, "/thermalvis%s/pose", nodeName);
01403 ROS_INFO("Configuring pose topic. %s", pose_pub_name);
01404
01405 currentPose.header.frame_id = "/world";
01406
01407
01408
01409
01410 ros::AdvertiseOptions op1 = ros::AdvertiseOptions::create<geometry_msgs::PoseStamped>(pose_pub_name, 1, &connected, &disconnected, ros::VoidPtr(), NULL);
01411 op1.has_header = false;
01412 pose_pub = nh.advertise(op1);
01413
01414 timer = nh.createTimer(ros::Duration(0.05), &videoslamNode::main_loop, this);
01415
01416 ROS_INFO("Establishing server callback...");
01417 f = boost::bind (&videoslamNode::serverCallback, this, _1, _2);
01418 server.setCallback (f);
01419
01420 }