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 }