sift_des.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Georgia Institute of Technology
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Georgia Institute of Technology nor the names of
00018  *     its contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 #ifndef sift_des_h_DEFINED
00036 #define sift_des_h_DEFINED
00037 
00038 #include <opencv2/core/core.hpp>
00039 #include <opencv2/imgproc/imgproc.hpp>
00040 #include <opencv2/features2d/features2d.hpp>
00041 #include <opencv2/nonfree/features2d.hpp>
00042 #include <opencv2/ml/ml.hpp>
00043 #include "abstract_feature.h"
00044 #include <vector>
00045 #include <iostream>
00046 #include <sstream>
00047 #include <fstream>
00048 
00049 namespace cpl_visual_features
00050 {
00051 
00052 typedef std::vector<float> SIFTFeature;
00053 typedef std::vector<SIFTFeature> SIFTFeatures;
00054 
00055 template <int x_stride, int y_stride, int n_scales, bool extract_keypoints> class SIFTDes
00056     : public AbstractFeature<std::vector<float> >
00057 {
00058  public:
00059   SIFTDes() : sift_()
00060   {
00061   }
00062 
00063   virtual void operator()(cv::Mat& img, cv::Rect& window)
00064   {
00065     cv::Mat img_bw(img.size(), CV_8UC1);
00066     cv::cvtColor(img, img_bw, CV_RGB2GRAY);
00067     SIFTFeatures raw_feats = extractRawFeatures(img_bw);
00068     descriptor_.clear();
00069     std::vector<float> desc(centers_.size(), 0);
00070     for (unsigned int i = 0; i < raw_feats.size(); ++i)
00071     {
00072       int label = quantizeFeature(raw_feats[i]);
00073       if (label < 0 || label > (int)desc.size())
00074       {
00075         std::cerr << "Quantized label " << label << " out of allowed range!"
00076                   << std::endl;
00077       }
00078       desc[label] += 1.0;
00079     }
00080     descriptor_ = desc;
00081   }
00082 
00083   virtual std::vector<float> getDescriptor() const
00084   {
00085     return descriptor_;
00086   }
00087 
00088   SIFTFeatures getCenters() const
00089   {
00090     return centers_;
00091   }
00092 
00093   SIFTFeatures extractRawFeatures(cv::Mat& frame)
00094   {
00095     SIFTFeatures feats;
00096     for (int s = 0; s < n_scales; ++s)
00097     {
00098       cv::Mat tmp = frame;
00099       if (s > 0)
00100       {
00101         cv::Size down_size;
00102         down_size.width = frame.cols/2;
00103         down_size.height = frame.rows/2;
00104         cv::pyrDown(tmp, frame, down_size);
00105       }
00106       cv::Mat raw_descriptor;
00107 
00108       if (extract_keypoints)
00109       {
00110         std::vector<cv::KeyPoint> cur_keypoints;
00111         sift_(frame, cv::Mat(), cur_keypoints, raw_descriptor, false);
00112       }
00113       else
00114       {
00115         std::vector<cv::KeyPoint> keypoint_locs;
00116         for (int x = 0; x < frame.cols; x += x_stride)
00117         {
00118           for (int y = 0; y < frame.rows; y += y_stride)
00119           {
00120             keypoint_locs.push_back(cv::KeyPoint(x,y,1));
00121           }
00122         }
00123         sift_(frame, cv::Mat(), keypoint_locs, raw_descriptor, true);
00124       }
00125 
00126       for (int r = 0; r < raw_descriptor.rows; ++r)
00127       {
00128         SIFTFeature f;
00129         for (int c = 0; c < raw_descriptor.cols; ++c)
00130         {
00131           f.push_back(raw_descriptor.at<float>(r,c));
00132         }
00133         feats.push_back(f);
00134       }
00135     }
00136     return feats;
00137   }
00138 
00139   SIFTFeatures clusterFeatures(SIFTFeatures samples, int k, int attempts)
00140   {
00141 
00142     // Convert the input samples into the correct format of a row per sample.
00143     int num_rows = samples.size();
00144     cv::Mat row_samples(num_rows, 128, CV_32FC1);
00145 
00146     for (unsigned int i = 0; i < samples.size(); ++i)
00147     {
00148       for (unsigned int j = 0; j < samples[i].size(); ++j)
00149       {
00150         row_samples.at<float>(i,j) = samples[i][j];
00151       }
00152     }
00153 
00154     // Construct variables needed for running kmeans
00155     cv::Mat labels;
00156     cv::Mat centers(k, 128, CV_32FC1);
00157     float epsilon = 0.01;
00158     int kmeans_max_iter = 100000;
00159 
00160     double compactness = cv::kmeans(row_samples, k, labels,
00161                                     cv::TermCriteria(CV_TERMCRIT_EPS +
00162                                                      CV_TERMCRIT_ITER,
00163                                                      kmeans_max_iter, epsilon),
00164                                     attempts, cv::KMEANS_PP_CENTERS, centers);
00165 
00166     SIFTFeatures sift_centers;
00167     for (int r = 0; r < centers.rows; ++r)
00168     {
00169       SIFTFeature feat;
00170       for (int c = 0; c < centers.cols; ++c)
00171       {
00172         feat.push_back(centers.at<float>(r,c));
00173       }
00174       sift_centers.push_back(feat);
00175     }
00176 
00177     return sift_centers;
00178   }
00179 
00180   void saveClusterCenters(SIFTFeatures centers, std::string file_name)
00181   {
00182     ROS_INFO_STREAM("Saving SIFT cluster centers to " << file_name.c_str());
00183 
00184     std::ofstream output(file_name.c_str());
00185     for (unsigned int i = 0; i < centers.size(); ++i)
00186     {
00187       for (unsigned int j = 0; j < centers[i].size(); ++j)
00188       {
00189         output << centers[i][j];
00190         if (j < centers[i].size() - 1)
00191           output << " ";
00192       }
00193       output << std::endl;
00194     }
00195 
00196     output.close();
00197   }
00198 
00199   bool loadClusterCenters(std::string file_name)
00200   {
00201     std::ifstream input(file_name.c_str());
00202     if (!input.good())
00203     {
00204       std::cerr << "Failed to open file" << file_name << std::endl;
00205       return false;
00206     }
00207 
00208     // Clear the centers currently loaded in the class
00209     centers_.clear();
00210 
00211     char line[1536];
00212 
00213     // Iterate through the lines of the file
00214     while( input.good() )
00215     {
00216       std::stringstream input_line(std::stringstream::in |
00217                                    std::stringstream::out);
00218       input.getline(line, 1536); // IS this long enough????
00219       input_line << line;
00220 
00221       SIFTFeature center;
00222 
00223       // Push back the line elements
00224       for(int i = 0; i < 128 && !input.eof(); ++i)
00225       {
00226         float val;
00227         input_line >> val;
00228         center.push_back(val);
00229       }
00230       centers_.push_back(center);
00231     }
00232     input.close();
00233 
00234     // This was the best way to ensure all codewords are read in, but no empty
00235     // centers are added
00236     if( centers_.back().size() != centers_[0].size() )
00237     {
00238       centers_.pop_back();
00239     }
00240     return true;
00241   }
00242 
00243   int quantizeFeature(SIFTFeature feat)
00244   {
00245     // TODO: use ANN or a kd-tree or something to speed this up
00246     float min_val = FLT_MAX;
00247     int min_idx = -1;
00248     for (unsigned int i = 0; i < centers_.size(); ++i)
00249     {
00250       float dist = featureDist(feat, centers_[i]);
00251       if (dist < min_val)
00252       {
00253         min_val = dist;
00254         min_idx = i;
00255       }
00256     }
00257 
00258     return min_idx;
00259   }
00260 
00261   float featureDist(SIFTFeature f1, SIFTFeature f2)
00262   {
00263     // Add sanity check for feature lengths
00264     // ROS_ASSERT_MSG(f1.size() == f2.size(),
00265     //                "f1 has size: %d. f2 has size: %d", f1.size(), f2.size());
00266     float dist = 0.0;
00267 
00268     for (unsigned int i = 0; i < f1.size(); ++i)
00269     {
00270       dist += std::abs(f1[i]-f2[i]);
00271     }
00272 
00273     return dist;
00274   }
00275 
00276  public:
00277   cv::SIFT sift_;
00278 
00279  protected:
00280   std::vector<float> descriptor_;
00281   SIFTFeatures centers_;
00282 };
00283 }
00284 #endif // sift_des_h_DEFINED


cpl_visual_features
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:52:36