00001 #ifndef UTILS
00002 #define UTILS
00003
00004 #include <ros/ros.h>
00005 #include <tf/transform_broadcaster.h>
00006 #include <opencv2/features2d/features2d.hpp>
00007 #include <opencv2/nonfree/features2d.hpp>
00008 #include <opencv2/nonfree/nonfree.hpp>
00009 #include <image_geometry/stereo_camera_model.h>
00010
00011 using namespace std;
00012 using namespace cv;
00013
00014 namespace haloc
00015 {
00016
00017 class Utils
00018 {
00019
00020 public:
00021
00028 static void keypointDetector(const Mat& image,
00029 vector<KeyPoint>& key_points,
00030 string type)
00031 {
00032
00033 size_t pos = 0;
00034 if ( (pos=type.find("Opponent")) == 0)
00035 {
00036 pos += string("Opponent").size();
00037 type = type.substr(pos);
00038 }
00039
00040 initModule_nonfree();
00041 Ptr<FeatureDetector> cv_detector;
00042 cv_detector = FeatureDetector::create(type);
00043 try
00044 {
00045 cv_detector->detect(image, key_points);
00046 }
00047 catch (Exception& e)
00048 {
00049 ROS_WARN("[StereoSlam:] cv_detector exception: %s", e.what());
00050 }
00051 }
00052
00059 static void descriptorExtraction(const Mat& image,
00060 vector<KeyPoint>& key_points, Mat& descriptors, string type)
00061 {
00062 Ptr<DescriptorExtractor> cv_extractor;
00063 cv_extractor = DescriptorExtractor::create(type);
00064 try
00065 {
00066 cv_extractor->compute(image, key_points, descriptors);
00067 }
00068 catch (Exception& e)
00069 {
00070 ROS_WARN("[StereoSlam:] cv_extractor exception: %s", e.what());
00071 }
00072 }
00073
00081 static void ratioMatching(const Mat& descriptors1, const Mat& descriptors2,
00082 double ratio, const Mat& match_mask, vector<DMatch>& matches)
00083 {
00084 matches.clear();
00085 if (descriptors1.empty() || descriptors2.empty())
00086 return;
00087 assert(descriptors1.type() == descriptors2.type());
00088 assert(descriptors1.cols == descriptors2.cols);
00089
00090 const int knn = 2;
00091 Ptr<DescriptorMatcher> descriptor_matcher;
00092
00093 if (descriptors1.type() == CV_8U)
00094 {
00095 descriptor_matcher = DescriptorMatcher::create("BruteForce-Hamming");
00096 }
00097 else
00098 {
00099 descriptor_matcher = DescriptorMatcher::create("BruteForce");
00100 }
00101 vector<vector<DMatch> > knn_matches;
00102 descriptor_matcher->knnMatch(descriptors1, descriptors2,
00103 knn_matches, knn, match_mask);
00104
00105 for (unsigned m = 0; m < knn_matches.size(); m++)
00106 {
00107 if (knn_matches[m].size() < 2) continue;
00108 if (knn_matches[m][0].distance <= knn_matches[m][1].distance * ratio)
00109 matches.push_back(knn_matches[m][0]);
00110 }
00111 }
00112
00121 static void thresholdMatching(const Mat& descriptors1, const Mat& descriptors2,
00122 double threshold, const Mat& match_mask, vector<DMatch>& matches)
00123 {
00124 matches.clear();
00125 if (descriptors1.empty() || descriptors2.empty())
00126 return;
00127 assert(descriptors1.type() == descriptors2.type());
00128 assert(descriptors1.cols == descriptors2.cols);
00129
00130 const int knn = 2;
00131 Ptr<DescriptorMatcher> descriptor_matcher;
00132
00133 if (descriptors1.type() == CV_8U)
00134 {
00135 descriptor_matcher = DescriptorMatcher::create("BruteForce-Hamming");
00136 }
00137 else
00138 {
00139 descriptor_matcher = DescriptorMatcher::create("BruteForce");
00140 }
00141 vector<vector<DMatch> > knn_matches;
00142 descriptor_matcher->knnMatch(descriptors1, descriptors2,
00143 knn_matches, knn, match_mask);
00144
00145 for (size_t m = 0; m < knn_matches.size(); m++)
00146 {
00147 if (knn_matches[m].size() < 2) continue;
00148 float dist1 = knn_matches[m][0].distance;
00149 float dist2 = knn_matches[m][1].distance;
00150 if (dist1 / dist2 < threshold)
00151 {
00152 matches.push_back(knn_matches[m][0]);
00153 }
00154 }
00155 }
00156
00163 static void crossCheckFilter(
00164 const vector<DMatch>& matches1to2,
00165 const vector<DMatch>& matches2to1,
00166 vector<DMatch>& checked_matches)
00167 {
00168 checked_matches.clear();
00169 for (size_t i = 0; i < matches1to2.size(); ++i)
00170 {
00171 bool match_found = false;
00172 const DMatch& forward_match = matches1to2[i];
00173 for (size_t j = 0; j < matches2to1.size() && match_found == false; ++j)
00174 {
00175 const DMatch& backward_match = matches2to1[j];
00176 if (forward_match.trainIdx == backward_match.queryIdx &&
00177 forward_match.queryIdx == backward_match.trainIdx)
00178 {
00179 checked_matches.push_back(forward_match);
00180 match_found = true;
00181 }
00182 }
00183 }
00184 }
00185
00194 static void crossCheckThresholdMatching(
00195 const Mat& descriptors1, const Mat& descriptors2,
00196 double threshold, const Mat& match_mask,
00197 vector<DMatch>& matches)
00198 {
00199 vector<DMatch> query_to_train_matches;
00200 thresholdMatching(descriptors1, descriptors2, threshold, match_mask, query_to_train_matches);
00201 vector<DMatch> train_to_query_matches;
00202 Mat match_mask_t;
00203 if (!match_mask.empty()) match_mask_t = match_mask.t();
00204 thresholdMatching(descriptors2, descriptors1, threshold, match_mask_t, train_to_query_matches);
00205
00206 crossCheckFilter(query_to_train_matches, train_to_query_matches, matches);
00207 }
00208
00216 static bool calculate3DPoint(const image_geometry::StereoCameraModel stereo_camera_model,
00217 const Point2d& left_point,
00218 const Point2d& right_point,
00219 double max_proj_err,
00220 Point3d& world_point)
00221 {
00222
00223 double disparity = left_point.x - right_point.x;
00224 stereo_camera_model.projectDisparityTo3d(left_point, disparity, world_point);
00225
00226
00227
00228 double fx_l = stereo_camera_model.left().fx();
00229 double fy_l = stereo_camera_model.left().fy();
00230 double cx_l = stereo_camera_model.left().cx();
00231 double cy_l = stereo_camera_model.left().cy();
00232
00233 double fx_r = stereo_camera_model.right().fx();
00234 double fy_r = stereo_camera_model.right().fy();
00235 double cx_r = stereo_camera_model.right().cx();
00236 double cy_r = stereo_camera_model.right().cy();
00237
00238 double baseline = stereo_camera_model.baseline();
00239
00240
00241 double x_l = (1.0/fx_l) * (left_point.x - cx_l);
00242 double y_l = (1.0/fy_l) * (left_point.y - cy_l);
00243 double z_l = 1.0;
00244
00245 double x_r = (1.0/fx_r) * (right_point.x - cx_r);
00246 double y_r = (1.0/fy_r) * (right_point.y - cy_r);
00247 double z_r = 1.0;
00248
00249 tf::Vector3 u(x_l, y_l, z_l);
00250 tf::Vector3 v(x_r, y_r, z_r);
00251 tf::Vector3 w0(-baseline, 0.0, 0.0);
00252
00253
00254 tf::Vector3 l0(0.0, 0.0, 0.0);
00255 tf::Vector3 r0(baseline, 0.0, 0.0);
00256
00257
00258 double a = u.dot(u);
00259 double b = u.dot(v);
00260 double c = v.dot(v);
00261 double d = u.dot(w0);
00262 double e = v.dot(w0);
00263
00264
00265 tf::Vector3 dv = (l0-r0) + ( ( (b*e-c*d)*u - (a*e-b*d)*v ) / (a*c - b*b) );
00266 double dist = sqrt( dv.x()*dv.x() + dv.y()*dv.y() + dv.z()*dv.z() );
00267 if (dist > max_proj_err)
00268 {
00269 return false;
00270 }
00271 else
00272 {
00273 return true;
00274 }
00275 }
00276
00282 static bool sortByMatching(const pair<int, float> d1, const pair<int, float> d2)
00283 {
00284 return (d1.second < d2.second);
00285 }
00286
00292 static bool sortDescByDistance(const DMatch& d1, const DMatch& d2)
00293 {
00294 return (d1.distance < d2.distance);
00295 }
00296
00302 static bool sortByResponse(const KeyPoint kp1, const KeyPoint kp2)
00303 {
00304 return (kp1.response > kp2.response);
00305 }
00306
00312 static bool sortByLikelihood(const pair<int, float> p1, const pair<int, float> p2)
00313 {
00314 return (p1.second > p2.second);
00315 }
00316
00323 static tf::Transform buildTransformation(Mat rvec, Mat tvec)
00324 {
00325 if (rvec.empty() || tvec.empty())
00326 return tf::Transform();
00327
00328 tf::Vector3 axis(rvec.at<double>(0, 0),
00329 rvec.at<double>(1, 0),
00330 rvec.at<double>(2, 0));
00331 double angle = norm(rvec);
00332 tf::Quaternion quaternion(axis, angle);
00333
00334 tf::Vector3 translation(tvec.at<double>(0, 0), tvec.at<double>(1, 0),
00335 tvec.at<double>(2, 0));
00336
00337 return tf::Transform(quaternion, translation);
00338 }
00339 };
00340
00341 }
00342
00343 #endif // UTILS
00344
00345