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
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
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
00045 char subpixelKey[] = {"-s"};
00046 char subpixelValue[] = {"1"};
00047 char max_flag[] = {"-tc2"};
00048
00049
00050 char verbosity[] = {"-v"};
00051 char verbosity_val[] = {"0"};
00052
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};
00058
00059
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
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
00116 siftgpu->GetFeatureVector(&keys[0], &descriptors[0]);
00117 } else {
00118 ROS_WARN("SIFTGPU->RunSIFT() failed!");
00119 }
00120
00121
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);
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
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) (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