int main() { #ifdef SIFTGPU_DLL_RUNTIME #ifdef _WIN32 #ifdef _DEBUG HMODULE hsiftgpu = LoadLibrary("siftgpu_d.dll"); #else HMODULE hsiftgpu = LoadLibrary("siftgpu.dll"); #endif #else void * hsiftgpu = dlopen("libsiftgpu.so", RTLD_LAZY); #endif if(hsiftgpu == NULL) return 0; #ifdef REMOTE_SIFTGPU ComboSiftGPU* (*pCreateRemoteSiftGPU) (int, char*) = NULL; pCreateRemoteSiftGPU = (ComboSiftGPU* (*) (int, char*)) GET_MYPROC(hsiftgpu, "CreateRemoteSiftGPU"); ComboSiftGPU * combo = pCreateRemoteSiftGPU(REMOTE_SERVER_PORT, REMOTE_SERVER); SiftGPU* sift = combo; SiftMatchGPU* matcher = combo; #else SiftGPU* (*pCreateNewSiftGPU)(int) = NULL; SiftMatchGPU* (*pCreateNewSiftMatchGPU)(int) = NULL; pCreateNewSiftGPU = (SiftGPU* (*) (int)) GET_MYPROC(hsiftgpu, "CreateNewSiftGPU"); pCreateNewSiftMatchGPU = (SiftMatchGPU* (*)(int)) GET_MYPROC(hsiftgpu, "CreateNewSiftMatchGPU"); SiftGPU* sift = pCreateNewSiftGPU(1); SiftMatchGPU* matcher = pCreateNewSiftMatchGPU(4096); #endif #elif defined(REMOTE_SIFTGPU) ComboSiftGPU * combo = CreateRemoteSiftGPU(REMOTE_SERVER_PORT, REMOTE_SERVER); SiftGPU* sift = combo; SiftMatchGPU* matcher = combo; #else //this will use overloaded new operators SiftGPU *sift = new SiftGPU; SiftMatchGPU *matcher = new SiftMatchGPU(4096); #endif vector<float > descriptors1(1), descriptors2(1); vector<SiftGPU::SiftKeypoint> keys1(1), keys2(1); int num1 = 0, num2 = 0; //process parameters //The following parameters are default in V340 //-m, up to 2 orientations for each feature (change to single orientation by using -m 1) //-s enable subpixel subscale (disable by using -s 0) char * argv[] = {"-fo", "-1", "-v", "1"};// //-fo -1 staring from -1 octave //-v 1 only print out # feature and overall time //-loweo add a (.5, .5) offset //-tc <num> set a soft limit to number of detected features //NEW: parameters for GPU-selection //1. CUDA. Use parameter "-cuda", "[device_id]" //2. OpenGL. Use "-Display", "display_name" to select monitor/GPU (XLIB/GLUT) // on windows the display name would be something like \\.\DISPLAY4 ////////////////////////////////////////////////////////////////////////////////////// //You use CUDA for nVidia graphic cards by specifying //-cuda : cuda implementation (fastest for smaller images) // CUDA-implementation allows you to create multiple instances for multiple threads // Checkout src\TestWin\MultiThreadSIFT ///////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////Two Important Parameters/////////////////////////// // First, texture reallocation happens when image size increases, and too many // reallocation may lead to allocatoin failure. You should be careful when using // siftgpu on a set of images with VARYING imag sizes. It is recommended that you // preset the allocation size to the largest width and largest height by using function // AllocationPyramid or prameter '-p' (e.g. "-p", "1024x768"). // Second, there is a parameter you may not be aware of: the allowed maximum working // dimension. All the SIFT octaves that needs a larger texture size will be skipped. // The default prameter is 2560 for the unpacked implementation and 3200 for the packed. // Those two default parameter is tuned to for 768MB of graphic memory. You should adjust // it for your own GPU memory. You can also use this to keep/skip the small featuers. // To change this, call function SetMaxDimension or use parameter "-maxd". // // NEW: by default SiftGPU will try to fit the cap of GPU memory, and reduce the working // dimension so as to not allocate too much. This feature can be disabled by -nomc ////////////////////////////////////////////////////////////////////////////////////// int argc = sizeof(argv)/sizeof(char*); sift->ParseParam(argc, argv); /////////////////////////////////////////////////////////////////////// //Only the following parameters can be changed after initialization (by calling ParseParam). //-dw, -ofix, -ofix-not, -fo, -unn, -maxd, -b //to change other parameters at runtime, you need to first unload the dynamically loaded libaray //reload the libarary, then create a new siftgpu instance //Create a context for computation, and SiftGPU will be initialized automatically //The same context can be used by SiftMatchGPU if(sift->CreateContextGL() != SiftGPU::SIFTGPU_FULL_SUPPORTED) return 0; if(sift->RunSIFT("../data/800-1.jpg")) { //Call SaveSIFT to save result to file, the format is the same as Lowe's //sift->SaveSIFT("../data/800-1.sift"); //Note that saving ASCII format is slow //get feature count num1 = sift->GetFeatureNum(); //allocate memory keys1.resize(num1); descriptors1.resize(128*num1); //reading back feature vectors is faster than writing files //if you dont need keys or descriptors, just put NULLs here sift->GetFeatureVector(&keys1[0], &descriptors1[0]); //this can be used to write your own sift file. } //You can have at most one OpenGL-based SiftGPU (per process). //Normally, you should just create one, and reuse on all images. if(sift->RunSIFT("../data/640-1.jpg")) { num2 = sift->GetFeatureNum(); keys2.resize(num2); descriptors2.resize(128*num2); sift->GetFeatureVector(&keys2[0], &descriptors2[0]); } //Testing code to check how it works when image size varies //sift->RunSIFT("../data/256.jpg");sift->SaveSIFT("../data/256.sift.1"); //sift->RunSIFT("../data/1024.jpg"); //this will result in pyramid reallocation //sift->RunSIFT("../data/256.jpg"); sift->SaveSIFT("../data/256.sift.2"); //two sets of features for 256.jpg may have different order due to implementation //************************************************************************* /////compute descriptors for user-specified keypoints (with or without orientations) //Method1, set new keypoints for the image you've just processed with siftgpu //say vector<SiftGPU::SiftKeypoint> mykeys; //sift->RunSIFT(mykeys.size(), &mykeys[0]); //sift->RunSIFT(num2, &keys2[0], 1); sift->SaveSIFT("../data/640-1.sift.2"); //sift->RunSIFT(num2, &keys2[0], 0); sift->SaveSIFT("../data/640-1.sift.3"); //Method2, set keypoints for the next coming image //The difference of with method 1 is that method 1 skips gaussian filtering //SiftGPU::SiftKeypoint mykeys[100]; //for(int i = 0; i < 100; ++i){ // mykeys[i].s = 1.0f;mykeys[i].o = 0.0f; // mykeys[i].x = (i%10)*10.0f+50.0f; // mykeys[i].y = (i/10)*10.0f+50.0f; //} //sift->SetKeypointList(100, mykeys, 0); //sift->RunSIFT("../data/800-1.jpg"); sift->SaveSIFT("../data/800-1.sift.2"); //### for comparing with method1: //sift->RunSIFT("../data/800-1.jpg"); //sift->RunSIFT(100, mykeys, 0); sift->SaveSIFT("../data/800-1.sift.3"); //********************************************************************************* //**********************GPU SIFT MATCHING********************************* //**************************select shader language************************* //SiftMatchGPU will use the same shader lanaguage as SiftGPU by default //Before initialization, you can choose between glsl, and CUDA(if compiled). //matcher->SetLanguage(SiftMatchGPU::SIFTMATCH_CUDA); // +i for the (i+1)-th device //Verify current OpenGL Context and initialize the Matcher; //If you don't have an OpenGL Context, call matcher->CreateContextGL instead; matcher->VerifyContextGL(); //must call once //Set descriptors to match, the first argument must be either 0 or 1 //if you want to use more than 4096 or less than 4096 //call matcher->SetMaxSift() to change the limit before calling setdescriptor matcher->SetDescriptors(0, num1, &descriptors1[0]); //image 1 matcher->SetDescriptors(1, num2, &descriptors2[0]); //image 2 //match and get result. int (*match_buf)[2] = new int[num1][2]; //use the default thresholds. Check the declaration in SiftGPU.h int num_match = matcher->GetSiftMatch(num1, match_buf); std::cout << num_match << " sift matches were found;\n"; //enumerate all the feature matches for(int i = 0; i < num_match; ++i) { //How to get the feature matches: //SiftGPU::SiftKeypoint & key1 = keys1[match_buf[i][0]]; //SiftGPU::SiftKeypoint & key2 = keys2[match_buf[i][1]]; //key1 in the first image matches with key2 in the second image } //*****************GPU Guided SIFT MATCHING*************** //example: define a homography, and use default threshold 32 to search in a 64x64 window //float h[3][3] = {{0.8f, 0, 0}, {0, 0.8f, 0}, {0, 0, 1.0f}}; //matcher->SetFeatureLocation(0, &keys1[0]); //SetFeatureLocaiton after SetDescriptors //matcher->SetFeatureLocation(1, &keys2[0]); //num_match = matcher->GetGuidedSiftMatch(num1, match_buf, h, NULL); //std::cout << num_match << " guided sift matches were found;\n"; //if you can want to use a Fundamental matrix, check the function definition // clean up.. delete[] match_buf; #ifdef REMOTE_SIFTGPU delete combo; #else delete sift; delete matcher; #endif #ifdef SIFTGPU_DLL_RUNTIME FREE_MYLIB(hsiftgpu); #endif return 1; }
/// /// \brief PairwiseMatching:do a pairwise matching between two image(sift) files, and save the match info in the .mat file. /// This includes a putative match function provided by SiftGPU and a guided match (using fundamental /// matrix and homography) /// \param match_filename: the name of the output match file. This is mainly used by transction-style saving /// \param first_sift: the sift data of the first sift file /// \param second_sift: the sift data of the second sift file /// \return /// bool PairwiseMatching(const std::string &match_filename, const std::string &first_sift_filename, const std::string &second_sift_filename, tw::SiftData &first_sift, tw::SiftData &second_sift, SiftMatchGPU &matcher, MatchParam const & match_param, FILE * match_fd, zeta::TransactionLog<FILE *> & tlog) { // write to the .mat file points correspondence and inlier information if(tlog.isReady()) { { std::string transaction_name = "match_info" + first_sift_filename + "&" + second_sift_filename; zeta::Transaction<FILE *> transaction_filename(tlog, transaction_name); if(!transaction_filename.exist()) { const int max_sift = 32768; int match_buf[max_sift][2]; // set feature location and descriptors, this is needed by SiftGPU matcher.SetDescriptors(0, first_sift.getFeatureNum(), first_sift.getDesPointer()); //matcher.SetFeatureLocation(0, first_sift.getLocPointer(), 3); matcher.SetDescriptors(1, second_sift.getFeatureNum(), second_sift.getDesPointer()); //matcher.SetFeatureLocation(1, second_sift.getLocPointer(), 3); // get putative match and store the match result in match_buf int nmatch = matcher.GetSiftMatch(max_sift, match_buf); zeta::notify(zeta::Notify::Debug) << nmatch << " matches"; if(nmatch < match_param.min_num_inlier) return true; // ransac fundamental matrix tw::FundamentalMatrixModel fundamental_model(match_buf, nmatch, first_sift.getFeatureNum(), second_sift.getFeatureNum(), first_sift.getLocPointer(), second_sift.getLocPointer(), first_sift.getLocDim(), match_param.f_error0, match_param.f_error1); zeta::RANSACNaiveSampler fundamental_sampler(match_param.f_ransac_conf, match_param.f_ransac_ratio, 8, nmatch, 0); typedef zeta::RANSAC<tw::FundamentalMatrixModel, zeta::RANSACNaiveSampler> RANSACFundamental; RANSACFundamental ransac_fundamental; RANSACFundamental::Param fundamental_param(match_param.thread_num); std::vector<bool> fundamental_inlier_flags; int fundamental_inlier_num = ransac_fundamental(fundamental_sampler, fundamental_model, fundamental_inlier_flags, fundamental_param); double f_inlier_ratio = (double)fundamental_inlier_num / (double)nmatch; zeta::notify(zeta::Notify::Debug) << ", F[" << fundamental_inlier_num << "/" << nmatch << "]"; // ransac homography tw::HomographyModel homography_model(match_buf, nmatch, first_sift.getFeatureNum(), second_sift.getFeatureNum(), first_sift.getLocPointer(), second_sift.getLocPointer(), first_sift.getLocDim(), match_param.h_error1); zeta::RANSACNaiveSampler homography_sampler(match_param.h_ransac_conf, match_param.h_ransac_ratio, 4, nmatch, 0); typedef zeta::RANSAC<tw::HomographyModel, zeta::RANSACNaiveSampler> RANSACHomography; RANSACHomography homography_ransac; RANSACHomography::Param homography_param(match_param.thread_num); std::vector<bool> homography_inlier_flags; int homography_inlier_num = homography_ransac(homography_sampler, homography_model, homography_inlier_flags, homography_param); double h_inlier_ratio = (double)homography_inlier_num / (double)nmatch; zeta::notify(zeta::Notify::Debug) << ", H[" << homography_inlier_num << "/" << nmatch << "]"; if((f_inlier_ratio < match_param.min_f_inlier_ratio || fundamental_inlier_num < match_param.min_f_inlier) && (h_inlier_ratio < match_param.min_h_inlier_ratio || homography_inlier_num < match_param.min_h_inlier)) return true; tw::SiftMatchPair sift_match(match_buf, nmatch, homography_inlier_flags, fundamental_inlier_flags, first_sift_filename, second_sift_filename, homography_model.getHomography(), fundamental_model.getFundmantalMatrix(), homography_inlier_num, fundamental_inlier_num); sift_match.WriteSiftMatchPair(match_fd); } else { zeta::notify(zeta::Notify::Debug) << "existed and skip"; return false; } } } else { zeta::notify(zeta::Notify::Error) << "Transaction log is not ready\n"; } return true; }
inline void ServerSiftGPU::ServerLoop(int port, int argc, char** argv) { SOCKET sockfd, newsockfd; struct sockaddr_in serv_addr, cli_addr; socklen_t addr_len = sizeof(sockaddr_in); ////////////////////////////////////////////////// memset((char*)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = INADDR_ANY; ///////////////////////////////////////////// if(ServerSiftGPU::InitSocket() == 0) { return; } ////////////////////////////////////////////////////////////// sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==INVALID_SOCKET) { std::cout << "server: can't open stream socket\n"; return; }else if(bind(sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr))) { std::cout << "server: can't bind to port " << port <<"\n"; return; }else if(listen(sockfd, 1)) { std::cout << "server: failed to listen\n"; return; }else { std::cout << "server: listent to port "<< port << "\n"; } newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &addr_len); if(newsockfd == INVALID_SOCKET) { std::cout << "error: accept failed\n"; closesocket(sockfd); return; } //////////////////////////////////////////////////////////////// char buf[1024]; int command, result; int sift_feature_count = 0;; vector<SiftGPU::SiftKeypoint> keys; vector<float> descriptors; vector<char> databuf; ///////////////////////////////////////////////////////////////// SiftGPU siftgpu; SiftMatchGPU matcher; if(argc > 0) siftgpu.ParseParam(argc, argv); ///////////////////// siftgpu.SetVerbose(0); ///////////////////////////////////////////////////////////////// do { while(SocketUtil::readint(newsockfd, &command) && command != COMMAND_DISCONNECT) { switch(command) { case COMMAND_INITIALIZE: { result = (siftgpu.CreateContextGL() == SiftGPU::SIFTGPU_FULL_SUPPORTED); SocketUtil::writeint(newsockfd, result); if(result) break; } case COMMAND_EXIT: closesocket(newsockfd); closesocket(sockfd); return; case COMMAND_ALLOCATE_PYRAMID: { int size[2]; SocketUtil::readint(newsockfd, size, 2); if(size[0] > 0 && size[1] > 0) siftgpu.AllocatePyramid(size[0], size[1]); break; } case COMMAND_GET_KEY_VECTOR: { int size = sift_feature_count * sizeof(SiftGPU::SiftKeypoint); SocketUtil::writedata(newsockfd, &keys[0], size); break; } case COMMAND_GET_DES_VECTOR: { int size = sift_feature_count * sizeof(float) * 128; SocketUtil::writedata(newsockfd, &descriptors[0], size); break; } case COMMAND_RUNSIFT: { result = siftgpu.RunSIFT(); if((sift_feature_count = siftgpu.GetFeatureNum()) > 0) { keys.resize(sift_feature_count); descriptors.resize(sift_feature_count * 128); siftgpu.GetFeatureVector(&keys[0], &descriptors[0]); std::cout << "RunSIFT: [-] [" << sift_feature_count << "]\n"; } SocketUtil::writeint(newsockfd, result); break; } case COMMAND_RUNSIFT_FILE: { SocketUtil::readline(newsockfd, buf, 1024); result = siftgpu.RunSIFT(buf); if((sift_feature_count = siftgpu.GetFeatureNum()) > 0) { keys.resize(sift_feature_count); descriptors.resize(sift_feature_count * 128); siftgpu.GetFeatureVector(&keys[0], &descriptors[0]); } std::cout << "RunSIFT: "<< buf <<" " << sift_feature_count << "\n" ; SocketUtil::writeint(newsockfd, result); break; } case COMMAND_SET_KEYPOINT: { int keys_have_orientation; SocketUtil::readint(newsockfd, &sift_feature_count); SocketUtil::readint(newsockfd, &keys_have_orientation); if(sift_feature_count > 0) { keys.resize(sift_feature_count); descriptors.resize(sift_feature_count * 128); SocketUtil::readdata(newsockfd, &keys[0], int(keys.size() * sizeof(SiftGPU::SiftKeypoint))); siftgpu.SetKeypointList(sift_feature_count, &keys[0], keys_have_orientation); } break; } case COMMAND_RUNSIFT_KEY: { int keys_have_orientation; SocketUtil::readint(newsockfd, &sift_feature_count); SocketUtil::readint(newsockfd, &keys_have_orientation); if(sift_feature_count > 0) { std::cout << "RunSIFT: "<< sift_feature_count << " KEYPOINTS\n" ; int key_data_size = sift_feature_count * sizeof(SiftGPU::SiftKeypoint); keys.resize(sift_feature_count); descriptors.resize(sift_feature_count * 128); SocketUtil::readdata(newsockfd, &keys[0], key_data_size); result = siftgpu.RunSIFT(sift_feature_count, &keys[0], keys_have_orientation); siftgpu.GetFeatureVector(NULL, &descriptors[0]); }else { result = 0; } SocketUtil::writeint(newsockfd, result); break; } case COMMAND_RUNSIFT_DATA: { int data_des[4], size = 0; SocketUtil::readint(newsockfd, data_des, 4); SocketUtil::readint(newsockfd, &size, 1); std::cout << "RunSIFT: [" << data_des[0] << "x" << data_des[1] << "]"; databuf.resize(size); void* data_ptr = &databuf[0]; SocketUtil::readdata(newsockfd, data_ptr, size); result = siftgpu.RunSIFT(data_des[0], data_des[1], data_ptr, data_des[2], data_des[3]); if((sift_feature_count = siftgpu.GetFeatureNum()) > 0) { keys.resize(sift_feature_count); descriptors.resize(sift_feature_count * 128); siftgpu.GetFeatureVector(&keys[0], &descriptors[0]); } std::cout << "[" << sift_feature_count << "]\n"; SocketUtil::writeint(newsockfd, result); break; } case COMMAND_SAVE_SIFT: { SocketUtil::readline(newsockfd, buf, 1024); siftgpu.SaveSIFT(buf); break; } case COMMAND_SET_MAX_DIMENSION: { int maxd; if(SocketUtil::readint(newsockfd, &maxd) && maxd > 0) siftgpu.SetMaxDimension(maxd); break; } case COMMAND_SET_TIGHTPYRAMID: { int tight; if(SocketUtil::readint(newsockfd, &tight)) siftgpu.SetTightPyramid(tight); break; } case COMMAND_GET_FEATURE_COUNT: { SocketUtil::writeint(newsockfd, sift_feature_count); break; } case COMMAND_PARSE_PARAM: { SocketUtil::readline(newsockfd, buf, 1024); std::cout << "ParseParam [" << buf << "]\n"; vector<char*> params; char* p = buf; while(*p) { while(*p == ' ' || *p == '\t')*p++ = 0; params.push_back(p); while(*p && *p != ' ' && *p != '\t') p++; } siftgpu.ParseParam(params.size(), ¶ms[0]); break; } case COMMAND_MATCH_INITIALIZE: { result = matcher.CreateContextGL(); SocketUtil::writeint(newsockfd, result); break; } case COMMAND_MATCH_SET_LANGUAGE: { int language; if(SocketUtil::readint(newsockfd, &language)) matcher.SetLanguage(language); break; } case COMMAND_MATCH_SET_DES_FLOAT: { int command[3] = {0, 0, 0}; if(SocketUtil::readdata(newsockfd, command, sizeof(command))) { databuf.resize(sizeof(float) * 128 * command[1]); if(SocketUtil::readdata(newsockfd, &databuf[0], databuf.size())) { matcher.SetDescriptors(command[0], command[1], (float*) (&databuf[0]), command[2]); } } break; } case COMMAND_MATCH_SET_DES_BYTE: { int command[3] = {0, 0, 0}; if(SocketUtil::readdata(newsockfd, command, sizeof(command))) { databuf.resize(sizeof(unsigned char) * 128 * command[1]); if(SocketUtil::readdata(newsockfd, &databuf[0], databuf.size())) { matcher.SetDescriptors(command[0], command[1], (unsigned char*) (&databuf[0]), command[2]); } } break; } case COMMAND_MATCH_GET_MATCH: { int command[2]; float fcommand[2]; result = 0; if( SocketUtil::readdata(newsockfd, command, sizeof(command)) && SocketUtil::readdata(newsockfd, fcommand, sizeof(fcommand))) { int max_match = command[0], mbm = command[1]; float distmax = fcommand[0], ratiomax = fcommand[1]; databuf.resize(max_match * 2 * sizeof(int)); result = matcher.GetSiftMatch(max_match, ( int(*)[2]) (&databuf[0]), distmax, ratiomax, mbm); } SocketUtil::writeint(newsockfd, result); if(result > 0) SocketUtil::writedata(newsockfd, &databuf[0], sizeof(int) * 2 * result); std::cout << "SiftMatch: " << result << "\n"; break; } case COMMAND_MATCH_SET_MAXSIFT: { int max_sift; if(SocketUtil::readint(newsockfd, &max_sift)) matcher.SetMaxSift(max_sift); break; } break; default: std::cout << "unrecognized command: " << command << "\n"; break; } } //client disconneted closesocket(newsockfd); //wait for the next client. std::cout << "wait for new client..."; newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &addr_len); if(newsockfd == INVALID_SOCKET) { std::cout << "error: accept failed"; closesocket(sockfd); return; }else { std::cout << "connected\n\n"; } }while(1); }