00001 #include <anj_featurenav/jockey.h>
00002
00003 #define GET_PARAM(prefix, type_t, name, default) \
00004 type_t name = default; \
00005 private_nh_.getParam(#prefix"/"#name, name); \
00006 ROS_DEBUG_STREAM(#prefix"/"#name": " << name);
00007
00008 #define GET_PARAM_DETECTOR(type_t, name, default) GET_PARAM(feature_detector, type_t, name, default)
00009 #define GET_PARAM_EXTRACTOR(type_t, name, default) GET_PARAM(descriptor_extractor, type_t, name, default)
00010 #define GET_PARAM_MATCHER(type_t, name, default) GET_PARAM(descriptor_matcher, type_t, name, default)
00011
00012 namespace anj_featurenav
00013 {
00014
00015 Jockey::Jockey(const std::string& name) :
00016 feature_detector_type_("FAST"),
00017 descriptor_extractor_type_("BRIEF"),
00018 descriptor_matcher_type_("FlannBased"),
00019 private_nh_("~"),
00020 base_name_(name)
00021 {
00022
00023 if(ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug))
00024 {
00025 ros::console::notifyLoggerLevelsChanged();
00026 }
00027
00028
00029 private_nh_.getParam("feature_detector/type", feature_detector_type_);
00030 ROS_DEBUG_STREAM("Feature detector type: " << feature_detector_type_);
00031
00032 if (feature_detector_type_ == "FAST")
00033 {
00034 initDetectorFast();
00035 }
00036 else if (feature_detector_type_ == "STAR")
00037 {
00038 initDetectorStar();
00039 }
00040 else if (feature_detector_type_ == "SIFT")
00041 {
00042 throw ros::InvalidParameterException("SIFT algorithm is nonfree, cf. anj_featurenav_nonfree package");
00043 }
00044 else if (feature_detector_type_ == "SURF")
00045 {
00046 throw ros::InvalidParameterException("SURF algorithm is nonfree, cf. anj_featurenav_nonfree package");
00047 }
00048 else if (feature_detector_type_ == "ORB")
00049 {
00050 initDetectorOrb();
00051 }
00052 else if (feature_detector_type_ == "MSER")
00053 {
00054 initDetectorMser();
00055 }
00056 else if (feature_detector_type_ == "GFTT")
00057 {
00058 initDetectorGftt();
00059 }
00060 else if (feature_detector_type_ == "Dense")
00061 {
00062 initDetectorDense();
00063 }
00064 else if (feature_detector_type_ == "SimpleBlob")
00065 {
00066 initDetectorSimpleblob();
00067 }
00068 else
00069 {
00070 throw ros::InvalidParameterException(std::string("Unkown feature detection algorithm (") +
00071 feature_detector_type_ + std::string(")"));
00072 }
00073
00074
00075 private_nh_.getParam("descriptor_extractor/type", descriptor_extractor_type_);
00076 ROS_DEBUG_STREAM("Descriptor extractor type: " << descriptor_extractor_type_);
00077
00078 if (descriptor_extractor_type_ == "SIFT")
00079 {
00080 throw ros::InvalidParameterException("SIFT algorithm is nonfree, cf. anj_featurenav_nonfree package");
00081 }
00082 else if (descriptor_extractor_type_ == "SURF")
00083 {
00084 throw ros::InvalidParameterException("SURF algorithm is nonfree, cf. anj_featurenav_nonfree package");
00085 }
00086 else if (descriptor_extractor_type_ == "ORB")
00087 {
00088 initExtractorOrb();
00089 }
00090 else if (descriptor_extractor_type_ == "BRIEF")
00091 {
00092 initExtractorBrief();
00093 }
00094 else
00095 {
00096 throw ros::InvalidParameterException(std::string("Unkown descriptor extraction algorithm (") +
00097 descriptor_extractor_type_ + std::string(")"));
00098 }
00099
00100
00101 private_nh_.getParam("descriptor_matcher/type", descriptor_matcher_type_);
00102 ROS_DEBUG_STREAM("Descriptor matcher type: " << descriptor_matcher_type_);
00103
00104 if (descriptor_matcher_type_ == "BruteForce")
00105 {
00106 initMatcherBruteforce();
00107 }
00108 else if (descriptor_matcher_type_ == "FlannBased")
00109 {
00110 initMatcherFlannbased();
00111 }
00112 else
00113 {
00114 throw ros::InvalidParameterException(std::string("Unkown descriptor matcher algorithm (") +
00115 descriptor_matcher_type_ + std::string(")"));
00116 }
00117
00118 map_interface_name_ = base_name_ + "_" + feature_detector_code_ + "_" + descriptor_extractor_code_;
00119 anjockey_ptr_.reset(new featurenav_base::ANJockey(base_name_, map_interface_name_));
00120 anjockey_ptr_->setExtractFeaturesFunction(boost::bind(&Jockey::extractFeatures, this, _1, _2, _3));
00121 anjockey_ptr_->setDescriptorMatcherFunction(boost::bind(&Jockey::matchDescriptors, this, _1, _2, _3));
00122 }
00123
00124 std::string Jockey::getLearningJockeyName() const
00125 {
00126 if (anjockey_ptr_ == NULL)
00127 {
00128 return "";
00129 }
00130 return anjockey_ptr_->getLearningJockeyName();
00131 }
00132
00133 std::string Jockey::getNavigatingJockeyName() const
00134 {
00135 if (anjockey_ptr_ == NULL)
00136 {
00137 return "";
00138 }
00139 return anjockey_ptr_->getNavigatingJockeyName();
00140 }
00141
00142
00143
00144 void Jockey::initDetectorFast()
00145 {
00146
00147 GET_PARAM_DETECTOR(int, threshold, 1);
00148 GET_PARAM_DETECTOR(bool, nonmax_suppression, true);
00149
00150 feature_detector_.reset(new cv::FastFeatureDetector(threshold, nonmax_suppression));
00151 feature_detector_code_ = "fast";
00152 }
00153
00154
00155
00156 void Jockey::initDetectorStar()
00157 {
00158 GET_PARAM_DETECTOR(int, max_size, 16);
00159 GET_PARAM_DETECTOR(int, response_threshold, 30);
00160 GET_PARAM_DETECTOR(int, line_threshold_projected, 10);
00161 GET_PARAM_DETECTOR(int, line_threshold_binarized, 8);
00162 GET_PARAM_DETECTOR(int, suppress_nonmax_size, 5);
00163
00164 feature_detector_.reset(new cv::StarFeatureDetector(max_size,
00165 response_threshold, line_threshold_projected, line_threshold_binarized, suppress_nonmax_size));
00166 feature_detector_code_ = "star";
00167 }
00168
00169
00170
00171 void Jockey::initDetectorOrb()
00172 {
00173 enum
00174 {
00175 HARRIS_SCORE = 0,
00176 FAST_SCORE = 1
00177 };
00178
00179 GET_PARAM_DETECTOR(double, scale_factor, 1.2);
00180 GET_PARAM_DETECTOR(int, n_features, 500);
00181 GET_PARAM_DETECTOR(int, n_levels, 8);
00182 GET_PARAM_DETECTOR(int, edge_threshold, 31);
00183 GET_PARAM_DETECTOR(int, first_level, 0);
00184 GET_PARAM_DETECTOR(int, wta_k, 2);
00185 GET_PARAM_DETECTOR(int, score_type, HARRIS_SCORE);
00186 GET_PARAM_DETECTOR(int, patch_size, 31);
00187
00188 feature_detector_.reset(new cv::OrbFeatureDetector(n_features, scale_factor, n_levels, edge_threshold,
00189 first_level, wta_k, score_type, patch_size));
00190 feature_detector_code_ = "orb";
00191 }
00192
00193
00194
00195 void Jockey::initDetectorMser()
00196 {
00197 GET_PARAM_DETECTOR(int, delta, 5);
00198 GET_PARAM_DETECTOR(int, min_area, 60);
00199 GET_PARAM_DETECTOR(int, max_area, 14400);
00200 GET_PARAM_DETECTOR(double, max_variation, 0.25);
00201 GET_PARAM_DETECTOR(double, min_diversity, 0.2);
00202 GET_PARAM_DETECTOR(int, max_evolution, 200);
00203 GET_PARAM_DETECTOR(double, area_threshold, 1.01);
00204 GET_PARAM_DETECTOR(double, min_margin, 0.003);
00205 GET_PARAM_DETECTOR(int, edge_blur_size, 5);
00206
00207 feature_detector_.reset(new cv::MserFeatureDetector(delta, min_area,
00208 max_area, max_variation, min_diversity, max_evolution, area_threshold,
00209 min_margin, edge_blur_size));
00210 feature_detector_code_ = "mser";
00211 }
00212
00213
00214
00215 void Jockey::initDetectorGftt()
00216 {
00217 GET_PARAM_DETECTOR(int, max_corners, 1000);
00218 GET_PARAM_DETECTOR(int, block_size, 3);
00219 GET_PARAM_DETECTOR(double, quality_level, 0.01);
00220 GET_PARAM_DETECTOR(double, min_distance, 1);
00221 GET_PARAM_DETECTOR(double, k, 0.04);
00222 GET_PARAM_DETECTOR(bool, use_harris_detector, false);
00223
00224 feature_detector_.reset(new cv::GoodFeaturesToTrackDetector(max_corners,
00225 quality_level, min_distance, block_size, use_harris_detector, k));
00226 feature_detector_code_ = "gfft";
00227 }
00228
00229
00230
00231 void Jockey::initDetectorDense()
00232 {
00233 GET_PARAM_DETECTOR(int, feature_scale_levels, 1);
00234 GET_PARAM_DETECTOR(int, init_xy_step, 6);
00235 GET_PARAM_DETECTOR(int, init_img_bound, 0);
00236 GET_PARAM_DETECTOR(double, init_feature_scale, 1);
00237 GET_PARAM_DETECTOR(double, feature_scale_mul, 0.1);
00238 GET_PARAM_DETECTOR(bool, vary_xy_step_with_scale, true);
00239 GET_PARAM_DETECTOR(bool, vary_img_bound_with_scale, false);
00240
00241 feature_detector_.reset(new cv::DenseFeatureDetector(init_feature_scale,
00242 feature_scale_levels, feature_scale_mul, init_xy_step, init_img_bound,
00243 vary_xy_step_with_scale, vary_img_bound_with_scale));
00244 feature_detector_code_ = "dense";
00245 }
00246
00247
00248
00249 void Jockey::initDetectorSimpleblob()
00250 {
00251 feature_detector_.reset(new cv::SimpleBlobDetector);
00252 feature_detector_code_ = "blob";
00253 }
00254
00255
00256
00257 void Jockey::initExtractorOrb()
00258 {
00259 enum
00260 {
00261 HARRIS_SCORE = 0,
00262 FAST_SCORE = 1
00263 };
00264
00265 GET_PARAM_EXTRACTOR(double, scale_factor, 1.2);
00266 GET_PARAM_EXTRACTOR(int, n_features, 500);
00267 GET_PARAM_EXTRACTOR(int, n_levels, 8);
00268 GET_PARAM_EXTRACTOR(int, edge_threshold, 31);
00269 GET_PARAM_EXTRACTOR(int, first_level, 0);
00270 GET_PARAM_EXTRACTOR(int, wta_k, 2);
00271 GET_PARAM_EXTRACTOR(int, score_type, HARRIS_SCORE);
00272 GET_PARAM_EXTRACTOR(int, patch_size, 31);
00273
00274 descriptor_extractor_.reset(new cv::OrbDescriptorExtractor(n_features, scale_factor,
00275 n_levels, edge_threshold, first_level, wta_k, score_type, patch_size));
00276 descriptor_extractor_code_ = "orb";
00277 }
00278
00279
00280
00281 void Jockey::initExtractorBrief()
00282 {
00283 GET_PARAM_EXTRACTOR(int, bytes, 32);
00284
00285 descriptor_extractor_.reset(new cv::BriefDescriptorExtractor(bytes));
00286 descriptor_extractor_code_ = "brief";
00287 }
00288
00289 void Jockey::initMatcherBruteforce()
00290 {
00291 int norm_type = cv::NORM_L1;
00292
00293 GET_PARAM_MATCHER(std::string, norm, "NORM_L2");
00294 GET_PARAM_MATCHER(bool, cross_check, false);
00295
00296 if ((norm == "NORM_L1") || (norm == "L1"))
00297 {
00298 norm_type = cv::NORM_L1;
00299 }
00300 else if ((norm == "NORM_L2") || (norm == "L2"))
00301 {
00302 norm_type = cv::NORM_L2;
00303 }
00304 else if ((norm == "NORM_HAMMING") || (norm == "HAMMING"))
00305 {
00306 norm_type = cv::NORM_HAMMING;
00307 }
00308 else if ((norm == "NORM_HAMMING2") || (norm == "HAMMING2"))
00309 {
00310 norm_type = cv::NORM_HAMMING2;
00311 }
00312 else
00313 {
00314 ROS_WARN_STREAM(ros::this_node::getName() << ": unknown norm type, defaulting to L2");
00315 }
00316
00317 descriptor_matcher_.reset(new cv::BFMatcher(norm_type, cross_check));
00318 descriptor_matcher_code_ = "bf";
00319 }
00320
00321 void Jockey::initMatcherFlannbased()
00322 {
00323 descriptor_matcher_.reset(new cv::FlannBasedMatcher());
00324 descriptor_matcher_code_ = "flann";
00325 }
00326
00327 void Jockey::extractFeatures(const sensor_msgs::ImageConstPtr& image, vector<KeyPoint>& keypoints, vector<Feature>& descriptors) const
00328 {
00329 cv_bridge::CvImageConstPtr cv_ptr;
00330 try
00331 {
00332 cv_ptr = cv_bridge::toCvShare(image, sensor_msgs::image_encodings::BGR8);
00333 }
00334 catch (cv_bridge::Exception& e)
00335 {
00336 ROS_ERROR("cv_bridge exception: %s, doing nothing...", e.what());
00337 return;
00338 }
00339
00340 feature_detector_->detect(cv_ptr->image, keypoints);
00341 cv::Mat cv_descriptors;
00342 descriptor_extractor_->compute(cv_ptr->image, keypoints, cv_descriptors);
00343
00344 rosFromCv(cv_descriptors, descriptors);
00345 }
00346
00347 void Jockey::matchDescriptors(const vector<Feature>& query_descriptors, const vector<Feature>& train_descriptors, vector<vector<DMatch> >& matches) const
00348 {
00349 int type = -1;
00350 if ((descriptor_extractor_code_ == "orb") || (descriptor_extractor_code_ == "brief"))
00351 {
00352 type = CV_8U;
00353 }
00354
00355 cv::Mat cv_query_descriptors;
00356 cvFromRos(query_descriptors, cv_query_descriptors, type);
00357
00358 cv::Mat cv_train_descriptors;
00359 cvFromRos(train_descriptors, cv_train_descriptors, type);
00360
00361
00362 if (descriptor_matcher_code_ == "flann")
00363 {
00364 cv::Mat cv_query_descriptors_copy;
00365 if(cv_query_descriptors.type() != CV_32F)
00366 {
00367 cv_query_descriptors.convertTo(cv_query_descriptors_copy, CV_32F);
00368 }
00369 else
00370 {
00371 cv_query_descriptors_copy = cv_query_descriptors;
00372 }
00373 cv::Mat cv_train_descriptors_copy;
00374 if(cv_train_descriptors.type() != CV_32F)
00375 {
00376 cv_train_descriptors.convertTo(cv_train_descriptors_copy, CV_32F);
00377 }
00378 else
00379 {
00380 cv_train_descriptors_copy = cv_train_descriptors;
00381 }
00382 descriptor_matcher_->knnMatch(cv_query_descriptors_copy, cv_train_descriptors_copy, matches, 2);
00383 }
00384 else
00385 {
00386 descriptor_matcher_->knnMatch(cv_query_descriptors, cv_train_descriptors, matches, 2);
00387 }
00388 }
00389
00390 }
00391