object_pose_detection_alg.cpp
Go to the documentation of this file.
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         // save the current configuration
00035         this->config_=new_cfg;
00036         //obj_.set_pixel_size(config_.pixel_x)
00037         
00038         this->unlock();
00039 }
00040 
00041 
00042 //My own function to display an image through the screen.
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 //My own function to display matches.
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                 //cout << matches[i].trainIdx << " -> " << matches[i].queryIdx << endl;
00068                 if(matches[i].trainIdx >= m1 or matches[i].queryIdx >= m2)
00069                         ROS_ERROR("REFERENCIA DE MATCHES INCORRECTA!");
00070         }
00071 }
00072 
00073 // INITIALIZATION FUNCTIONS ///////////////////////////////////////////////////////////////
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!="") //skipping white lines
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                 //std::string trimmedl=trim(*line); //Changed because "eated" the first char of the line.
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         //std::string feats_dir_;
00151         this->feats_dir_=parse_param(init,std::string("feats_dir"));
00152         if(this->feats_dir_=="")
00153                 this->feats_dir_="train_feats/";
00154 
00155         //std::string train_imas_dir_
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         //std::list<std::string> train_files_;
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         //float distance ratio_
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         //int min_matches
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         //std::string test_image_;
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         // For every train image...
00199         for(std::vector<std::string>::const_iterator file=this->train_files_.begin(); file!=this->train_files_.end(); file++)
00200         {
00201                 // Skip comments in file.
00202                 if( (*file)[0] == '#')
00203                         continue;
00204 
00205                 // Read image.
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                 // Extract key points.
00216                 std::vector<cv::KeyPoint> keypoints;
00217                 this->detector->detect( image, keypoints );
00218 
00219                 // Compute descriptors.
00220                 cv::Mat descriptors;
00221                 this->descriptorExtractor->compute( image, keypoints, descriptors );
00222 
00223                 // Save the features. (The folder to save the features has to be previously created)
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                 // Push the features to the class variables.
00229                 this->train_kpoints_.push_back(keypoints);
00230                 this->train_desc_.push_back(descriptors);
00231 
00232                 counter++;
00233         }
00234 
00235         // Train the matcher with all the descriptors.
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 //Unused
00246 void ObjectPoseDetectionAlgorithm::load_train_set()
00247 {
00248         std::vector<cv::KeyPoint> keypoints;
00249         cv::Mat descriptors;
00250         unsigned int counter = 0;
00251 
00252         // For every training image...
00253         for(std::vector<std::string>::const_iterator file=this->train_files_.begin(); 
00254                         file!=this->train_files_.end(); 
00255                         file++)
00256         {
00257                 // Push the image to the class variable.
00258                 cv::Mat image = cv::imread(train_imas_dir_+*file+".png",0);
00259                 this->train_imas_.push_back(image);
00260 
00261                 // Read the keypoints and descriptors from the disk.
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                 // Push them to the class variables.
00267                 this->train_kpoints_.push_back(keypoints);
00268                 this->train_desc_.push_back(descriptors);
00269 
00270                 counter++;
00271         }
00272 
00273         // Train the matcher with all the descriptors.
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 // Just like ortk_detect_callback, but to call manually.
00282 // Reads ObjectPoseDetectionAlgorithm::test_image_ to know the path of the image.
00283 void ObjectPoseDetectionAlgorithm::ortk_detect()
00284 {
00285         cv::Mat testImage = cv::imread(test_image_, 0);
00286 
00287         // Detect keypoints from test image.
00288         std::vector<cv::KeyPoint> testKeypoints;
00289         this->detector->detect( testImage, testKeypoints );
00290 
00291         // Extract descriptors.
00292         cv::Mat testDescriptors;
00293         this->descriptorExtractor->compute( testImage, testKeypoints, testDescriptors );
00294 
00295         // Compute matches between test images and all the train library.
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         // Now we want to identify which set of matches belong to each image.
00302         vector< vector<cv::DMatch> > totalMatches(train_imas_.size());
00303         for(vector< vector<cv::DMatch> >::iterator it = matcherOutput.begin(); it != matcherOutput.end(); ++it)
00304                 // Only if it's much better than the others.
00305                 if( (*it)[0].distance / (*it)[1].distance < this->distance_ratio_ )
00306                         totalMatches[(*it)[0].imgIdx].push_back( (*it)[0] );
00307 
00308         // For every train image...
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                 // If enough matches...
00316                 if(initialMatches.size() >= this->min_matches_)
00317                 {
00318                         // GHT
00319                         //   Declare output variables.
00320                         HoughTransform hough;
00321                         vector<HoughTransform::Hypothesis> myHypotheses;
00322                         //   Call GHT
00323                         int numHoughHypotheses = hough.computeTransform(trainImage.cols,
00324                                                 trainImage.rows,
00325                                                 train_kpoints_[iImage],
00326                                                 testKeypoints,
00327                                                 initialMatches,
00328                                                 myHypotheses);
00329                         //   Print results.
00330                         ROS_INFO("We have %d hough hypotheses", numHoughHypotheses);
00331                         if(numHoughHypotheses > 0)
00332                         {
00333                                 //   Display matches.
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                                 // RANSAC
00342                                 //   Declare output variables.
00343                                 list<cv::Mat> affineSolutions;
00344                                 list<pair<float, int> > errorMeasures;
00345                                 vector< vector<cv::DMatch> > ransacMatches;
00346                                 //   Call RANSAC and IRLS.
00347                                 computeAffHyp(train_kpoints_[iImage], testKeypoints, myHypotheses, affineSolutions, errorMeasures, true, true, ransacMatches);
00348                                 //   Display matches.
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                                 //   Display resulting bounding boxes.
00365                                 displayBox(train_imas_[iImage], testImage, affineSolutions);
00366                         }
00367                 }
00368         }
00369 }
00370 
00371 
00372 ObjectPoseDetectionAlgorithm::ObjectPoseDetectionAlgorithm()
00373 {
00374 /*      if(argc != 5)
00375         {
00376                 cout << "Usage: rosrun ortk ortk pathToConfigFile detectorType descriptorType matcherType\n\n"
00377                      << "Possible detectorType values: see in documentation on createFeatureDetector().\n"
00378                      << "Possible descriptorType values: see in documentation on createDescriptorExtractor().\n"
00379                      << "Possible matcherType values: see in documentation on createDescriptorMatcher().\n\n"
00380                      << "Example: rosrun ortk ortk ~/PFC/experiments/ortk_inicial/config_file.txt SIFT SIFT FlannBased\n"
00381                      << "config-file.txt example:\n"
00382                      << "train_file_list=~/base_train.txt\n"
00383                      << "train_imas_dir=~/tex_book/\n"
00384                      << "feats_dir=~/features/\n";
00385                 ROS_ERROR("Error: Wrong number of params!");
00386                 exit(-1);
00387         }
00388 */
00389         // Parameters configuration.
00390         //   Config file.
00391         std::string initfile(argv[1]);
00392         if(!init_config(initfile))
00393         {
00394                 ROS_ERROR("Error: Bad config file");
00395                 exit(-1);
00396         }
00397         //   Feature Detector
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         //   Descriptor Extractor
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         //   Descriptor Matcher
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         // Loading training data.
00420         this->compute_train_set();
00421         //this->load_train_set(); // Not used since we always compute the features.
00422 }


iri_object_pose_detection
Author(s):
autogenerated on Fri Dec 6 2013 23:17:43