SurfSet.cpp
Go to the documentation of this file.
00001 
00028 #include "SurfSet.h"
00029 #include <iostream>
00030 #include <fstream>
00031 #include <string>
00032 #include <opencv/cv.h>
00033 #include <opencv/highgui.h>
00034 #include <opencv2/nonfree/features2d.hpp>
00035 #include <vector>
00036 
00037 using namespace std;
00038 using namespace DVision;
00039 
00040 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00041 
00042 void SurfSet::SaveCustom(const std::string &filename) const
00043 {
00044         fstream f(filename.c_str(), ios::out);
00045         if(!f.is_open()) throw string("SurfSet: cannot open ") + filename;
00046 
00047         int L = 0;
00048         if(!keys.empty()) L = descriptors.size() / keys.size();
00049 
00050         f << keys.size() << " " << L << endl;
00051 
00052         vector<cv::KeyPoint>::const_iterator kit;
00053         vector<float>::const_iterator dit = descriptors.begin();
00054         for(kit = keys.begin(); kit != keys.end(); ++kit){
00055                 f << kit->pt.x << " "
00056                         << kit->pt.y << " "
00057                         << kit->angle << " "
00058                         << kit->size << " "
00059                         << kit->response << " "
00060                         << kit->octave << " "
00061                         << laplacians[kit - keys.begin()] << " ";
00062 
00063                 for(int i = 0; i < L; ++i, ++dit){
00064                         f << *dit << " ";
00065                 }
00066                 f << endl;
00067         }
00068 
00069         f.close();
00070 }
00071 
00072 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00073 
00074 void SurfSet::LoadCustom(const std::string &filename)
00075 {
00076         keys.resize(0);
00077         descriptors.resize(0);
00078         laplacians.resize(0);
00079         delete m_index; m_index = NULL;
00080 
00081         fstream f(filename.c_str(), ios::in);
00082         if(!f.is_open()) throw string("SurfSet: cannot open ") + filename;
00083 
00084         int N, L;
00085         f >> N >> L;
00086 
00087         if (f.is_open() && !f.fail() ){
00088                 keys.resize(N);
00089                 descriptors.resize(N * L);
00090                 laplacians.resize(N);
00091 
00092                 vector<float>::iterator dit = descriptors.begin();
00093                 for(int i = 0; i < N; ++i){
00094                         cv::KeyPoint& k = keys[i];
00095 
00096                         f >> k.pt.x >> k.pt.y >> k.angle >> k.size >> k.response
00097                                 >> k.octave >> laplacians[i];
00098 
00099                         for(int j = 0; j < L; ++j, ++dit){
00100                                 f >> *dit;
00101                         }
00102                 }
00103         }else{
00104           throw string("SurfSet: cannot read file ") + filename;
00105         }
00106 
00107         f.close();
00108 }
00109 
00110 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00111 
00112 void SurfSet::Extract(const cv::Mat &image, double hessianTh, bool extended)
00113 {
00114   // OpenCV 2.4 implementation
00115   
00116   cv::SURF surf;
00117   surf.set("hessianThreshold", hessianTh);
00118   surf.set("extended", extended);
00119   
00120   cv::Mat descs;
00121   surf(image, cv::Mat() /* mask */, this->keys, descs);
00122   
00123   if(this->keys.empty())
00124   {
00125     this->descriptors.clear();
00126     this->laplacians.clear();
00127   }
00128   else
00129   {
00130     this->descriptors.resize(this->keys.size() * descs.cols);
00131     this->laplacians.resize(this->keys.size());
00132     
00133     vector<cv::KeyPoint>::const_iterator kit;
00134     vector<int>::iterator lit = this->laplacians.begin();
00135     for(kit = this->keys.begin(); kit != this->keys.end(); ++kit, ++lit)
00136     {
00137       *lit = kit->class_id; // laplacian sign should be stored here
00138     }
00139     
00140     assert(descs.type() == CV_32F && descs.isContinuous());
00141     
00142     std::copy(descs.ptr<float>(), descs.ptr<float>() + (descs.rows * descs.cols),
00143       this->descriptors.begin());
00144   }
00145   
00146   /* // old implementation opencv 2.0
00147   CvSeq *kp1=NULL;
00148   CvSeq *desc1=NULL;
00149   CvMemStorage *storage = cvCreateMemStorage(0);
00150 
00151   IplImage ipl_image = IplImage(image);
00152   cvExtractSURF(&ipl_image, NULL, &kp1, &desc1, storage,
00153     cvSURFParams(hessianTh, (extended ? 1: 0) ));
00154 
00155   const CvSURFParams params=cvSURFParams(hessianTh, (extended ? 1: 0) );
00156   CvSeqReader reader, kreader;
00157   cvStartReadSeq( desc1, &reader, 0 );
00158   cvStartReadSeq( kp1, &kreader, 0 );
00159 
00160   const int L = (extended ? 128 : 64);
00161 
00162   descriptors.resize(desc1->total * L);
00163   keys.resize(kp1->total);
00164   laplacians.resize(kp1->total);
00165 
00166   for( int i = 0; i < desc1->total; i++ )
00167   {
00168     const CvSURFPoint *p= (const CvSURFPoint*)kreader.ptr;
00169     const float* vec = (const float*)reader.ptr;
00170     CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
00171     CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
00172 
00173     keys[i].pt.x = p->pt.x;
00174     keys[i].pt.y = p->pt.y;
00175     keys[i].angle = p->dir;
00176     keys[i].size = (float)p->size;
00177     keys[i].response = p->hessian;
00178     keys[i].octave = getPointOctave(*p, params);
00179     laplacians[i] = p->laplacian;
00180 
00181     for(int j = 0; j < L; ++j){
00182         descriptors[i*L + j] = vec[j];
00183     }
00184   }
00185 
00186   cvReleaseMemStorage(&storage);
00187   */
00188 }
00189 
00190 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00191 
00192 void SurfSet::Compute(const cv::Mat &image,
00193     const std::vector<cv::KeyPoint> &keypoints, bool extended)
00194 {
00195   // OpenCV 2.4 implementation
00196   if(keypoints.empty())
00197   {
00198     this->keys.clear();
00199     this->descriptors.clear();
00200     this->laplacians.clear();
00201   }
00202   else
00203   {
00204     this->keys = keypoints;
00205 
00206     cv::SURF surf;
00207     surf.set("extended", extended);
00208     
00209     cv::Mat descs;
00210     surf(image, cv::Mat() /* mask */, this->keys, descs, true);
00211   
00212     this->descriptors.resize(this->keys.size() * descs.cols);
00213     this->laplacians.resize(this->keys.size());
00214     
00215     vector<cv::KeyPoint>::const_iterator kit;
00216     vector<int>::iterator lit = this->laplacians.begin();
00217     for(kit = this->keys.begin(); kit != this->keys.end(); ++kit, ++lit)
00218     {
00219       *lit = kit->class_id; // laplacian sign should be stored here
00220     }
00221     
00222     assert(descs.type() == CV_32F && descs.isContinuous());
00223     
00224     std::copy(descs.ptr<float>(), descs.ptr<float>() + (descs.rows * descs.cols),
00225       this->descriptors.begin());
00226   }
00227 
00228   /*
00229   const int L = (extended ? 128 : 64);
00230   
00231   keys = keypoints;
00232   laplacians.resize(keys.size());
00233   descriptors.resize(keys.size() * L);
00234 
00235   std::fill(laplacians.begin(), laplacians.end(), 1);
00236 
00237   CvSeqWriter writer;
00238   CvMemStorage *storage = cvCreateMemStorage(0);
00239   cvStartWriteSeq(0, sizeof(CvSeq), sizeof(CvSURFPoint), storage, &writer);
00240   CvSURFPoint p;
00241 
00242   std::vector<cv::KeyPoint>::const_iterator kit;
00243   for(kit = keypoints.begin(); kit != keypoints.end(); ++kit)
00244   {
00245     p.pt.x = kit->pt.x;
00246     p.pt.y = kit->pt.y;
00247     p.dir = kit->angle;
00248     p.size = kit->size;
00249     p.hessian = kit->response;
00250     p.laplacian = 1;
00251 
00252     CV_WRITE_SEQ_ELEM(p, writer);
00253   }
00254 
00255   CvSeq *kp1 = cvEndWriteSeq(&writer);
00256   CvSeq *desc1 = NULL;
00257 
00258   IplImage ipl_image = IplImage(image);
00259   cvExtractSURF(&ipl_image, NULL, &kp1, &desc1, storage,
00260     cvSURFParams(0, (extended ? 1: 0) ), 1); // use provided keypoints 
00261 
00262   CvSeqReader reader;
00263   cvStartReadSeq( desc1, &reader, 0 );
00264 
00265   assert(desc1->total == (int)keys.size()); // ### check
00266 
00267   for( int i = 0; i < desc1->total; i++ )
00268   {
00269     const float* vec = (const float*)reader.ptr;
00270     CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
00271 
00272     for(int j = 0; j < L; ++j){
00273         descriptors[i*L + j] = vec[j];
00274     }
00275   }
00276 
00277   cvReleaseMemStorage(&storage);
00278   */
00279 }
00280 
00281 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00282 
00283 void SurfSet::CalculateCorrespondences(const SurfSet &B,
00284                 vector<int> &corr_A, vector<int> &corr_B,
00285                 vector<double> *distances, bool remove_duplicates,
00286                 double max_ratio) const
00287 {
00288   calculateCorrespondencesNaive(B, corr_A, corr_B, distances,
00289     remove_duplicates, max_ratio);
00290 }
00291 
00292 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00293 
00294 void SurfSet::CalculateFastCorrespondences(const SurfSet &B,
00295                 vector<int> &corr_A, vector<int> &corr_B,
00296                 vector<double> *distances, bool remove_duplicates,
00297                 double max_ratio)
00298 {
00299   calculateCorrespondencesApproximate(B, corr_A, corr_B, distances,
00300     remove_duplicates, max_ratio);
00301 }
00302 
00303 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00304 
00305 void SurfSet::calculateCorrespondencesApproximate(const SurfSet &B,
00306                 std::vector<int> &A_corr, std::vector<int> &B_corr,
00307                 std::vector<double> *distances,
00308                 bool remove_duplicates, double max_ratio)
00309 {
00310   const int L = GetDescriptorLength();
00311 
00312   //const cv::Mat A_features( this->keys.size(), L, CV_32F,
00313   //  const_cast<float*>(&this->descriptors[0]) );
00314   const cv::Mat B_features( B.keys.size(), L, CV_32F,
00315     const_cast<float*>(&B.descriptors[0]) );
00316 
00317   //const cv::Mat *features,
00318   const cv::Mat *queries;
00319   std::vector<int> *f_corr, *q_corr;
00320   /*
00321   if(this->keys.size() >= B.keys.size())
00322   {
00323     features = &A_features;
00324     queries = &B_features;
00325     f_corr = &A_corr;
00326     q_corr = &B_corr;
00327   }
00328   else
00329   {
00330     features = &B_features;
00331     queries = &A_features;
00332     f_corr = &B_corr;
00333     q_corr = &A_corr;
00334   }
00335   */
00336   queries = &B_features;
00337   f_corr = &A_corr;
00338   q_corr = &B_corr;
00339 
00340   cv::Mat indices(queries->rows, 2, CV_32S);
00341   cv::Mat dists(queries->rows, 2, CV_32F);
00342 
00343   if(!m_index) RecalculateApproximationTree();
00344   m_index->knnSearch(*queries, indices, dists, 2, cv::flann::SearchParams(64));
00345 
00346   A_corr.resize(0);
00347   B_corr.resize(0);
00348   if(distances) distances->resize(0);
00349 
00350   int* indices_ptr = indices.ptr<int>(0);
00351   float* dists_ptr = dists.ptr<float>(0);
00352 
00353   if(!remove_duplicates)
00354   {
00355     if(distances)
00356     {
00357       for (int i=0; i < indices.rows; ++i) {
00358         if (dists_ptr[2*i] < max_ratio * dists_ptr[2*i+1])
00359         {
00360           q_corr->push_back(i);
00361           f_corr->push_back(indices_ptr[2*i]);
00362           distances->push_back(dists_ptr[2*i]);
00363         }
00364       }
00365     } // if(distances)
00366     else
00367     {
00368       for (int i=0; i < indices.rows; ++i) {
00369         if (dists_ptr[2*i] < max_ratio * dists_ptr[2*i+1])
00370         {
00371           q_corr->push_back(i);
00372           f_corr->push_back(indices_ptr[2*i]);
00373         }
00374       }
00375     }
00376   } // if(!remove_duplicates)
00377   else
00378   {
00379     vector<int>::const_iterator it;
00380     if(distances)
00381     {
00382       for (int i=0; i < indices.rows; ++i) {
00383         if (dists_ptr[2*i] < max_ratio * dists_ptr[2*i+1])
00384         {
00385           int i_f = indices_ptr[2*i];
00386           float d_now = dists_ptr[2*i];
00387 
00388           it = find(f_corr->begin(), f_corr->end(), i_f);
00389           if(it != f_corr->end())
00390           {
00391             int i_before = it - f_corr->begin();
00392             float d_before = dists_ptr[2*i_before];
00393 
00394             if(d_now < d_before)
00395             {
00396               //update
00397               (*q_corr)[i_before] = i;
00398               (*f_corr)[i_before] = i_f;
00399               (*distances)[i_before] = d_now;
00400             }
00401           } // if(i_f is not in f_corr)
00402           else
00403           {
00404             q_corr->push_back(i);
00405             f_corr->push_back(indices_ptr[2*i]);
00406             distances->push_back(dists_ptr[2*i]);
00407           }
00408         } // if(d1/d2 < max_ratio)
00409       } // for each query sample
00410     } // if(distances)
00411     else
00412     {
00413       for (int i=0; i < indices.rows; ++i) {
00414         if (dists_ptr[2*i] < max_ratio * dists_ptr[2*i+1])
00415         {
00416           int i_f = indices_ptr[2*i];
00417           float d_now = dists_ptr[2*i];
00418 
00419           it = find(f_corr->begin(), f_corr->end(), i_f);
00420           if(it != f_corr->end())
00421           {
00422             int i_before = it - f_corr->begin();
00423             float d_before = dists_ptr[2*i_before];
00424 
00425             if(d_now < d_before)
00426             {
00427               //update
00428               (*q_corr)[i_before] = i;
00429               (*f_corr)[i_before] = i_f;
00430             }
00431           } // if(i_f is not in f_corr)
00432           else
00433           {
00434             q_corr->push_back(i);
00435             f_corr->push_back(indices_ptr[2*i]);
00436           }
00437         } // if(d1/d2 < max_ratio)
00438       } // for each query sample
00439     } // if(!distances)
00440   } // if(remove_duplicates)
00441 
00442 }
00443 
00444 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00445 
00446 void SurfSet::calculateCorrespondencesNaive(const SurfSet &B,
00447                 vector<int> &corr_A, vector<int> &corr_B,
00448                 vector<double> *distances, bool remove_duplicates,
00449                 double max_ratio) const
00450 {
00451 
00452   const SurfSet& A = *this;
00453 
00454   corr_A.clear();
00455   corr_B.clear();
00456 
00457   bool deallocate;
00458   if(distances)
00459   {
00460     deallocate = false;
00461   }else{
00462     distances = new vector<double>;
00463     deallocate = true;
00464   }
00465 
00466   int L = 0;
00467   if(!A.keys.empty()) L = A.descriptors.size() / A.keys.size();
00468 
00469   vector<float>::const_iterator da;
00470   vector<float>::const_iterator db;
00471 
00472   da = A.descriptors.begin();
00473   for(unsigned int a = 0; a < A.keys.size(); ++a, da += L)
00474   {
00475     double best_1 = 1e9;
00476     double best_2 = 1e9;
00477     int best_b = 0;
00478 
00479     db = B.descriptors.begin();
00480     for(unsigned int b = 0; b < B.keys.size(); ++b, db += L)
00481     {
00482       if(A.laplacians[a] == B.laplacians[b]){
00483         double d = calculateSqDistance(da, db, L);
00484 
00485         if(d < best_1){
00486           best_2 = best_1;
00487           best_1 = d;
00488           best_b = b;
00489         }else if(d < best_2){
00490           best_2 = d;
00491         }
00492       }
00493     }
00494 
00495     // best_ distances are square
00496     if(best_1 / best_2 < max_ratio*max_ratio)
00497     {
00498       // candidate found
00499       if(remove_duplicates)
00500       {
00501         // check that the B's point has not already been used
00502         // by another scene point.
00503         // in that case, select that with the minimum distance
00504         vector<int>::const_iterator it =
00505           find(corr_B.begin(), corr_B.end(), best_b);
00506 
00507         if(it == corr_B.end()){
00508           // add it
00509           corr_A.push_back(a);
00510           corr_B.push_back(best_b);
00511           distances->push_back(best_1);
00512         }else{
00513           int corr_idx = it - corr_B.begin();
00514           if(best_1 < (*distances)[ corr_idx ]){
00515             // update
00516             corr_A[corr_idx] = a;
00517             (*distances)[corr_idx] = best_1;
00518           }
00519         }
00520       } // if(remove_duplicates)
00521       else
00522       {
00523         // add it
00524         corr_A.push_back(a);
00525         corr_B.push_back(best_b);
00526         distances->push_back(best_1);
00527       }
00528     } // if ( < max_ratio )
00529 
00530   } // for each feature
00531 
00532   if(deallocate)
00533     delete distances;
00534   else
00535   {
00536     // remove the "square" from the distance values
00537     vector<double>::iterator dit;
00538     for(dit = distances->begin(); dit != distances->end(); ++dit)
00539     {
00540       *dit = sqrt(*dit);
00541     }
00542   }
00543 
00544 }
00545 
00546 
00547 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00548 
00549 double SurfSet::calculateSqDistance(
00550     vector<float>::const_iterator ita, vector<float>::const_iterator itb,
00551     const int L) const
00552 {
00553     double d = 0.0;
00554     for(int i = 0; i < L; i += 4, ita += 4, itb += 4)
00555     {
00556         d += (*ita - *itb)*(*ita - *itb);
00557         d += (*(ita+1) - *(itb+1))*(*(ita+1) - *(itb+1));
00558         d += (*(ita+2) - *(itb+2))*(*(ita+2) - *(itb+2));
00559         d += (*(ita+3) - *(itb+3))*(*(ita+3) - *(itb+3));
00560     }
00561     return d;
00562 }
00563 
00564 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00565 
00566 void SurfSet::RecalculateApproximationTree()
00567 {
00568   if(m_index) delete m_index;
00569 
00570   const int L = GetDescriptorLength();
00571   const cv::Mat features( this->keys.size(), L, CV_32F,
00572     const_cast<float*>(&this->descriptors[0]) );
00573 
00574   //m_index = new cv::flann::Index(features, cv::flann::KDTreeIndexParams(4));
00575   m_index = new cv::flann::Index(features, cv::flann::AutotunedIndexParams());
00576 }
00577 
00578 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00579 
00580 void SurfSet::Save(const std::string &filename) const
00581 {
00582   cv::FileStorage fs(filename.c_str(), cv::FileStorage::WRITE);
00583   save(fs, 0);
00584 }
00585 
00586 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00587 
00588 void SurfSet::save(cv::FileStorage &fs, int idx) const
00589 {
00590   stringstream ss;
00591   ss << "set" << idx;
00592 
00593   fs << ss.str() << "{";
00594 
00595   fs << "descriptor_length" << GetDescriptorLength();
00596   cv::write(fs, "keypoints", keys);
00597 
00598   cv::write(fs, "descriptors", descriptors);
00599   cv::write(fs, "laplacians", laplacians);
00600 
00601   /*
00602   if(!descriptors.empty())
00603     fs << "descriptors" << "[" << descriptors << "]";
00604   else
00605     fs << "descriptors" << "[" << "]";
00606 
00607   if(!laplacians.empty())
00608     fs << "laplacians" << "[" << laplacians << "]";
00609   else
00610     fs << "laplacians" << "[" << "]";
00611   */
00612 
00613   fs << "}";
00614 }
00615 
00616 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00617 
00618 void SurfSet::Load(const std::string &filename)
00619 {
00620   cv::FileStorage fs(filename.c_str(), cv::FileStorage::READ);
00621   load(fs, 0);
00622 }
00623 
00624 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00625 int SurfSet::getPointOctave(const CvSURFPoint& kpt, const CvSURFParams& params)
00626 {
00627     const int HAAR_SIZE0 = 9;
00628     const int HAAR_SIZE_INC = 6;
00629     int octave = 0, layer = 0, best_octave = 0;
00630     float min_diff = FLT_MAX;
00631     for( octave = 1; octave < params.nOctaves; octave++ )
00632         for( layer = 0; layer < params.nOctaveLayers; layer++ )
00633         {
00634             float diff = std::abs(kpt.size - (float)((HAAR_SIZE0 + HAAR_SIZE_INC*layer) << octave));
00635             if( min_diff > diff )
00636             {
00637                 min_diff = diff;
00638                 best_octave = octave;
00639                 if( min_diff == 0 )
00640                     return best_octave;
00641             }
00642         }
00643 
00644     return best_octave;
00645 }
00646 
00647 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00648 
00649 void SurfSet::load(cv::FileStorage &fs, int idx)
00650 {
00651   keys.resize(0);
00652   descriptors.resize(0);
00653   laplacians.resize(0);
00654   delete m_index; m_index = NULL;
00655 
00656   stringstream ss;
00657   ss << "set" << idx;
00658 
00659   cv::FileNode fn = fs[ss.str()];
00660 
00661   int L = (int)fn["descriptor_length"];
00662     
00663   cv::read(fn["keypoints"], keys);
00664   
00665   descriptors.resize(keys.size() * L);
00666   laplacians.resize(keys.size());
00667 
00668   cv::read(fn["descriptors"], descriptors);
00669   cv::read(fn["laplacians"], laplacians);
00670 }
00671 
00672 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00673 
00674 int SurfSet::getPointOctave(const CvSURFPoint& kpt, const CvSURFParams& params)
00675   const 
00676 {
00677   // these are as defined in opencv surf.cpp
00678   const int HAAR_SIZE0 = 9;
00679   const int HAAR_SIZE_INC = 6;
00680   
00681   int octave = 0, layer = 0, best_octave = 0;
00682   float min_diff = FLT_MAX;
00683   for( octave = 1; octave < params.nOctaves; octave++ )
00684     for( layer = 0; layer < params.nOctaveLayers; layer++ )
00685     {
00686       float diff = std::abs(kpt.size - 
00687         (float)((HAAR_SIZE0 + HAAR_SIZE_INC*layer) << octave));
00688       if( min_diff > diff )
00689       {
00690         min_diff = diff;
00691         best_octave = octave;
00692         if( min_diff == 0 )
00693           return best_octave;
00694       }
00695   }
00696   return best_octave;
00697 }
00698 


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:33:07