00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 #include <cpl_visual_features/motion/feature_tracker.h>
00036 #include <cpl_visual_features/motion/flow_types.h>
00037 #include <opencv2/imgproc/imgproc.hpp>
00038 #include <opencv2/video/video.hpp>
00039 #include <ros/ros.h>
00040 
00041 #define DISPLAY_TRACKER_OUTPUT 1
00042 #ifdef DISPLAY_TRACKER_OUTPUT
00043 #include <opencv2/highgui/highgui.hpp>
00044 #endif // DISPLAY_TRACKER_OUTPUT
00045 namespace cpl_visual_features
00046 {
00047 
00048 FeatureTracker::FeatureTracker(std::string name, double hessian_thresh,
00049                                int num_octaves, int num_layers, bool extended,
00050                                bool upright, bool use_fast) :
00051     surf_(hessian_thresh, num_octaves, num_layers, extended, upright),
00052     initialized_(false), ratio_threshold_(0.5), window_name_(name),
00053     min_flow_thresh_(0), max_corners_(500), klt_corner_thresh_(0.3),
00054     klt_corner_min_dist_(2), use_fast_(false)
00055 {
00056   prev_keypoints_.clear();
00057   cur_keypoints_.clear();
00058   prev_descriptors_.clear();
00059   cur_descriptors_.clear();
00060 }
00061 
00062 
00063 
00064 
00065 
00066 void FeatureTracker::initTracks(cv::Mat& frame)
00067 {
00068   updateCurrentDescriptors(frame, cv::Mat());
00069   prev_keypoints_ = cur_keypoints_;
00070   prev_descriptors_ = cur_descriptors_;
00071   initialized_ = true;
00072 }
00073 
00074 AffineFlowMeasures FeatureTracker::updateTracksLK(cv::Mat& cur_frame,
00075                                                   cv::Mat& prev_frame)
00076 {
00077   AffineFlowMeasures sparse_flow;
00078   std::vector<cv::Point2f> prev_points;
00079   std::vector<cv::Point2f> new_points;
00080   ROS_INFO_STREAM("max_corners: " << max_corners_);
00081   ROS_INFO_STREAM("quality_level: " << klt_corner_thresh_);
00082   ROS_INFO_STREAM("min_distance: " << klt_corner_min_dist_);
00083   cv::goodFeaturesToTrack(prev_frame, prev_points, max_corners_,
00084                           klt_corner_thresh_, klt_corner_min_dist_);
00085   ROS_INFO_STREAM("Found " << prev_points.size() << " corners.");
00086   std::vector<uchar> status;
00087   std::vector<float> err;
00088   cv::calcOpticalFlowPyrLK(prev_frame, cur_frame, prev_points, new_points,
00089                            status, err);
00090   int moving_points = 0;
00091   for (unsigned int i = 0; i < prev_points.size(); i++)
00092   {
00093     if (! status[i]) continue;
00094     int dx = prev_points[i].x - new_points[i].x;
00095     int dy = prev_points[i].y - new_points[i].y;
00096     sparse_flow.push_back(AffineFlowMeasure(new_points[i].x, new_points[i].y,
00097                                             dx, dy));
00098     if (abs(sparse_flow[i].u) + abs(sparse_flow[i].v) > min_flow_thresh_)
00099       moving_points++;
00100   }
00101   ROS_INFO_STREAM(window_name_ << ": num moving points: " << moving_points);
00102 
00103 #ifdef DISPLAY_TRACKER_OUTPUT
00104   cv::Mat display_cur_frame(cur_frame.rows, cur_frame.cols, CV_8UC3);;
00105   cv::cvtColor(cur_frame, display_cur_frame, CV_GRAY2BGR);
00106   for (unsigned int i = 0; i < sparse_flow.size(); i++)
00107   {
00108     if (abs(sparse_flow[i].u) + abs(sparse_flow[i].v) > min_flow_thresh_)
00109     {
00110       ROS_DEBUG_STREAM("Point is moving (" << sparse_flow[i].u << ", "
00111                        << sparse_flow[i].v << ")");
00112       cv::line(display_cur_frame,
00113                cv::Point(sparse_flow[i].x, sparse_flow[i].y),
00114                cv::Point(sparse_flow[i].x + sparse_flow[i].u,
00115                          sparse_flow[i].y + sparse_flow[i].v),
00116                cv::Scalar(0,0,255), 1);
00117     }
00118   }
00119 
00120   cv::imshow(window_name_, display_cur_frame);
00121 #endif // DISPLAY_TRACKER_OUTPUT
00122   return sparse_flow;
00123 }
00124 
00125 AffineFlowMeasures FeatureTracker::updateTracks(const cv::Mat& frame)
00126 {
00127   return updateTracks(frame, cv::Mat());
00128 }
00129 
00130 AffineFlowMeasures FeatureTracker::updateTracks(const cv::Mat& frame,
00131                                                 const cv::Mat& mask)
00132 {
00133   cur_keypoints_.clear();
00134   cur_descriptors_.clear();
00135   updateCurrentDescriptors(frame, mask);
00136 
00137   std::vector<int> matches_cur;
00138   std::vector<int> matches_prev;
00139   AffineFlowMeasures sparse_flow;
00140   matches_cur.clear();
00141   matches_prev.clear();
00142 
00143   
00144   findMatches(cur_descriptors_, prev_descriptors_, matches_cur, matches_prev,
00145               cur_scores_);
00146   ROS_DEBUG_STREAM(window_name_ << ": num feature matches: "
00147                    << matches_cur.size());
00148   int moving_points = 0;
00149   for (unsigned int i = 0; i < matches_cur.size(); i++)
00150   {
00151     int dx = prev_keypoints_[matches_prev[i]].pt.x -
00152         cur_keypoints_[matches_cur[i]].pt.x;
00153     int dy = prev_keypoints_[matches_prev[i]].pt.y -
00154         cur_keypoints_[matches_cur[i]].pt.y;
00155     sparse_flow.push_back(AffineFlowMeasure(
00156         cur_keypoints_[matches_cur[i]].pt.x,
00157         cur_keypoints_[matches_cur[i]].pt.y, dx, dy));
00158     if (abs(sparse_flow[i].u) + abs(sparse_flow[i].v) >= min_flow_thresh_)
00159       moving_points++;
00160   }
00161   ROS_DEBUG_STREAM(window_name_ << ": num moving points: " << moving_points);
00162 
00163 #ifdef DISPLAY_TRACKER_OUTPUT
00164   cv::Mat display_frame(frame.rows, frame.cols, CV_8UC3);;
00165   cv::cvtColor(frame, display_frame, CV_GRAY2BGR);
00166   for (unsigned int i = 0; i < matches_cur.size(); i++)
00167   {
00168     if (abs(sparse_flow[i].u) + abs(sparse_flow[i].v) >= min_flow_thresh_)
00169     {
00170       ROS_DEBUG_STREAM("Point is moving (" << sparse_flow[i].u << ", "
00171                        << sparse_flow[i].v << ")");
00172       cv::line(display_frame,
00173                prev_keypoints_[matches_prev[i]].pt,
00174                cur_keypoints_[matches_cur[i]].pt,
00175                cv::Scalar(0,0,255), 1);
00176     }
00177   }
00178 
00179   cv::imshow(window_name_, display_frame);
00180 #endif // DISPLAY_TRACKER_OUTPUT
00181 
00182   prev_keypoints_ = cur_keypoints_;
00183   prev_descriptors_ = cur_descriptors_;
00184   cur_flow_ = sparse_flow;
00185   return sparse_flow;
00186 }
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194 
00195 
00196 
00197 
00198 
00199 
00200 double FeatureTracker::SSD(Descriptor& a, Descriptor& b)
00201 {
00202   double diff = 0;
00203 
00204   for (unsigned int i = 0; i < a.size(); ++i) {
00205     float delta = a[i] - b[i];
00206     diff += delta*delta;
00207   }
00208 
00209   return diff;
00210 }
00211 
00212 
00213 
00214 
00215 
00216 
00217 
00218 
00219 
00220 
00221 
00222 std::pair<int, float> FeatureTracker::ratioTest(Descriptor& a,
00223                                                 Descriptors& bList,
00224                                                 double threshold)
00225 {
00226   double best_score = 1000000;
00227   double second_best = 1000000;
00228   int best_index = -1;
00229 
00230   for (unsigned int b = 0; b < bList.size(); ++b) {
00231     double score = 0;
00232     score = SSD(a, bList[b]);
00233 
00234     if (score < best_score) {
00235       second_best = best_score;
00236       best_score = score;
00237       best_index = b;
00238     } else if (score < second_best) {
00239       second_best = score;
00240     }
00241     if ( best_score / second_best > threshold) {
00242       best_index = -1;
00243     }
00244 
00245   }
00246 
00247   return std::pair<int, float>(best_index, best_score);
00248 }
00249 
00258 void FeatureTracker::findMatches(Descriptors& descriptors1,
00259                                  Descriptors& descriptors2,
00260                                  std::vector<int>& matches1,
00261                                  std::vector<int>& matches2,
00262                                  std::vector<float>& scores)
00263 {
00264   
00265   for (unsigned int a = 0; a < descriptors1.size(); ++a) {
00266     const std::pair<int,float> best_match = ratioTest(descriptors1[a],
00267                                                       descriptors2,
00268                                                       ratio_threshold_);
00269     const int best_index = best_match.first;
00270     const int best_score = best_match.second;
00271     if (best_index != -1) {
00272       matches1.push_back(a);
00273       matches2.push_back(best_index);
00274       scores.push_back(best_score);
00275     }
00276   }
00277 
00278   
00279   for (unsigned int x = 0; x < matches2.size();) {
00280     const std::pair<int,float> best_match = ratioTest(descriptors2[matches2[x]],
00281                                                       descriptors1,
00282                                                       ratio_threshold_);
00283     const int best_index = best_match.first;
00284     const int best_score = best_match.second;
00285     if (best_index != matches1[x]) {
00286       matches1.erase(matches1.begin()+x);
00287       matches2.erase(matches2.begin()+x);
00288       scores.erase(scores.begin()+x);
00289     } else {
00290       x++;
00291     }
00292   }
00293 }
00294 
00295 
00296 
00297 
00298 
00299 void FeatureTracker::updateCurrentDescriptors(const cv::Mat& frame,
00300                                               const cv::Mat& mask)
00301 {
00302   std::vector<float> raw_descriptors;
00303   try
00304   {
00305     if (use_fast_)
00306     {
00307       cv::Mat masked_frame(frame.size(), frame.type(), cv::Scalar(0));
00308       frame.copyTo(masked_frame, mask);
00309       cv::FAST(masked_frame, cur_keypoints_, 9, true);
00310       
00311       surf_(frame, mask, cur_keypoints_, raw_descriptors, true);
00312     }
00313     else
00314     {
00315       surf_(frame, mask, cur_keypoints_, raw_descriptors, false);
00316     }
00317     for (unsigned int i = 0; i < raw_descriptors.size(); i += 128)
00318     {
00319       Descriptor d(raw_descriptors.begin() + i,
00320                    raw_descriptors.begin() + i + 128);
00321       cur_descriptors_.push_back(d);
00322     }
00323   }
00324   catch(cv::Exception e)
00325   {
00326     ROS_ERROR_STREAM(e.err);
00327     
00328   }
00329 }
00330 }