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 }