00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef USE_SIFT_GPU
00018 #include "sift_gpu_wrapper.h"
00019 #include <GL/gl.h>
00020 #include <iostream>
00021 #include <ros/ros.h>
00022 #include <stdio.h>
00023 #include "parameter_server.h"
00024 #include "scoped_timer.h"
00025 using namespace cv;
00026
00027 SiftGPUWrapper* SiftGPUWrapper::instance = NULL;
00028
00029 SiftGPUWrapper::SiftGPUWrapper() {
00030 gpu_mutex.lock();
00031 data = NULL;
00032 error = false;
00033 imageHeight = 0;
00034 imageWidth = 0;
00035 siftgpu = new SiftGPU();
00036 bool use_cuda = ParameterServer::instance()->get<bool>("siftgpu_with_cuda");
00037 char method[6];
00038 if(use_cuda){
00039 strcpy(method, "-cuda");
00040 } else {
00041 strcpy(method, "-glsl");
00042 }
00043
00044
00045 int max_features = ParameterServer::instance()->get<int>("max_keypoints");
00046 char max_flag[] = {"-tc2"};
00047 char max_feat_char[10]; sprintf(max_feat_char, "%d", max_features);
00048
00049 char subpixelKey[] = {"-s"};
00050 char subpixelValue[] = {"1"};
00051
00052 char unnormalized_descriptors[] = {"-unn"};
00053
00054 char verbosity[] = {"-v"};
00055 char verbosity_val[] = {"0"};
00056
00057 char first_octave[] = {"-fo"};
00058 char first_octave_val[] = {"-1"};
00059
00060 char edge_threshold[] = "-e";
00061 char edge_threshold_val[] = "10.0";
00062
00063 char dog_levels[] = "-d";
00064 char dog_levels_val[] = "5";
00065
00066 char nonfixedorientation[] = "-ofix-not";
00067 char * argv[] = {method,
00068 subpixelKey, subpixelValue,
00069 max_flag, max_feat_char,
00070 first_octave, first_octave_val,
00071 verbosity, verbosity_val,
00072 unnormalized_descriptors,
00073 dog_levels, dog_levels_val,
00074 edge_threshold, edge_threshold_val,
00075 nonfixedorientation};
00076
00077 siftgpu->ParseParam(15, argv);
00078
00079
00080
00081 if (siftgpu->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) {
00082 ROS_ERROR("Can't create OpenGL context! SiftGPU cannot be used.");
00083 error = true;
00084 }
00085
00086 isMatcherInitialized = false;
00087 gpu_mutex.unlock();
00088 }
00089
00090 SiftGPUWrapper::~SiftGPUWrapper() {
00091 gpu_mutex.lock();
00092 delete siftgpu;
00093 if (isMatcherInitialized) delete matcher;
00094 instance = NULL;
00095 if (data != NULL) {
00096 free(data);
00097 data = NULL;
00098 }
00099 gpu_mutex.unlock();
00100 }
00101
00102 void SiftGPUWrapper::destroyInstance() {
00103 delete instance;
00104 }
00105 SiftGPUWrapper* SiftGPUWrapper::getInstance() {
00106 if (instance == NULL) {
00107 ROS_DEBUG("Creating SiftGPU Instance");
00108 instance = new SiftGPUWrapper();
00109 }
00110 return instance;
00111 }
00112
00113 void SiftGPUWrapper::detect(const cv::Mat& image, cv::vector<cv::KeyPoint>& keypoints, std::vector<float>& descriptors, const Mat& mask) const {
00114 ScopedTimer s(__FUNCTION__);
00115 if (error) {
00116 keypoints.clear();
00117 ROS_FATAL("SiftGPU cannot be used. Detection of keypoints failed");
00118 }
00119
00120
00121 if(image.rows != imageHeight || image.cols != imageWidth){
00122 imageHeight = image.rows;
00123 imageWidth = image.cols;
00124 free(data);
00125 data = (unsigned char*) malloc(imageWidth * imageHeight);
00126 }
00127 cvMatToSiftGPU(image, data);
00128
00129 int num_features = 0;
00130 SiftGPU::SiftKeypoint* keys = 0;
00131
00133 if(keypoints.size() != 0){
00134 keys = new SiftGPU::SiftKeypoint[keypoints.size()];
00135 for(int i = 0; i < keypoints.size(); ++i){
00136 keys[i].x = keypoints[i].pt.x;
00137 keys[i].y = keypoints[i].pt.y;
00138 keys[i].o = keypoints[i].angle / 180.0 * 3.1415927;
00139 keys[i].s = keypoints[i].size / 12.0;
00140 }
00141 siftgpu->SetKeypointList(keypoints.size(), &keys[0]);
00142 }
00143
00144 gpu_mutex.lock();
00145 ROS_DEBUG("SIFTGPU: cols: %d, rows: %d", image.cols, image.rows);
00146 if (siftgpu->RunSIFT(image.cols, image.rows, data, GL_LUMINANCE, GL_UNSIGNED_BYTE)) {
00147 num_features = siftgpu->GetFeatureNum();
00148 ROS_DEBUG("Number of features found: %i", num_features);
00149 descriptors.resize(128 * num_features);
00150
00151 if(keypoints.size() == 0){
00152 keys = new SiftGPU::SiftKeypoint[num_features];
00153 siftgpu->GetFeatureVector(&keys[0], &descriptors[0]);
00154 }
00155 siftgpu->GetFeatureVector(NULL, &descriptors[0]);
00156 } else {
00157 ROS_WARN("SIFTGPU->RunSIFT() failed!");
00158 }
00159
00160
00161 keypoints.clear();
00162 for (int i = 0; i < num_features; ++i) {
00163 KeyPoint key(keys[i].x, keys[i].y, 12.0 * keys[i].s, keys[i].o * 180.0 / 3.1415927);
00164 keypoints.push_back(key);
00165 }
00166 gpu_mutex.unlock();
00167 }
00168
00169 int SiftGPUWrapper::match(
00170 const std::vector<float>& descriptors1,
00171 int num1,
00172 const std::vector<float>& descriptors2,
00173 int num2,
00174 std::vector<cv::DMatch>* matches) {
00175 if (!isMatcherInitialized)
00176 initializeMatcher();
00177
00178 float sumDistances = 0;
00179
00180 gpu_mutex.lock();
00181 matcher->SetDescriptors(0, num1, &descriptors1[0]);
00182 matcher->SetDescriptors(1, num2, &descriptors2[0]);
00183
00184 int (*match_buf)[2] = new int[num1][2];
00185 int number = matcher->GetSiftMatch(num1, match_buf, 0.9, 0.9);
00186
00187 if (matches->size() != 0) {
00188 ROS_WARN("Clearing matches vector!");
00189 matches->clear();
00190 }
00191
00192 cv::DMatch match;
00193 int counter = 0;
00194
00195 for (int i = 0; i < number; i++) {
00196 match.queryIdx = match_buf[i][0];
00197 match.trainIdx = match_buf[i][1];
00198
00199
00200 if (match.queryIdx == 0 || match.trainIdx == 0) {
00201 counter++;
00202 }
00203
00204 if (counter > 0.5 * number) {
00205 matches->clear();
00206 sumDistances = 0;
00207 ROS_ERROR("Matches bad due to context error");
00208 break;
00209 }
00210
00211 float sum = 0;
00212 for (int j = 0; j < 128; j++) {
00213 float a = descriptors1[match.queryIdx * 128 + j] - descriptors2[match.trainIdx * 128 + j];
00214 sum += a * a;
00215 }
00216
00217 match.distance = sqrt(sum);
00218 sumDistances += match.distance;
00219 matches->push_back(match);
00220 ROS_DEBUG("Matched Features %d and %d with distance of %f. Sum: %f", match.queryIdx, match.trainIdx, match.distance, sumDistances);
00221 }
00222
00223 delete[] match_buf;
00224
00225 gpu_mutex.unlock();
00226 return sumDistances;
00227 }
00228
00229 void SiftGPUWrapper::initializeMatcher() {
00230 gpu_mutex.lock();
00231 matcher = CreateNewSiftMatchGPU(4096);
00232 if (!matcher->VerifyContextGL()) {
00233 ROS_FATAL("Can't create OpenGL context! SiftGPU Matcher cannot be used.\nYou probably have no OpenGL support. You can use a different type of matcher though, e.g. FLANN.");
00234 error = true;
00235 return;
00236 }
00237 ROS_INFO("SiftGPU matcher initialized successfully.");
00238 isMatcherInitialized = true;
00239 gpu_mutex.unlock();
00240 }
00241
00242 void SiftGPUWrapper::cvMatToSiftGPU(const Mat& image, unsigned char* siftImage) const {
00243 ScopedTimer s(__FUNCTION__);
00244 Mat tmp;
00245 image.convertTo(tmp, CV_8U);
00246 for (int y = 0; y < tmp.rows; ++y) {
00247 for (int x = 0; x < tmp.cols; ++x) {
00248 siftImage[y * tmp.cols + x] = tmp.at<unsigned char> (y, x);
00249 }
00250 }
00251 }
00252
00253 void SiftGPUWrapper::writePGM(FILE *fp, unsigned char* data, int width, int height)
00254 {
00255 int val;
00256 fprintf(fp, "P5\n%d %d\n255\n", width, height);
00257
00258 for (int y = 0; y < height; y++) {
00259 for (int x = 0; x < width; x++) {
00260 val = (int) (data[y * width + x]);
00261 if (x == 0) val = 255;
00262 if (y == 0) val = 255;
00263 fputc(MAX(0, MIN(255, val)), fp);
00264 }
00265 }
00266 }
00267 #endif