sift_gpu_wrapper.cpp
Go to the documentation of this file.
00001 /* This file is part of RGBDSLAM.
00002  * 
00003  * RGBDSLAM is free software: you can redistribute it and/or modify
00004  * it under the terms of the GNU General Public License as published by
00005  * the Free Software Foundation, either version 3 of the License, or
00006  * (at your option) any later version.
00007  * 
00008  * RGBDSLAM is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  * 
00013  * You should have received a copy of the GNU General Public License
00014  * along with RGBDSLAM.  If not, see <http://www.gnu.org/licenses/>.
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     //sprintf(method, "%s", ParameterServer::instance()->get<bool>("cuda_available") ? "-cuda" : "-glsl");
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"};//nothing but errors
00056 
00057     char first_octave[] = {"-fo"};
00058     char first_octave_val[] = {"-1"}; //Slower than 0, more keypoints
00059 
00060     char edge_threshold[] = "-e"; 
00061     char edge_threshold_val[] = "10.0"; //Default: 10
00062 
00063     char dog_levels[] = "-d"; //This parameter affects the number of keypoints found
00064     char dog_levels_val[] = "5"; //Default: 3 (would result in less features for, e.g., blurry images)
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     //get image
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;//opencv uses degree
00139         keys[i].s = keypoints[i].size / 12.0;//Changchang Wu: "You can use 6*scale as the radius" and OpenCV uses diameter
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         //descriptors = new float[128 * num_features];
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     //copy to opencv structure
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); // 6 x scale is the conversion to pixels of the radius, according to changchang wu (the author of siftgpu). OpenCV uses Diameter and degree
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         //only use matches with indices != 0 (opengl context problem may sometimes happen)
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) (/*255.0 */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


rgbdslam_v2
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Thu Jun 6 2019 21:49:45