00001 00002 // File: SimpleSIFT.cpp 00003 // Author: Changchang Wu 00004 // Description : A simple example shows how to use SiftGPU and SiftMatchGPU 00005 // 00006 // 00007 // 00008 // Copyright (c) 2007 University of North Carolina at Chapel Hill 00009 // All Rights Reserved 00010 // 00011 // Permission to use, copy, modify and distribute this software and its 00012 // documentation for educational, research and non-profit purposes, without 00013 // fee, and without a written agreement is hereby granted, provided that the 00014 // above copyright notice and the following paragraph appear in all copies. 00015 // 00016 // The University of North Carolina at Chapel Hill make no representations 00017 // about the suitability of this software for any purpose. It is provided 00018 // 'as is' without express or implied warranty. 00019 // 00020 // Please send BUG REPORTS to ccwu@cs.unc.edu 00021 // 00023 00024 00025 #include <stdlib.h> 00026 #include <vector> 00027 #include <iostream> 00028 using std::vector; 00029 using std::iostream; 00030 00031 00033 #if !defined(SIFTGPU_STATIC) && !defined(SIFTGPU_DLL_RUNTIME) 00034 // SIFTGPU_STATIC comes from compiler 00035 #define SIFTGPU_DLL_RUNTIME 00036 // Load at runtime if the above macro defined 00037 // comment the macro above to use static linking 00038 #endif 00039 00041 // define REMOTE_SIFTGPU to run computation in multi-process (Or remote) mode 00042 // in order to run on a remote machine, you need to start the server manually 00043 // This mode allows you use Multi-GPUs by creating multiple servers 00044 // #define REMOTE_SIFTGPU 00045 // #define REMOTE_SERVER NULL 00046 // #define REMOTE_SERVER_PORT 7777 00047 00048 00050 //#define DEBUG_SIFTGPU //define this to use the debug version in windows 00051 00052 #ifdef _WIN32 00053 #ifdef SIFTGPU_DLL_RUNTIME 00054 #define WIN32_LEAN_AND_MEAN 00055 #include <windows.h> 00056 #define FREE_MYLIB FreeLibrary 00057 #define GET_MYPROC GetProcAddress 00058 #else 00059 //define this to get dll import definition for win32 00060 #define SIFTGPU_DLL 00061 #ifdef _DEBUG 00062 #pragma comment(lib, "../../lib/siftgpu_d.lib") 00063 #else 00064 #pragma comment(lib, "../../lib/siftgpu.lib") 00065 #endif 00066 #endif 00067 #else 00068 #ifdef SIFTGPU_DLL_RUNTIME 00069 #include <dlfcn.h> 00070 #define FREE_MYLIB dlclose 00071 #define GET_MYPROC dlsym 00072 #endif 00073 #endif 00074 00075 #include "../SiftGPU/SiftGPU.h" 00076 00077 00078 int main() 00079 { 00080 #ifdef SIFTGPU_DLL_RUNTIME 00081 #ifdef _WIN32 00082 #ifdef _DEBUG 00083 HMODULE hsiftgpu = LoadLibrary("siftgpu_d.dll"); 00084 #else 00085 HMODULE hsiftgpu = LoadLibrary("siftgpu.dll"); 00086 #endif 00087 #else 00088 void * hsiftgpu = dlopen("libsiftgpu.so", RTLD_LAZY); 00089 #endif 00090 00091 if(hsiftgpu == NULL) return 0; 00092 00093 #ifdef REMOTE_SIFTGPU 00094 ComboSiftGPU* (*pCreateRemoteSiftGPU) (int, char*) = NULL; 00095 pCreateRemoteSiftGPU = (ComboSiftGPU* (*) (int, char*)) GET_MYPROC(hsiftgpu, "CreateRemoteSiftGPU"); 00096 ComboSiftGPU * combo = pCreateRemoteSiftGPU(REMOTE_SERVER_PORT, REMOTE_SERVER); 00097 SiftGPU* sift = combo; 00098 SiftMatchGPU* matcher = combo; 00099 #else 00100 SiftGPU* (*pCreateNewSiftGPU)(int) = NULL; 00101 SiftMatchGPU* (*pCreateNewSiftMatchGPU)(int) = NULL; 00102 pCreateNewSiftGPU = (SiftGPU* (*) (int)) GET_MYPROC(hsiftgpu, "CreateNewSiftGPU"); 00103 pCreateNewSiftMatchGPU = (SiftMatchGPU* (*)(int)) GET_MYPROC(hsiftgpu, "CreateNewSiftMatchGPU"); 00104 SiftGPU* sift = pCreateNewSiftGPU(1); 00105 SiftMatchGPU* matcher = pCreateNewSiftMatchGPU(4096); 00106 #endif 00107 00108 #elif defined(REMOTE_SIFTGPU) 00109 ComboSiftGPU * combo = CreateRemoteSiftGPU(REMOTE_SERVER_PORT, REMOTE_SERVER); 00110 SiftGPU* sift = combo; 00111 SiftMatchGPU* matcher = combo; 00112 #else 00113 //this will use overloaded new operators 00114 SiftGPU *sift = new SiftGPU; 00115 SiftMatchGPU *matcher = new SiftMatchGPU(4096); 00116 #endif 00117 vector<float > descriptors1(1), descriptors2(1); 00118 vector<SiftGPU::SiftKeypoint> keys1(1), keys2(1); 00119 int num1, num2; 00120 00121 //process parameters 00122 //The following parameters are default in V340 00123 //-m, up to 2 orientations for each feature (change to single orientation by using -m 1) 00124 //-s enable subpixel subscale (disable by using -s 0) 00125 00126 00127 char * argv[] = {"-fo", "-1", "-v", "1", "-cuda"};// 00128 //-fo -1 staring from -1 octave 00129 //-v 1 only print out # feature and overall time 00130 //-loweo add a (.5, .5) offset 00131 //-tc <num> set a soft limit to number of detected features 00132 00133 //NEW: parameters for GPU-selection 00134 //1. CUDA. Use parameter "-cuda", "[device_id]" 00135 //2. OpenGL + Windows. Use "-winpos", "XxY" to set a location on a specific monitor/GPU 00136 //3. OpenGL + Other OS. Use "-Display", "display_name" to select monitor/GPU (XLIB/GLUT) 00137 00139 //You use CUDA for nVidia graphic cards by specifying 00140 //-cuda : cuda implementation (fastest for smaller images) 00142 00145 // First, texture reallocation happens when image size increases, and too many 00146 // reallocation may lead to allocatoin failure. You should be careful when using 00147 // siftgpu on a set of images with VARYING imag sizes. It is recommended that you 00148 // preset the allocation size to the largest width and largest height by using function 00149 // AllocationPyramid or prameter '-p' (e.g. "-p", "1024x768"). 00150 00151 // Second, there is a parameter you may not be aware of: the allowed maximum working 00152 // dimension. All the SIFT octaves that needs a larger texture size will be skipped. 00153 // The default prameter is 2560 for the unpacked implementation and 3200 for the packed. 00154 // Those two default parameter is tuned to for 768MB of graphic memory. You should adjust 00155 // it for your own GPU memory. You can also use this to keep/skip the small featuers. 00156 // To change this, call function SetMaxDimension or use parameter "-maxd". 00158 00159 00160 int argc = sizeof(argv)/sizeof(char*); 00161 sift->ParseParam(argc, argv); 00162 00164 //Only the following parameters can be changed after initialization (by calling ParseParam). 00165 //-dw, -ofix, -ofix-not, -fo, -unn, -maxd, -b 00166 //to change other parameters at runtime, you need to first unload the dynamically loaded libaray 00167 //reload the libarary, then create a new siftgpu instance 00168 00169 00170 //Create a context for computation, and SiftGPU will be initialized automatically 00171 //The same context can be used by SiftMatchGPU 00172 if(sift->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) return 0; 00173 00174 if(sift->RunSIFT("../data/800-1.jpg")) 00175 { 00176 //Call SaveSIFT to save result to file, the format is the same as Lowe's 00177 //sift->SaveSIFT("../data/800-1.sift"); //Note that saving ASCII format is slow 00178 00179 //get feature count 00180 num1 = sift->GetFeatureNum(); 00181 00182 //allocate memory 00183 keys1.resize(num1); descriptors1.resize(128*num1); 00184 00185 //reading back feature vectors is faster than writing files 00186 //if you dont need keys or descriptors, just put NULLs here 00187 sift->GetFeatureVector(&keys1[0], &descriptors1[0]); 00188 //this can be used to write your own sift file. 00189 } 00190 00191 //You can have at most one OpenGL-based SiftGPU (per process). 00192 //Normally, you should just create one, and reuse on all images. 00193 //NEW: CUDA-implementation allows you to create multiple instances for multiple threads 00194 //Checkout src\TestWin\MultiThreadSIFT 00195 if(sift->RunSIFT("../data/640-1.jpg")) 00196 { 00197 num2 = sift->GetFeatureNum(); 00198 keys2.resize(num2); descriptors2.resize(128*num2); 00199 sift->GetFeatureVector(&keys2[0], &descriptors2[0]); 00200 } 00201 00202 //Testing code to check how it works when image size varies 00203 //sift->RunSIFT("../data/256.jpg");sift->SaveSIFT("../data/256.sift.1"); 00204 //sift->RunSIFT("../data/1024.jpg"); //this will result in pyramid reallocation 00205 //sift->RunSIFT("../data/256.jpg"); sift->SaveSIFT("../data/256.sift.2"); 00206 //two sets of features for 256.jpg may have different order due to implementation 00207 00208 //************************************************************************* 00210 00211 //Method1, set new keypoints for the image you've just processed with siftgpu 00212 //say vector<SiftGPU::SiftKeypoint> mykeys; 00213 //sift->RunSIFT(mykeys.size(), &mykeys[0]); 00214 //sift->RunSIFT(num2, &keys2[0], 1); sift->SaveSIFT("../data/640-1.sift.2"); 00215 //sift->RunSIFT(num2, &keys2[0], 0); sift->SaveSIFT("../data/640-1.sift.3"); 00216 00217 //Method2, set keypoints for the next coming image 00218 //The difference of with method 1 is that method 1 skips gaussian filtering 00219 //SiftGPU::SiftKeypoint mykeys[100]; 00220 //for(int i = 0; i < 100; ++i){ 00221 // mykeys[i].s = 1.0f;mykeys[i].o = 0.0f; 00222 // mykeys[i].x = (i%10)*10.0f+50.0f; 00223 // mykeys[i].y = (i/10)*10.0f+50.0f; 00224 //} 00225 //sift->SetKeypointList(100, mykeys, 0); 00226 //sift->RunSIFT("../data/800-1.jpg"); sift->SaveSIFT("../data/800-1.sift.2"); 00227 //### for comparing with method1: 00228 //sift->RunSIFT("../data/800-1.jpg"); 00229 //sift->RunSIFT(100, mykeys, 0); sift->SaveSIFT("../data/800-1.sift.3"); 00230 //********************************************************************************* 00231 00232 00233 //**********************GPU SIFT MATCHING********************************* 00234 //**************************select shader language************************* 00235 //SiftMatchGPU will use the same shader lanaguage as SiftGPU by default 00236 //Before initialization, you can choose between glsl, and CUDA(if compiled). 00237 //matcher->SetLanguage(SiftMatchGPU::SIFTMATCH_CUDA); // +i for the (i+1)-th device 00238 00239 //Verify current OpenGL Context and initialize the Matcher; 00240 //If you don't have an OpenGL Context, call matcher->CreateContextGL instead; 00241 matcher->VerifyContextGL(); //must call once 00242 00243 //Set descriptors to match, the first argument must be either 0 or 1 00244 //if you want to use more than 4096 or less than 4096 00245 //call matcher->SetMaxSift() to change the limit before calling setdescriptor 00246 matcher->SetDescriptors(0, num1, &descriptors1[0]); //image 1 00247 matcher->SetDescriptors(1, num2, &descriptors2[0]); //image 2 00248 00249 //match and get result. 00250 int (*match_buf)[2] = new int[num1][2]; 00251 //use the default thresholds. Check the declaration in SiftGPU.h 00252 int num_match = matcher->GetSiftMatch(num1, match_buf); 00253 std::cout << num_match << " sift matches were found;\n"; 00254 00255 //enumerate all the feature matches 00256 for(int i = 0; i < num_match; ++i) 00257 { 00258 //How to get the feature matches: 00259 //SiftGPU::SiftKeypoint & key1 = keys1[match_buf[i][0]]; 00260 //SiftGPU::SiftKeypoint & key2 = keys2[match_buf[i][1]]; 00261 //key1 in the first image matches with key2 in the second image 00262 } 00263 00264 //*****************GPU Guided SIFT MATCHING*************** 00265 //example: define a homography, and use default threshold 32 to search in a 64x64 window 00266 //float h[3][3] = {{0.8f, 0, 0}, {0, 0.8f, 0}, {0, 0, 1.0f}}; 00267 //matcher->SetFeatureLocation(0, &keys1[0]); //SetFeatureLocaiton after SetDescriptors 00268 //matcher->SetFeatureLocation(1, &keys2[0]); 00269 //num_match = matcher->GetGuidedSiftMatch(num1, match_buf, h, NULL); 00270 //std::cout << num_match << " guided sift matches were found;\n"; 00271 //if you can want to use a Fundamental matrix, check the function definition 00272 00273 // clean up.. 00274 delete[] match_buf; 00275 #ifdef REMOTE_SIFTGPU 00276 delete combo; 00277 #else 00278 delete sift; 00279 delete matcher; 00280 #endif 00281 00282 #ifdef SIFTGPU_DLL_RUNTIME 00283 FREE_MYLIB(hsiftgpu); 00284 #endif 00285 return 1; 00286 } 00287