videoslam.cpp
Go to the documentation of this file.
00001 
00005 #include "videoslam.hpp"
00006 
00007 struct timeval cycle_timer;
00008 //double elapsedTime;
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         //ros::Rate loop_rate(25);
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         //ros::waitForShutdown();
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         //nh.param<bool>("evaluationMode", evaluationMode, false);
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"); // /pose
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         //main_mutex.lock();
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                         //printf("%s << featureTrackVector.at(%d).locations.at(%d).imageIndex = (%d) vs (%d)\n", __FUNCTION__, iii, jjj, featureTrackVector.at(iii).locations.at(jjj).imageIndex, seq);
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         //main_mutex.unlock();
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         // First, some kind of check to make sure that the tracks/connections for this frame are decent..
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         } /* else if (fromICP) {
00182                 
00183                 for (unsigned int iii = 0; iii < storedPosesCount; iii++) {
00184                         
00185                         if (!keyframeTypes[iii]) {
00186                         
00187                                 for (unsigned int jjj = iii; jjj < storedPosesCount-1; jjj++) {
00188                                         keyframePoses[jjj] = keyframePoses[jjj+1];
00189                                         keyframeTypes[jjj] = keyframeTypes[jjj+1];
00190                                 }
00191                                 
00192                                 storedPosesCount--;
00193                                 
00194                                 if (configData.verboseMode) { ROS_WARN("Appending most recent frame (%d) to keyframes to replace video-based frame", pose_msg.header.seq); }
00195                                 keyframePoses[storedPosesCount] = pose_msg;
00196                                 keyframeTypes[storedPosesCount] = fromICP;
00197                                 storedPosesCount++;
00198                                 return true;
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         // Otherwise, need to find the least informative... (want to include newest, too!)
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         // ROS_ERROR("Features trimmed for cameras below (%d)", newestSafeIndex);
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         //ROS_ERROR("featureTrackVector.size() = (%d)", featureTrackVector.size());
00347 }
00348 
00349 void shiftPose(const geometry_msgs::Pose& pose_src, geometry_msgs::Pose& pose_dst, cv::Mat transformation) {
00350         
00351         //ROS_ERROR("Transforming from (%f, %f, %f) (%f, %f, %f, %f)...", pose_src.position.x, pose_src.position.y, pose_src.position.z, pose_src.orientation.w, pose_src.orientation.x, pose_src.orientation.y, pose_src.orientation.z);
00352         
00353         // pose_dst = pose_src;
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         //cout << "transformation = " << transformation << endl;
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         //ROS_ERROR("Transforming _to_ (%f, %f, %f) (%f, %f, %f, %f)...", pose_dst.position.x, pose_dst.position.y, pose_dst.position.z, pose_dst.orientation.w, pose_dst.orientation.x, pose_dst.orientation.y, pose_dst.orientation.z);
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         //ROS_WARN("Searching for time (%f) with a total of (%d) poses to check", targetTime.toSec(), poseHistoryCounter);
00437         
00438         for (int iii = 0; iii < min(int(poseHistoryCounter), MAX_HISTORY); iii++) {
00439                 
00440                 //ROS_WARN("Testing time (%f) with (%f)", targetTime.toSec(), poseHistoryBuffer[iii % MAX_HISTORY].header.stamp.toSec());
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                 //ROS_WARN("diff = (%f)", diff);
00449                 
00450                 //ROS_INFO("diff = (%f); (%f & (%d)%f)", diff, latestTracksTime, iii, poseHistoryBuffer[iii % MAX_HISTORY].header.stamp.toSec());
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                                 //ROS_INFO("updating pos index 1: (%d)", iii);
00459                                 posAssigned++;
00460                         } else if (posAssigned < 2) {
00461                                 twoPosDiff = abs(diff);
00462                                 twoPosInd = iii;
00463                                 posAssigned++;
00464                                 //ROS_INFO("updating pos index 2: (%d)", iii);
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                                 //ROS_INFO("updating neg indices");
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                         //ROS_INFO("updating ALL indices");
00489                 }
00490                 
00491         }
00492         
00493         if ( (minPosInd >= 0) && (minNegInd >= 0) ) { // && (minPosDiff <= twoNegDiff) && (minNegDiff <= twoPosDiff)
00494                 
00495                 index1 = minPosInd;
00496                 index2 = minNegInd;
00497                 
00498                 //ROS_WARN("minPosDiff = (%f), twoPosDiff = (%f), minNegDiff = (%f), twoNegDiff = (%f)", minPosDiff, twoPosDiff, minNegDiff, twoNegDiff);
00499                 
00500                 return true;
00501                  
00502         } else {
00503                 
00504                 //ROS_WARN("Entering non-surrounded segment...");
00505                 
00506                 if (minPosDiff >= twoNegDiff) {
00507                         
00508                         index1 = minNegInd;
00509                         index2 = twoNegInd;
00510                         //ROS_WARN("Two negatives... (%d, %d)", index1, index2);
00511                 } else if (minNegDiff >= twoPosDiff) {
00512                         
00513                         index1 = twoPosInd;
00514                         index2 = minPosInd;
00515                         //ROS_WARN("Two positives... (%d, %d)", index1, index2);
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         //for (unsigned int jjj = max(frameProcessedCounter, int(frameHeaderHistoryCounter)-MAX_HISTORY+1); jjj < frameHeaderHistoryCounter; jjj++) { 
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                         // ROS_INFO("Camera indices to consider includes [%d] : (%u)", iii, keyframePoses[iii].header.seq);
00602                         cameraIndices.push_back(keyframePoses[iii].header.seq);
00603                 }
00604         
00605                 // ROS_INFO("Finding triangulatable tracks with latest frame of (%d)", keyframePoses[storedPosesCount-1].header.seq);
00606                 //main_mutex.lock();
00607                 
00608                 //maxPairs = itriangle(minProjections-1);
00609                 
00610                 int minProjections_ = minProjections(configData.pairsForTriangulation);
00611                 
00612                 //unsigned int minAppearances = triangle(configData.pairsForTriangulation-1);
00613                 findTriangulatableTracks(featureTrackVector, triangulatableIndices, cameraIndices, minProjections_);
00614                 //findTriangulatableTracks3(featureTrackVector, triangulatableIndices, keyframePoses[storedPosesCount-1].header.seq, configData.pairsForTriangulation);
00615                 
00616                 
00617                 // unsigned int triangulatableCount = ((int)triangulatableIndices.size());
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                 //main_mutex.unlock();
00634         }
00635 }
00636 
00637 bool videoslamNode::determinePose() {
00638         
00639         // TO PUBLISH POSE FOR LATEST RECEIVED TRACKS
00640                 // MAY NEED TO EXTRAPOLATE IF THESE TRACKS POSES HAVE NOT BEEN INTERPOLATED
00641                 
00642         // if (configData.verboseMode) { ROS_INFO("<%s> entered..", __FUNCTION__); } // , frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp.toSec(), poseHistoryBuffer[(poseHistoryCounter-1) % MAX_HISTORY].header.stamp.toSec());
00643         
00644         int idx1, idx2;
00645         
00646         bool surrounded = findNearestPoses(idx1, idx2, frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].stamp);
00647         
00648         //ROS_INFO("Found indices (%d, %d) : (%f, %f)", idx1, idx2, poseHistoryBuffer[idx1 % MAX_HISTORY].header.stamp.toSec(), poseHistoryBuffer[idx2 % MAX_HISTORY].header.stamp.toSec());
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                 // Just use the previous "currentPose" as the best estimate for the current one..
00682                         
00683         }
00684         
00685         savedPose = currentPose;
00686         
00687         // Convert: currentPose.pose into usable format
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         // ROS_ERROR("About to attempt to estimate pose for index (%d) using PnP", frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].seq);
00697         
00698         // int minProjections_ = minProjections(configData.pairsForTriangulation);
00699         
00700         framesProcessed++;
00701         
00702         pnpError = -1.0;
00703         pnpInlierProp = -1.0;
00704         
00705         main_mutex.lock();
00706         //ROS_WARN("about to <estimatePoseFromKnownPoints> with seq = (%d), lastTestedFrame = (%d), latestHandledTracks = (%d)", frameHeaderHistoryBuffer[(frameHeaderHistoryCounter-1) % MAX_HISTORY].seq, lastTestedFrame, latestHandledTracks);
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                 //cout << "guide = " << c << endl;
00719                 //cout << "estimated = " << estimatedPose << endl << endl;
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         //ROS_ERROR("Base pose #1 (%f, %f, %f) [%f, %f, %f, %f]", poseHistoryBuffer[idx1 % MAX_HISTORY].pose.position.x, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.position.y, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.position.z, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.orientation.w, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.orientation.x, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.orientation.y, poseHistoryBuffer[idx1 % MAX_HISTORY].pose.orientation.z);
00739         //ROS_ERROR("Base pose #2 (%f, %f, %f) [%f, %f, %f, %f]", poseHistoryBuffer[idx2 % MAX_HISTORY].pose.position.x, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.position.y, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.position.z, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.orientation.w, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.orientation.x, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.orientation.y, poseHistoryBuffer[idx2 % MAX_HISTORY].pose.orientation.z);
00740         //ROS_ERROR("About to publish pose of (%f, %f, %f) [%f, %f, %f, %f]", 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);
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                 //ROS_INFO("currentPose.seq = (%d); pos = (%f, %f, %f), q = (%f, %f, %f, %f)", 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);
00751 
00752                 // ROS_INFO("Have (%d) stored poses.", storedPosesCount);
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                 //odometryBundleAdjustment(configData.cameraData, featureTrackVector, keyframePoses, storedPosesCount, configData.adjustmentIterations, configData.debugSBA);
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) ) ) { //   || (configData.adjustmentIterations == 0)
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 //void videoslamNode::publishPoints(const geometry_msgs::PoseStamped& pose_msg) {
00815         vector<cv::Point3d> testPoints3d;
00816         
00817         if (0) { ROS_INFO("About to try and extract 3D points.."); }
00818         
00819         //main_mutex.lock();
00820         getPoints3dFromTracks(featureTrackVector, testPoints3d);
00821         //main_mutex.unlock();
00822         
00823         //transformPoints(testPoints3d, 4);
00824         //transformPoints(testPoints3d, configData.transformationCode);
00825         
00826         
00827         cv::Point3d midPoint(0.0, 0.0, 0.0);
00828         for (unsigned int iii = 0; iii < testPoints3d.size(); iii++) {
00829                 //pointsToPublish.push_back(pcl::PointXYZ(testPoints3d.at(iii).x, testPoints3d.at(iii).y, testPoints3d.at(iii).z));
00830                 
00831                 /*
00832                 testPoints3d.at(iii).x = testPoints3d.at(iii).y;
00833                 testPoints3d.at(iii).y = 3.0 - testPoints3d.at(iii).x;
00834                 testPoints3d.at(iii).z = -testPoints3d.at(iii).z;
00835                 */
00836                 
00837                 // ROS_INFO("Point(%d) = (%f, %f, %f)", iii, testPoints3d.at(iii).x,testPoints3d.at(iii).y, testPoints3d.at(iii).z);
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         sys.tracks.clear();
00854         sys.nodes.clear();
00855         
00856         SysSBA sys_temp;
00857         addPointsToSBA(sys_temp, testPoints3d);
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         //pointsToPublish.push_back(pcl::PointXYZ(configData.x, configData.y, configData.z));
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; // pose_msg.header.stamp;
00881         pointCloud_message.header.seq = seq; // pose_msg.header.seq;
00882         
00883         //ROS_ERROR("pointCloud_message.size() = (%d, %d)", pointCloud_message.height, pointCloud_message.width);
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         //if (configData.verboseMode) { ROS_WARN("Handling mapper pose (%d) at (%f)", pose_msg.header.seq, pose_msg.header.stamp.toSec()); }
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         //ROS_WARN("Entered <%s>", __FUNCTION__);
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                 //ROS_WARN("Searching for track index of (%d)..", msg->indices[iii]);
00947                 int trackPos = findTrackPosition(featureTrackVector, msg->indices[iii]);
00948                 
00949                 //ROS_WARN("For projection (%d), found track (%d) at vector position (%d)", ((int)iii), ((int)msg->indices[iii]), trackPos);
00950                 
00951                 if (trackPos == -1) {
00952                         
00953                         // Put the track in, but at the correct spot..
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                 //ROS_INFO("Got here - position now (%d).", trackPos);
00976                 
00977                 // Now you have the track in place for this projection...
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                                 //ROS_INFO("Point already added...");
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                         //ROS_INFO("Adding point...");
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         //checkConnectivity(msg->header.seq);
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                 //return;
01021         }
01022         
01023         
01024         if (wantsToShutdown) return;
01025         
01026         if ((configData.evaluateParameters > 0) && (msg->header.seq > configData.evaluateParameters)) {
01027                 // print summary
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         //latestHandledTracks = msg->header.seq;
01064         
01065         main_mutex.lock();
01066         //ROS_INFO("[pre-trimming] featureTrackVector.size() = (%d)", featureTrackVector.size());
01067         if (configData.trimFeatureTracks) trimFeatureTrackVector(); 
01068         //ROS_INFO("[post-trimming] featureTrackVector.size() = (%d)", featureTrackVector.size());
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                 //ROS_INFO("elapsed = (%f) vs (%f) & (%f)", elapsed, latestTracksTime, poseHistoryBuffer[(poseHistoryCounter-1) % MAX_HISTORY].header.stamp.toSec());
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         // First will publish the PnP convergence error
01128         
01129         // Second will publish the SBA convergence error (if any)
01130         if (predictiveError == configData.maxAllowableError) {
01131                 confidence_msg.scores.push_back(-1.0);
01132                 //confidence_msg.data = 0.0;    // This means SBA failed, so PnP estimate only
01133         } else {
01134                 confidence_msg.scores.push_back(predictiveError);
01135                 //confidence_msg.data = 1.0 - min(predictiveError/3.0,1.0);
01136         }
01137         
01138         confidence_msg.scores.push_back(bundleTransShift);
01139         confidence_msg.scores.push_back(bundleRotShift);
01140         confidence_msg.scores.push_back(float(usedTriangulations)); // 4th - not very useful...
01141         confidence_msg.scores.push_back(pointShift);
01142         confidence_msg.scores.push_back(pnpError);
01143         confidence_msg.scores.push_back(pnpInlierProp);
01144         
01145         //confidence_msg.header = currentPose.header;
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         // main_mutex.lock();
01165         // main_mutex.unlock();
01166         
01167         // ROS_INFO("Entered main loop...");
01168         
01169         // addFixedCamera(display_sys, configData.cameraData, eye4);
01170                         
01171         // pose_pub.publish(currentPose);
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 { /*if (info_msg->distortion_model == "plumb_bob") {*/
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 (...) /*(sensor_msgs::CvBridgeException& e)*/ {
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                 // http://stackoverflow.com/questions/8478851/suppressing-cout-output-with-in-a-function
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         //matrixToQuaternion(extrinsicCalib_R, extrinsicCalib_quat);
01329         composeTransform(extrinsicCalib_R, extrinsicCalib_T, extrinsicCalib_P);
01330         
01331         if (configData.verboseMode) { ROS_INFO("Transforms complete."); }
01332         
01333         // To Apply
01334         // actualThermal_quat = extrinsicCalib_quat * virtualDepth_quat;
01335         // actualThermal_P = virtualDepth_P * extrinsicCalib_P;
01336         
01337         frameProcessedCounter = 0;
01338         frameHeaderHistoryCounter = 0;
01339         poseHistoryCounter = 0;
01340         
01341         //latestHandledTracks = -1;
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         char path_pub_name[256];
01360         sprintf(path_pub_name, "/thermalvis%s/path", nodeName);
01361         path_pub = nh.advertise<visualization_msgs::Marker>( path_pub_name, 1 );
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         //confidence_pub  = nh.advertise<std_msgs::Float32>(confidence_pub_name, 1);
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"; //pose_pub_name;
01406         
01407         //pose_pub = nh.advertise<geometry_msgs::PoseStamped>(pose_pub_name, 1);
01408         //pose_pub = nh.advertise(op);
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 }


thermalvis
Author(s): Stephen Vidas
autogenerated on Sun Jan 5 2014 11:38:45