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 
00025 using namespace cv;
00026 
00027 SiftGPUWrapper* SiftGPUWrapper::instance = NULL;
00028 
00029 SiftGPUWrapper::SiftGPUWrapper() {
00030     gpu_mutex.lock();
00031     error = false;
00032     siftgpu = new SiftGPU();
00033 
00034 #if defined(SIFT_GPU_MODE) and SIFT_GPU_MODE == 1
00035     char method[] = {"-cuda"};
00036 #elif defined(SIFT_GPU_MODE) and SIFT_GPU_MODE == 2
00037     char method[] = {"-glsl"};
00038 #endif
00039 
00040     //sprintf(method, "%s", ParameterServer::instance()->get<bool>("cuda_available") ? "-cuda" : "-glsl");
00041     int max_features = ParameterServer::instance()->get<int>("max_keypoints");
00042     char max_feat_char[10];
00043     sprintf(max_feat_char, "%d", max_features);
00044     //ROS_INFO("Max_feat_char %s", max_feat_char);
00045     char subpixelKey[] = {"-s"};
00046     char subpixelValue[] = {"1"};
00047     char max_flag[] = {"-tc2"};
00048     //char resize_storage_on_demand[] = {"-tight"};
00049     //char unnormalized_descriptors[] = {"-unn"};
00050     char verbosity[] = {"-v"};//nothing but errors
00051     char verbosity_val[] = {"0"};//nothing but errors
00052     //char * argv[] = {method, "-t", "10", subpixelKey, subpixelValue, max_flag, max_feat_char};
00053     char first_octave[] = {"-fo"};
00054     char first_octave_val[] = {"-1"};
00055     char * argv[] = {method,  subpixelKey, subpixelValue, \
00056                      max_flag, max_feat_char, first_octave,  \
00057                      first_octave_val, verbosity, verbosity_val}; /*, resize_storage_on_demand};
00058                      unnormalized_descriptors, \
00059                      "-e", "50.0" };//, "-t", "0.005"};*/
00060     siftgpu->ParseParam(9, argv);
00061 
00062     if (siftgpu->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) {
00063         ROS_ERROR("Can't create OpenGL context! SiftGPU cannot be used.");
00064         error = true;
00065     }
00066 
00067     data = (unsigned char*) malloc(imageWidth * imageHeight);
00068 
00069     isMatcherInitialized = false;
00070     gpu_mutex.unlock();
00071 }
00072 
00073 SiftGPUWrapper::~SiftGPUWrapper() {
00074     gpu_mutex.lock();
00075     delete siftgpu;
00076     if (isMatcherInitialized) delete matcher;
00077     instance = NULL;
00078     if (data != NULL) {
00079         free(data);
00080         data = NULL;
00081     }
00082     gpu_mutex.unlock();
00083 }
00084 
00085 void SiftGPUWrapper::destroyInstance() {
00086     delete instance;
00087 }
00088 SiftGPUWrapper* SiftGPUWrapper::getInstance() {
00089     if (instance == NULL) {
00090         ROS_INFO("Create Instance");
00091         instance = new SiftGPUWrapper();
00092     }
00093     return instance;
00094 }
00095 
00096 void SiftGPUWrapper::detect(const cv::Mat& image, cv::vector<cv::KeyPoint>& keypoints, std::vector<float>& descriptors, const Mat& mask) const {
00097     if (error) {
00098         keypoints.clear();
00099         ROS_FATAL("SiftGPU cannot be used. Detection of keypoints failed");
00100     }
00101 
00102     //get image
00103     cvMatToSiftGPU(image, data);
00104 
00105     int num_features = 0;
00106     SiftGPU::SiftKeypoint* keys = 0;
00107 
00108     gpu_mutex.lock();
00109     ROS_DEBUG("SIFTGPU: cols: %d, rows: %d", image.cols, image.rows);
00110     if (siftgpu->RunSIFT(image.cols, image.rows, data, GL_LUMINANCE, GL_UNSIGNED_BYTE)) {
00111         num_features = siftgpu->GetFeatureNum();
00112         ROS_INFO("Number of features found: %i", num_features);
00113         keys = new SiftGPU::SiftKeypoint[num_features];
00114         descriptors.resize(128 * num_features);
00115         //descriptors = new float[128 * num_features];
00116         siftgpu->GetFeatureVector(&keys[0], &descriptors[0]);
00117     } else {
00118         ROS_WARN("SIFTGPU->RunSIFT() failed!");
00119     }
00120 
00121     //copy to opencv structure
00122     keypoints.clear();
00123     for (int i = 0; i < num_features; ++i) {
00124         KeyPoint key(keys[i].x, keys[i].y, 6.0 * keys[i].s, keys[i].o); // 6 x scale is the conversion to pixels, according to changchang wu (the author of siftgpu)
00125         keypoints.push_back(key);
00126     }
00127     gpu_mutex.unlock();
00128 
00129 }
00130 
00131 int SiftGPUWrapper::match(
00132         const std::vector<float>& descriptors1,
00133         int num1,
00134         const std::vector<float>& descriptors2,
00135         int num2,
00136         std::vector<cv::DMatch>* matches) {
00137     if (!isMatcherInitialized)
00138         initializeMatcher();
00139 
00140     float sumDistances = 0;
00141 
00142     gpu_mutex.lock();
00143     matcher->SetDescriptors(0, num1, &descriptors1[0]);
00144     matcher->SetDescriptors(1, num2, &descriptors2[0]);
00145 
00146     int (*match_buf)[2] = new int[num1][2];
00147     int number = matcher->GetSiftMatch(num1, match_buf, 0.9, 0.9);
00148 
00149     if (matches->size() != 0) {
00150         ROS_WARN("Clearing matches vector!");
00151         matches->clear();
00152     }
00153 
00154     cv::DMatch match;
00155     int counter = 0;
00156 
00157     for (int i = 0; i < number; i++) {
00158         match.queryIdx = match_buf[i][0];
00159         match.trainIdx = match_buf[i][1];
00160 
00161         //only use matches with indices != 0 (opengl context problem may sometimes happen)
00162         if (match.queryIdx == 0 || match.trainIdx == 0) {
00163             counter++;
00164         }
00165 
00166         if (counter > 0.5 * number) {
00167             matches->clear();
00168             sumDistances = 0;
00169             ROS_ERROR("Matches bad due to context error");
00170             break;
00171         }
00172 
00173         float sum = 0;
00174         for (int j = 0; j < 128; j++) {
00175             float a = descriptors1[match.queryIdx * 128 + j] - descriptors2[match.trainIdx * 128 + j];
00176             sum += a * a;
00177         }
00178 
00179         match.distance = sqrt(sum);
00180         sumDistances += match.distance;
00181         matches->push_back(match);
00182         ROS_DEBUG("Matched Features %d and %d with distance of %f. Sum: %f", match.queryIdx, match.trainIdx, match.distance, sumDistances);
00183     }
00184 
00185     delete[] match_buf;
00186 
00187     gpu_mutex.unlock();
00188     return sumDistances;
00189 }
00190 
00191 void SiftGPUWrapper::initializeMatcher() {
00192     gpu_mutex.lock();
00193     matcher = CreateNewSiftMatchGPU(4096);
00194     if (!matcher->VerifyContextGL()) {
00195         ROS_FATAL("Can't create OpenGL context! SiftGPU Matcher cannot be used.");
00196         error = true;
00197         return;
00198     }
00199     ROS_INFO("matcher - ok");
00200     isMatcherInitialized = true;
00201     gpu_mutex.unlock();
00202 }
00203 
00204 void SiftGPUWrapper::cvMatToSiftGPU(const Mat& image,
00205         unsigned char* siftImage) const {
00206     Mat tmp;
00207     image.convertTo(tmp, CV_8U);
00208     for (int y = 0; y < tmp.rows; ++y) {
00209         for (int x = 0; x < tmp.cols; ++x) {
00210             siftImage[y * tmp.cols + x] = tmp.at<unsigned char> (y, x);
00211         }
00212     }
00213 }
00214 
00215 void SiftGPUWrapper::writePGM(FILE *fp, unsigned char* data, int width, int height)
00216 {
00217     int val;
00218     fprintf(fp, "P5\n%d %d\n255\n", width, height);
00219 
00220     for (int y = 0; y < height; y++) {
00221         for (int x = 0; x < width; x++) {
00222             val = (int) (/*255.0 */data[y * width + x]);
00223             if (x == 0) val = 255;
00224             if (y == 0) val = 255;
00225             fputc(MAX(0, MIN(255, val)), fp);
00226         }
00227     }
00228 }
00229 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


rgbdslam
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Wed Dec 26 2012 15:53:09