00001
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include <iostream>
00044 #include <vector>
00045 #include <boost/program_options.hpp>
00046 #include <gpusurf/GpuSurfDetector.hpp>
00047 #include "assert_macros.hpp"
00048 #include <opencv/highgui.h>
00049 #include <opencv/cv.h>
00050 #include <opencv/cv.hpp>
00051 #include <fstream>
00052 #include "CudaSynchronizedMemory.hpp"
00053 #include "gpu_utils.h"
00054 #include "gpu_globals.h"
00055 #include <opencv/highgui.h>
00056 #include <opencv/highgui.hpp>
00057
00058 void drawKeypoints(std::vector<cv::KeyPoint> const & keypoints, cv::Mat & image)
00059 {
00060 std::vector<cv::KeyPoint>::const_iterator k = keypoints.begin();
00061 cv::Scalar red(255,0,0);
00062 cv::Scalar blue(0,0,255);
00063 for( ; k != keypoints.end(); k++)
00064 {
00065 cv::Scalar * choice = NULL;
00066 if( isLastBitSet(k->response) )
00067 choice = &red;
00068 else
00069 choice = &blue;
00070
00071 cv::Point2f dir(k->pt);
00072 float st = k->size * sin(k->angle);
00073 float ct = k->size * cos(k->angle);
00074 dir.x += ct;
00075 dir.y += st;
00076 cv::circle(image, k->pt, (int)k->size, *choice, 1,CV_AA);
00077 cv::line(image, k->pt, dir, *choice, 1, CV_AA);
00078 }
00079 }
00080
00081 bool interestingStrengthIndex(std::pair<float,int> const & lhs, std::pair<float,int> const & rhs)
00082 {
00083 return lhs.first > rhs.first;
00084 }
00085
00086 std::string getFileBasename(std::string const & filename)
00087 {
00088 size_t extIdx = filename.find_last_of('.');
00089 return filename.substr(0,extIdx);
00090 }
00091
00092 void load_keypoints(std::string const & inputKeypointFile, std::vector<cv::KeyPoint> & inKeypoints, int imRows, int imCols)
00093 {
00094 std::ifstream fin(inputKeypointFile.c_str());
00095 ASRL_ASSERT(fin.good(),"Unable to open keypoint file " << inputKeypointFile << " for reading");
00096
00097
00098 std::string line;
00099 std::getline(fin,line);
00100 int i = 1;
00101 while(!fin.eof())
00102 {
00103 std::istringstream lin(line);
00104 cv::KeyPoint k;
00105 lin >> k.pt.x;
00106 lin >> k.pt.y;
00107 lin >> k.size;
00108 lin >> k.response;
00109 lin >> k.angle;
00110 lin >> k.octave;
00111 int laplacian;
00112 lin >> laplacian;
00113 if(laplacian == 1)
00114 {
00115 setLastBit(k.response);
00116 }
00117 else
00118 {
00119 clearLastBit(k.response);
00120 }
00121
00122 ASRL_ASSERT_GE_LT(k.pt.x,0,imCols,"Keypoint " << i << " is out of bounds");
00123 ASRL_ASSERT_GE_LT(k.pt.y,0,imRows,"Keypoint " << i << " is out of bounds");
00124 ASRL_ASSERT_GE_LT(k.angle,-3.15,3.15,"Keypoint " << i << " angle is out of bounds");
00125 ASRL_ASSERT_GE_LT(k.size,1,100,"Keypoint " << i << " size is out of bounds");
00126 inKeypoints.push_back(k);
00127 std::getline(fin,line);
00128 i++;
00129 }
00130
00131 }
00132
00133 void save_keypoints(std::vector<cv::KeyPoint> const & keypoints,
00134 std::vector<float> const & descriptors,
00135 std::vector<std::pair<float,int> > const & strengthIndex,
00136 std::string const & imageFileName,
00137 bool noDescriptor)
00138 {
00139 std::string keypointFileName = getFileBasename(imageFileName) + "-gpusurf.key";
00140 std::ofstream fout(keypointFileName.c_str());
00141
00142
00143 for(unsigned i = 0; i < strengthIndex.size() ; i++)
00144 {
00145 cv::KeyPoint const & k = keypoints[ strengthIndex[i].second ];
00146 fout << k.pt.x << "\t"
00147 << k.pt.y << "\t"
00148 << k.size << "\t"
00149 << k.response << "\t"
00150 << k.angle << "\t"
00151 << k.octave << "\t"
00152 << isLastBitSet(k.response) << "\t";
00153
00154 if(! noDescriptor )
00155 {
00156 std::vector<float>::const_iterator d = descriptors.begin() + (strengthIndex[i].second * ASRL_SURF_DESCRIPTOR_DIM);
00157 for(int j = 0; j < ASRL_SURF_DESCRIPTOR_DIM; j++, d++)
00158 {
00159 fout << *d << "\t";
00160 }
00161 }
00162 fout << std::endl;
00163
00164 }
00165 fout.close();
00166 }
00167
00168 namespace po = boost::program_options;
00169
00170 int main(int argc, char * argv[])
00171 {
00172 std::vector<std::string> images;
00173
00174 try {
00175
00176 asrl::GpuSurfConfiguration configuration;
00177 int targetFeatures;
00178 int detectorType;
00179 bool noDescriptor;
00180 bool noOrientation;
00181 int device = 0;
00182 std::string inputFile;
00183 int demoCamera = 0;
00184
00185
00186 po::options_description desc("Options");
00187 desc.add_options()
00188 ("help,h", "produce help message")
00189 ("image",po::value<std::vector<std::string> >(&images),"Image filename")
00190 ("threshold,t",po::value<float>(&configuration.threshold)->default_value(0.1f),"The interest operator threshold")
00191 ("n-octaves,v",po::value<int>(&configuration.nOctaves)->default_value(4),"The number of octaves")
00192 ("n-intervals,i", po::value<int>(&configuration.nIntervals)->default_value(4),"The number of intervals")
00193 ("initial-scale,s",po::value<float>(&configuration.initialScale)->default_value(2.f),"The initial scale of the detector")
00194 ("l1",po::value<float>(&configuration.l1)->default_value(3.f/1.5f),"Filter parameter l1")
00195 ("l2",po::value<float>(&configuration.l2)->default_value(5.f/1.5f),"Filter parameter l2")
00196 ("l3",po::value<float>(&configuration.l3)->default_value(3.f/1.5f),"Filter parameter l3")
00197 ("l4",po::value<float>(&configuration.l4)->default_value(1.f/1.5f),"Filter parameter l4")
00198 ("edge-scale",po::value<float>(&configuration.edgeScale)->default_value(0.81f),"The edge rejection mask scale")
00199 ("initial-step",po::value<int>(&configuration.initialStep)->default_value(1),"The initial step in pixels")
00200 ("n-features,n",po::value<int>(&targetFeatures)->default_value(0),"The target number of features to return")
00201 ("debug-iimg","dump the integral image to disk. The integral image will be saved as imagename-iimg.bin")
00202 ("no-descriptor","don't compute the descriptor")
00203 ("no-orientation","don't compute orientation")
00204 ("fast-orientation","use an orientation calculation that is slightly faster")
00205 ("device",po::value<int>(&device)->default_value(0),"The cuda device to use")
00206 ("input-keypoints",po::value<std::string>(&inputFile),"Read the keypoints from a file, push them to the GPU then produce the orientation and descriptor. If used together with --no-orientation, the input orientation will be used.")
00207 ("detector-threads-x",po::value<int>(&configuration.detector_threads_x)->default_value(8),"The number of threads to use in the interest point detector kernel (dimension 1)")
00208 ("detector-threads-y",po::value<int>(&configuration.detector_threads_y)->default_value(8),"The number of threads to use in the interest point detector kernel (dimension 2)")
00209 ("nonmax-threads-x",po::value<int>(&configuration.nonmax_threads_x)->default_value(8),"The number of threads to use in the non-max suppression kernel (dimension 1)")
00210 ("nonmax-threads-y",po::value<int>(&configuration.nonmax_threads_y)->default_value(8),"The number of threads to use in the non-max suppression kernel (dimension 2)")
00211 ("run-demo","Use OpenCV to run a demo using the camera.")
00212 ("demo-camera",po::value<int>(&demoCamera)->default_value(0),"The camera index to use when running the demo.")
00213 ;
00214
00215 po::positional_options_description p;
00216 p.add("image", -1);
00217
00218 po::variables_map vm;
00219 po::store(po::command_line_parser(argc, argv).
00220 options(desc).positional(p).run(), vm);
00221
00222 po::notify(vm);
00223
00224 if (vm.count("help") || (vm.count("image") == 0 && ! vm.count("run-demo")) ) {
00225 std::cout << "Usage [options] image\n\n";
00226 std::cout << desc << "\n";
00227 return 1;
00228 }
00229
00230 bool debugHessian = vm.count("debug-hessian") > 0;
00231 bool debugIimg = vm.count("debug-iimg") > 0;
00232 noDescriptor = vm.count("no-descriptor") > 0;
00233 noOrientation = vm.count("no-orientation") > 0;
00234 bool fastOrientation = vm.count("fast-orientation") > 0;
00235
00236
00237
00238 cudaError_t err;
00239 int deviceCount;
00240 err = cudaGetDeviceCount(&deviceCount);
00241 ASRL_ASSERT_EQ(err,cudaSuccess, "Unable to get the CUDA device count: " << cudaGetErrorString(err));
00242 ASRL_ASSERT_GT(deviceCount,0,"There are no CUDA capable devices present");
00243 ASRL_ASSERT_GT(deviceCount,device,"Device index is out of bounds");
00244 err = cudaSetDevice(device);
00245 ASRL_ASSERT_EQ(err,cudaSuccess, "Unable to set the CUDA device: " << cudaGetErrorString(err));
00246
00247 if(vm.count("run-demo") > 0)
00248 {
00249 asrl::GpuSurfDetector detector(configuration);
00250 cv::VideoCapture vc(demoCamera);
00251 cv::Mat image, greyImage;
00252 std::string windowName = "Speeded Up SURF";
00253 cv::namedWindow(windowName,CV_WINDOW_AUTOSIZE);
00254 int key = cv::waitKey(5);
00255 std::vector<cv::KeyPoint> keypoints;
00256 bool success = vc.grab();
00257
00258 while(success && key == -1)
00259 {
00260 success = vc.retrieve(image);
00261 if(success)
00262 {
00263 cv::cvtColor(image,greyImage,CV_BGR2GRAY);
00264 detector.buildIntegralImage(greyImage);
00265 detector.detectKeypoints();
00266 if(!noOrientation)
00267 {
00268 if(fastOrientation)
00269 detector.findOrientationFast();
00270 else
00271 detector.findOrientation();
00272 }
00273 detector.getKeypoints(keypoints);
00274 drawKeypoints(keypoints,image);
00275 cv::imshow(windowName, image);
00276 key = cv::waitKey(5);
00277 success = vc.grab();
00278 }
00279 }
00280 }
00281 else if(vm.count("input-keypoints") > 0)
00282 {
00283 ASRL_ASSERT_EQ(images.size(),1,"Exactly one image must be supplied with a keypoint file");
00284
00285
00286 asrl::GpuSurfDetector detector(configuration);
00287 cv::Mat cvImage;
00288 cvImage = cv::imread(images[0],CV_LOAD_IMAGE_GRAYSCALE);
00289
00290 std::vector<cv::KeyPoint> inKeypoints;
00291 load_keypoints(inputFile,inKeypoints, cvImage.cols, cvImage.rows);
00292 detector.setKeypoints(inKeypoints);
00293 detector.buildIntegralImage(cvImage);
00294 if(! noOrientation )
00295 {
00296 if(fastOrientation)
00297 detector.findOrientationFast();
00298 else
00299 detector.findOrientation();
00300 }
00301 if(!noDescriptor)
00302 {
00303 detector.computeDescriptors();
00304 }
00305 std::vector<cv::KeyPoint> keypoints;
00306 std::vector<float> descriptors;
00307 detector.getKeypoints(keypoints);
00308 detector.getDescriptors(descriptors);
00309
00310
00311 std::vector<std::pair<float,int> > strengthIndex(keypoints.size());
00312 for(unsigned k = 0; k < keypoints.size(); k++)
00313 {
00314 strengthIndex[k].first = keypoints[k].response;
00315 strengthIndex[k].second = k;
00316 }
00317
00318 save_keypoints(keypoints, descriptors, strengthIndex,inputFile, noDescriptor);
00319 }
00320 else
00321 {
00322 ASRL_ASSERT_GT(images.size(),0,"No image filenames passed to application");
00323
00324 asrl::GpuSurfDetector detector(configuration);
00325 for(unsigned i = 0; i < images.size(); i++)
00326 {
00327 cv::Mat cvImage;
00328 cvImage = cv::imread(images[i],CV_LOAD_IMAGE_GRAYSCALE);
00329
00330 detector.buildIntegralImage(cvImage);
00331
00332 detector.detectKeypoints();
00333 if(! noOrientation )
00334 {
00335 if(fastOrientation)
00336 detector.findOrientationFast();
00337 else
00338 detector.findOrientation();
00339 }
00340
00341 if(!noDescriptor)
00342 {
00343 detector.computeDescriptors();
00344 }
00345
00346 std::vector<cv::KeyPoint> keypoints;
00347 std::vector<float> descriptors;
00348 detector.getKeypoints(keypoints);
00349 detector.getDescriptors(descriptors);
00350
00351
00352 std::vector<std::pair<float,int> > strengthIndex(keypoints.size());
00353 for(unsigned k = 0; k < keypoints.size(); k++)
00354 {
00355 strengthIndex[k].first = keypoints[k].response;
00356 strengthIndex[k].second = k;
00357 }
00358
00359
00360 if(targetFeatures > 0 && (int)keypoints.size() > targetFeatures)
00361 {
00362 std::partial_sort(strengthIndex.begin(), strengthIndex.begin() + targetFeatures, strengthIndex.end(), &interestingStrengthIndex);
00363 strengthIndex.resize(targetFeatures);
00364 }
00365
00366 save_keypoints(keypoints, descriptors, strengthIndex, images[i], noDescriptor);
00367
00368 if(debugIimg)
00369 {
00370 detector.saveIntegralImage(getFileBasename(images[i]));
00371 }
00372 }
00373 }
00374
00375
00376 }
00377 catch(std::exception const & e)
00378 {
00379 std::cout << "Exception during processing " << e.what() << std::endl;
00380 }
00381
00382 return 0;
00383 }
00384