00001 #include <list>
00002 #include <time.h>
00003
00004 #include <ros/ros.h>
00005
00006 #include <image_transport/image_transport.h>
00007 #include <cv_bridge/cv_bridge.h>
00008 #include <opencv2/core/core.hpp>
00009 #include <opencv2/core/types_c.h>
00010 #include <opencv2/imgproc/imgproc.hpp>
00011 #include <opencv2/features2d/features2d.hpp>
00012 #include <opencv2/highgui/highgui.hpp>
00013
00014 #include "object_pose_detection_alg.h"
00015 #include <HoughTransform.hpp>
00016 #include <ransac.hpp>
00017
00018 using namespace std;
00019
00020
00021
00022 ObjectPoseDetectionAlgorithm::ObjectPoseDetectionAlgorithm(void)
00023 {
00024 }
00025
00026 ObjectPoseDetectionAlgorithm::~ObjectPoseDetectionAlgorithm(void)
00027 {
00028 }
00029
00030 void ObjectPoseDetectionAlgorithm::config_update(Config& new_cfg, uint32_t level)
00031 {
00032 this->lock();
00033
00034
00035 this->config_=new_cfg;
00036
00037
00038 this->unlock();
00039 }
00040
00041
00042
00043 void myDisplayImage(cv::Mat image, std::string title="Window title")
00044 {
00045 cv::namedWindow(title, CV_WINDOW_NORMAL);
00046 cv::imshow(title,image);
00047 cv::waitKey(0);
00048 cv::destroyWindow(title);
00049 }
00050
00051
00052 void myPrintMatches(vector<cv::KeyPoint> trainKeyPoints,
00053 vector<cv::KeyPoint> testKeyPoints,
00054 vector<cv::DMatch> matches)
00055 {
00056 int m1, m2;
00057 unsigned int m3;
00058 m1 = trainKeyPoints.size();
00059 m2 = testKeyPoints.size();
00060 m3 = matches.size();
00061 cout << "Number of train key points: " << m1 << endl;
00062 cout << "Number of test key points: " << m2 << endl;
00063 cout << "Number of matches: " << m3 << endl;
00064
00065 for(unsigned int i=0; i<m3; ++i)
00066 {
00067
00068 if(matches[i].trainIdx >= m1 or matches[i].queryIdx >= m2)
00069 ROS_ERROR("REFERENCIA DE MATCHES INCORRECTA!");
00070 }
00071 }
00072
00073
00074
00075 bool file_exists(std::string filename)
00076 {
00077 std::fstream fin;
00078 fin.open(filename.c_str(),std::ios::in);
00079 if( fin.is_open() )
00080 {
00081 return true;
00082 }
00083 fin.close();
00084 return false;
00085 }
00086
00087 std::vector<std::string> read_file_into_vector(const std::string &initfile)
00088 {
00089 std::vector<std::string> init;
00090 std::ifstream pf(initfile.c_str(), std::ios::in);
00091 if(!pf.is_open())
00092 {
00093 return init;
00094 }
00095
00096 std::string line;
00097 while(!pf.eof())
00098 {
00099 std::getline(pf,line);
00100 if(line!="")
00101 init.push_back(line);
00102 }
00103 return init;
00104 }
00105
00106 std::string trim(const std::string s, bool all=false)
00107 {
00108 std::string res="";
00109 if(s[0]==' ')
00110 res.push_back(s[0]);
00111
00112 for(uint i=1;i<s.length();i++)
00113 {
00114 if(s[i]!=' ')
00115 res.push_back(s[i]);
00116 else if(!all)
00117 if(s[i-1]!=' ')
00118 res.push_back(s[i]);
00119 }
00120 return res;
00121 }
00122
00123 std::string ObjectPoseDetectionAlgorithm::parse_param(const std::vector<std::string>& init, std::string req)
00124 {
00125 for(std::vector<std::string>::const_iterator line=init.begin(); line!=init.end();line++)
00126 {
00127
00128 std::string trimmedl=*line;
00129 if(trimmedl[0]=='#')
00130 continue;
00131
00132 std::size_t eqpos=trimmedl.find('=');
00133 if(eqpos==std::string::npos)
00134 continue;
00135
00136 std::string var=trimmedl.substr(0,eqpos);
00137 if(var==req)
00138 {
00139 std::string val=trimmedl.substr(eqpos+1);
00140 return val;
00141 }
00142 }
00143 return "";
00144 }
00145
00146 bool ObjectPoseDetectionAlgorithm::init_config(const std::string &initfile)
00147 {
00148 std::vector<std::string> init=read_file_into_vector(initfile);
00149
00150
00151 this->feats_dir_=parse_param(init,std::string("feats_dir"));
00152 if(this->feats_dir_=="")
00153 this->feats_dir_="train_feats/";
00154
00155
00156 this->train_imas_dir_=parse_param(init,std::string("train_imas_dir"));
00157 if(this->train_imas_dir_=="")
00158 this->train_imas_dir_="png/";
00159
00160
00161 std::string train_file_list=parse_param(init,std::string("train_file_list"));
00162 if(train_file_list=="" || !file_exists(train_file_list))
00163 train_file_list="/home/frigual/Dropbox/PFC/experiments/ortk_inicial/lists/base_train.txt";
00164 this->train_files_=read_file_into_vector(train_file_list);
00165
00166
00167 this->distance_ratio_=fromString<float>(parse_param(init,std::string("distance_ratio")));
00168 if(this->distance_ratio_<0.01 || this->distance_ratio_>1)
00169 this->distance_ratio_=0.8;
00170
00171
00172 this->min_matches_=fromString<int>(parse_param(init,std::string("min_matches")));
00173 if(this->min_matches_<3 || this->min_matches_>25.)
00174 this->min_matches_=3;
00175
00176
00177 this->test_image_=parse_param(init,std::string("test_image"));
00178 if(this->test_image_=="")
00179 this->test_image_="/home/frigual/PFC/datasets/ASL_test_left/img26-L.png";
00180
00181 #ifdef DEBUG
00182 std::cout<<"feats_dir: "<<this->feats_dir_<<std::endl;
00183 std::cout<<"train_imas_dir: "<<this->train_imas_dir_<<std::endl;
00184 std::cout<<"train_files_: "<<train_file_list<<std::endl;
00185 std::cout<<"distance_ratio_: "<<this->distance_ratio_<<std::endl;
00186 std::cout<<"min_matches_: "<<this->min_matches_<<std::endl;
00187 std::cout<<"test_image: "<<this->test_image_<<std::endl;
00188 #endif
00189
00190 return true;
00191 }
00192
00193
00194 void ObjectPoseDetectionAlgorithm::compute_train_set()
00195 {
00196 unsigned int counter = 0;
00197
00198
00199 for(std::vector<std::string>::const_iterator file=this->train_files_.begin(); file!=this->train_files_.end(); file++)
00200 {
00201
00202 if( (*file)[0] == '#')
00203 continue;
00204
00205
00206 std::string path = train_imas_dir_ + *file + ".png";
00207 cv::Mat image = cv::imread(path,0);
00208 if(image.empty())
00209 {
00210 cout << "Can not read image: " << path << endl;
00211 exit(-1);
00212 }
00213 this->train_imas_.push_back(image);
00214
00215
00216 std::vector<cv::KeyPoint> keypoints;
00217 this->detector->detect( image, keypoints );
00218
00219
00220 cv::Mat descriptors;
00221 this->descriptorExtractor->compute( image, keypoints, descriptors );
00222
00223
00224 cv::FileStorage fs(this->feats_dir_ + *file + ".yml.gz", cv::FileStorage::WRITE);
00225 cv::write(fs, "keypoints", keypoints);
00226 cv::write(fs, "descriptors", descriptors);
00227
00228
00229 this->train_kpoints_.push_back(keypoints);
00230 this->train_desc_.push_back(descriptors);
00231
00232 counter++;
00233 }
00234
00235
00236 if(not this->descriptorMatcher->empty())
00237 this->descriptorMatcher->clear();
00238 this->descriptorMatcher->add(train_desc_);
00239 this->descriptorMatcher->train();
00240
00241 ROS_INFO("Computed the features of %d images.", counter);
00242 }
00243
00244
00245
00246 void ObjectPoseDetectionAlgorithm::load_train_set()
00247 {
00248 std::vector<cv::KeyPoint> keypoints;
00249 cv::Mat descriptors;
00250 unsigned int counter = 0;
00251
00252
00253 for(std::vector<std::string>::const_iterator file=this->train_files_.begin();
00254 file!=this->train_files_.end();
00255 file++)
00256 {
00257
00258 cv::Mat image = cv::imread(train_imas_dir_+*file+".png",0);
00259 this->train_imas_.push_back(image);
00260
00261
00262 cv::FileStorage fs2(feats_dir_+*file+".yml.gz", cv::FileStorage::READ);
00263 cv::read(fs2["keypoints"], keypoints);
00264 cv::read(fs2["descriptors"], descriptors);
00265
00266
00267 this->train_kpoints_.push_back(keypoints);
00268 this->train_desc_.push_back(descriptors);
00269
00270 counter++;
00271 }
00272
00273
00274 this->descriptorMatcher->add(train_desc_);
00275 this->descriptorMatcher->train();
00276
00277 ROS_INFO("Loaded the features of %d images.", counter);
00278 }
00279
00280
00281
00282
00283 void ObjectPoseDetectionAlgorithm::ortk_detect()
00284 {
00285 cv::Mat testImage = cv::imread(test_image_, 0);
00286
00287
00288 std::vector<cv::KeyPoint> testKeypoints;
00289 this->detector->detect( testImage, testKeypoints );
00290
00291
00292 cv::Mat testDescriptors;
00293 this->descriptorExtractor->compute( testImage, testKeypoints, testDescriptors );
00294
00295
00296 vector< vector<cv::DMatch> > matcherOutput;
00297 this->descriptorMatcher->knnMatch(testDescriptors, matcherOutput, 2);
00298
00299 ROS_INFO("Detected %d matches from test image to train library.", (int) matcherOutput.size());
00300
00301
00302 vector< vector<cv::DMatch> > totalMatches(train_imas_.size());
00303 for(vector< vector<cv::DMatch> >::iterator it = matcherOutput.begin(); it != matcherOutput.end(); ++it)
00304
00305 if( (*it)[0].distance / (*it)[1].distance < this->distance_ratio_ )
00306 totalMatches[(*it)[0].imgIdx].push_back( (*it)[0] );
00307
00308
00309 for(unsigned int iImage = 0; iImage < train_imas_.size(); ++iImage)
00310 {
00311 vector<cv::DMatch> initialMatches = totalMatches[iImage];
00312 cv::Mat trainImage = train_imas_[iImage];
00313 ROS_INFO("For the #%d image, %d initial matches have been found.", iImage, (int) initialMatches.size());
00314
00315
00316 if(initialMatches.size() >= this->min_matches_)
00317 {
00318
00319
00320 HoughTransform hough;
00321 vector<HoughTransform::Hypothesis> myHypotheses;
00322
00323 int numHoughHypotheses = hough.computeTransform(trainImage.cols,
00324 trainImage.rows,
00325 train_kpoints_[iImage],
00326 testKeypoints,
00327 initialMatches,
00328 myHypotheses);
00329
00330 ROS_INFO("We have %d hough hypotheses", numHoughHypotheses);
00331 if(numHoughHypotheses > 0)
00332 {
00333
00334 cv::Mat displayHough;
00335 for(uint iHyp = 0; iHyp < 1; ++iHyp)
00336 {
00337 cv::drawMatches(testImage, testKeypoints, train_imas_[iImage], train_kpoints_[iImage], myHypotheses[iHyp].matches, displayHough, cv::Scalar( 0, 255, 0), cv::Scalar( 0, 255, 0), vector<char>(), 6);
00338 myDisplayImage(displayHough, "GHT matches");
00339 }
00340
00341
00342
00343 list<cv::Mat> affineSolutions;
00344 list<pair<float, int> > errorMeasures;
00345 vector< vector<cv::DMatch> > ransacMatches;
00346
00347 computeAffHyp(train_kpoints_[iImage], testKeypoints, myHypotheses, affineSolutions, errorMeasures, true, true, ransacMatches);
00348
00349 for(uint iSolution = 0; iSolution<ransacMatches.size(); ++iSolution)
00350 {
00351 cv::Mat displayRansac;
00352 cv::drawMatches(testImage,
00353 testKeypoints,
00354 train_imas_[iImage],
00355 train_kpoints_[iImage],
00356 ransacMatches[iSolution],
00357 displayRansac,
00358 cv::Scalar( 0, 255, 0),
00359 cv::Scalar( 0, 255, 0),
00360 vector<char>(),
00361 6);
00362 myDisplayImage(displayRansac, "Ransac matches");
00363 }
00364
00365 displayBox(train_imas_[iImage], testImage, affineSolutions);
00366 }
00367 }
00368 }
00369 }
00370
00371
00372 ObjectPoseDetectionAlgorithm::ObjectPoseDetectionAlgorithm()
00373 {
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 std::string initfile(argv[1]);
00392 if(!init_config(initfile))
00393 {
00394 ROS_ERROR("Error: Bad config file");
00395 exit(-1);
00396 }
00397
00398 this->detector = cv::FeatureDetector::create( argv[2] );
00399 if(detector.empty())
00400 {
00401 ROS_ERROR("Error: Couldn't create feature detector.");
00402 exit(-1);
00403 }
00404
00405 this->descriptorExtractor = cv::DescriptorExtractor::create( argv[3] );
00406 if(descriptorExtractor.empty())
00407 {
00408 ROS_ERROR("Error: Couldn't create descriptor extractor.");
00409 exit(-1);
00410 }
00411
00412 this->descriptorMatcher = cv::DescriptorMatcher::create( argv[4] );
00413 if(descriptorMatcher.empty())
00414 {
00415 ROS_ERROR("Error: Couldn't create descriptor matcher.");
00416 exit(-1);
00417 }
00418
00419
00420 this->compute_train_set();
00421
00422 }