使用SiftGPU对两幅图像进行特征点匹配

2023-05-16

前言

继上一篇博客中谈到使用Changchang Wu的SiftGPU,使用GLSL语言在Windows系统下的编译方法http://blog.csdn.net/qq_36007951/article/details/78472349,测试代码中尚未涉及两幅图片的特征点匹配。

今天介绍继续使用GLSL语言,在SiftGPU中对两幅图像进行特征点匹配方法,经本人验证,在图片分辨率没有那么大的情况下,匹配速度会比Lowe算法的快。

个人编译环境:Windows 8.1,Visual Studio2010,OPENCV2.4.9

在你下载的SiftGPU文件夹中找到.....\SiftGPU\msvc\TestWin,在TestWin文件夹中可以看到一些测试的工程,

其中解决方案SimpleSIFT才是我们需要的,将其中的部分代码提取出来即可。

以下是我个人稍微修改了的代码,仅供大家参考。

// siftGPU-match.cpp : 定义控制台应用程序的入口点。
//

#include "StdAfx.h"

//标准C++
#include <iostream>
#include <vector>


// OpenCV图像
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/nonfree.hpp"

// OpenGL
#include <Windows.h>
#include <GL/gl.h>

// SiftGPU模块
#include "SiftGPU.h"



// boost库中计时函数
#include <boost/timer.hpp>



#pragma comment(lib,"devil.lib")
//#pragma comment(lib,"ilu.lib")
//#pragma comment(lib,"ilut.lib")

using namespace cv;
using namespace std;



int main()
{
	   SiftGPU  *sift = new SiftGPU;
    SiftMatchGPU *matcher = new SiftMatchGPU(4096);
	   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;

	boost::timer timer1;
    if(sift->RunSIFT("640-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.            
    }
		cout<<"siftgpu::runsift(1) cost time="<<timer1.elapsed()<<endl;
    //You can have at most one OpenGL-based SiftGPU (per process).
    //Normally, you should just create one, and reuse on all images. 
		timer1.restart();
    if(sift->RunSIFT("800-1.jpg"))
    {
        num2 = sift->GetFeatureNum();
        keys2.resize(num2);    descriptors2.resize(128*num2);
        sift->GetFeatureVector(&keys2[0], &descriptors2[0]);
    }
		cout<<"siftgpu::runsift(2) cost time="<<timer1.elapsed()<<endl;
    //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
	boost::timer timer;
    matcher->SetDescriptors(0, num1, &descriptors1[0]); //image 1
	cout<<"siftgpu::match1 cost time="<<timer.elapsed()<<endl;

	timer.restart();
    matcher->SetDescriptors(1, num2, &descriptors2[0]); //image 2
	cout<<"siftgpu::match2 cost time="<<timer.elapsed()<<endl;

    //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";
    
	//Mat img1=imread("640-1.jpg");
	//Mat img2=imread("800-1.jpg");
	//	drawMatches(img1, keys1(1),         //第一幅图像和它的特征点  
	//	img2, key_points2,      //第二幅图像和它的特征点  
	//	matches,       //匹配器算子  
	//	img_matches,      //匹配输出图像  
	//	Scalar(255, 0, 255));     //用红色色直线连接两幅图像中的特征点  

    //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;
	return 0;
}

最终运行结果:

可以看到,在计算sift,和match上花费的时间很少。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用SiftGPU对两幅图像进行特征点匹配 的相关文章

  • ES6分页from+size、search_after两种查询

    1 from 43 size 分页查询 64 RequestMapping value 61 34 get 34 method 61 RequestMethod GET public BaseResponse lt List lt Obje
  • 使用activiti总结--bpmn画流程图

    假期结束 xff0c 赶紧总结一下前几天使用的Activiti工作流的一些方法 简单介绍一下Activiti Activiti一套完整的方便的业务流程管理 xff08 BPM xff09 框架 xff0c 它是覆盖了业务流程管理 工作流 服
  • clock函数 使用以及问题

    使用 clock 函数是一个计算程序运行时间 xff08 其实简略的理解为占用CPU的使用时间 xff09 其实如果使用sleep函数 xff0c 程序是放弃CPU的使用权 xff0c 直到某个时间的到来 xff0c 当然就不会存在占用CP
  • 使用activiti总结--发布,办理,查询

    接上一篇文章 xff0c 使用创建好的流程图 xff0c 总结一下activiti发布到查询使用的方法和测试代码 流程图 1 引用配置文件 activiti cfg xml xff0c 不引用或者引用失败的话在创建流引擎的时候会报空指针异常
  • Could not open JDBC Connection for transaction

    操做 xff1a 访问20次数据库没问题 xff0c 超过20次调用后报如下错误 详细报错 xff1a org springframework transaction CannotCreateTransactionException Cou
  • 【可信计算】第八次课:可信软件栈编程开发

    TPM2开源软件包 目前在github上TPM2开源软件一共包含六个项目tpm2 tools tpm2 tss tpm2 pkcs11 tpm2 tss engine tpm2 abrmd tpm2 totp 1 tpm2 tools 这一
  • 国赛----可见光室内定位

    初期试探 拿到题目后 xff0c 反复读了题目 首先队内结合网上资料形成了两种方案 xff0c 原理相同就是利用光信号到达的强度来定位 两者差距在于算法不同而已 xff0c 一种利用计算得出位置 xff0c 另一种就是经过测量得到一种位置与
  • 各种Arduino外部中断程序

    一 中断 Interrupt 的基本概念 中断 xff08 Interrupt xff09 是计算机的一个重要概念 xff0c 现代计算机普遍采用中断技术 什么是中断呢 xff1f CPU执行时原本是按程序指令一条一条向下顺序执行的 但如果
  • PX4通过参数脚本给飞控导入参数

    PX4通过参数脚本给飞控导入参数 先找一架正常能飞的无人机连接地面站 在参数页面右上角点击工具 gt 保存到文件 保存的时候文件名注明参数的相关信息 然后将需要加载参数的无人机连接至地面站 xff0c 注意需要加载参数的无人机必须和保存的参
  • 深蓝 运动规划

    文章目录 CH1 Introduction一 Motion Planning 概念二 Front end xff1a Path finding1 Search based methods2 Sampling based methods3 K
  • 接收机/DTU 安装调试 读取gps数据

    文章目录 一 整体连接图二 DTU配置三 接收机设置 在这里记录一下 xff0c 实验室平台上 xff0c 安装gps接收机和配置的一些步骤 一 整体连接图 二 DTU配置 首先 DTU 需要通过 COM 口和电脑端连接 xff0c 注意这
  • OOQP 安装和使用

    OOQP 安装和使用 1 安装2 使用 1 安装 需要先安装 blas 和 ma27 BLAS xff1a span class token builtin class name cd span my lib span class toke
  • 系统指标

    目录 1 cpu xxx 1 1 cpu空闲率cpu idle cpu idle表示除硬盘IO等待时间以外其它等待时间 xff0c 这个值越大 xff0c 表示cpu越空闲 xff0c 还可以执行更多的任务 xff0c 反之亦然 xff0c
  • stm32 MPU6050 6轴姿态传感器的介绍与DMP的应用

    最近应用到三轴姿态传感器 xff0c 因为之前有MPU6050 xff08 6轴传感器 xff0c 这是6轴的 xff09 xff0c 进行搭配使用 xff0c 通过三轴姿态传感器进行舵机的角度调整 内容来源学习正点原子的教程 xff09
  • 室内外融合北斗+uwb终端数据监听和发送控制方法

    UDP接收GNGGA报文同时转发UDP报文的方法 span class token keyword package span span class token class name Frame span span class token p
  • Ubuntu使用终端命令安装谷歌Chrome浏览器

    使用命令行安装谷歌浏览器稳定版 span class token function sudo span span class token function wget span http www linuxidc com files repo
  • 无人机PX4使用动捕系统mocap的位置实现控制+MAVROS

    动捕系统Optitrack xff0c 有很高的定位精度 xff0c 能够给无人机提供比较精确的位置信息 xff0c 因此如果实验室有条件 xff0c 都可以买一套动捕系统 动捕系统的原理 xff1a 光学式动作捕捉依靠一整套精密而复杂的光
  • Optitrack使用ros完成实时接收刚体的位置与四元数信息

    1 Opitrack系统标定 工作环境 xff1a 运行Motive的Windows主机 和一台安装有ROS的ubuntu电脑 标定步骤 1 准备 优化捕获设置 xff1b 2 在相机预览窗口 xff08 Camera Preview xf
  • RoboMaster机甲大师比赛入门?我们从STM32开始!

    同步博客地址 xff1a 从STM32开始的RoboMaster生活 xff1a 入门篇 项目 amp 教程仓库 xff1a STM32 RoboMaster 1 0 STM32是什么 1 1 定义 ST 43 M 43 32 61 STM
  • C++头文件定义类的方法

    新手在写C 43 43 程序定义类的时候 xff0c 可能会犯一个错误 xff0c 就是在main函数文件里定义很多类 xff0c 一个文件中包含很多函数 xff0c 这样程序看起来很冗杂 今天总结一下如何在C 43 43 中使用头文件来定

随机推荐

  • 相机光学(十五)——如何提高相机标定的精度

    为了提高单目相机标定的精度 xff0c 认真看了张正友标定法的原文 xff0c 并且学习过网上一些牛人的方法 xff0c 但是大部分时候说的很笼统 xff0c 自己把这些经验总结起来并都测试了一下 xff0c 感觉靠谱的结论列出如下 xff
  • TCP/UDP、封装与解封装

    目录 传输类型 网络里面三层架构 TCP IP模型 OSI模型 TCP IP模型 掌握 TCP IP模型当中重点 数据传递过程中的封装和解封装 封装 解封装 TCP UDP ICMP ICMP错误报告 ICMP重定向 典型应用 PING应用
  • 解决 ERROR: cannot launch node of type [xxx]: can‘t locate node [xxx] in package [xxx]

    背景 xff1a 从github下载的ros代码 xff0c 修改添加节点后 xff0c catkin make 编译通过 xff0c 但在运行launch文件时候报错 原因 xff1a 1 从github上下载的很多文件 xff0c 下载
  • stm32控制步进电机

    本文使用DM542c驱动器驱动 使用前注意根据实际情况调节拨码开关 本文不会提到GPIO使能 xff0c 请自行使能 一 PWM操作驱动器使步进电机一直转 使能定时器时钟 xff0c 并配置基本参数 下图以TIM3为例 配置输出比较PWM1
  • 树莓派GPIO

    命令行执行下行 xff0c 即可得树莓派管脚编码表 gpio readall 也可看下图 xff1a BOARD 编号参考 Raspberry Pi 主板上 P1 接线柱的针脚编号 使用该方式的优点是无需考虑主板的修订版本 xff0c 无需
  • python opencv滤波

    1 均值滤波 算法简单 xff0c 计算速度快 xff0c 在去噪的同时去除了很多细节部分 xff0c 将图像变得模糊 cv2 blur 2 高斯滤波 去除高斯噪声 cv2 GaussianBlur 3 中值滤波 去除椒盐噪声 cv2 me
  • opencv imwrite()保存指定路径

    cpp为例 include lt opencv2 opencv hpp gt include lt string gt include lt iostream gt using namespace cv using namespace st
  • python pip安装的包的路径

    以ubuntu为例 从一个店家那里拿到的一个ubuntu环境中 xff0c 同时安装了python3 6和python2 7 xff0c 又安装了ros xff0c 最后pip安装包的位置很混乱 xff0c 安装的包不知道安装在了哪里 使用
  • solidworks实体显示线框

    sw有段时间没使用 xff0c 今天打开突然发现打开的sw窗口数超过1 xff0c 那么从第二个窗口以后的模型都显示成以下样子 xff08 无论是之前的文件还是新建的都不行 xff09 如上是一个圆盘 xff0c 明明是实体 xff0c 却
  • vscode使用虚拟环境

    我的conda没有添加入path xff0c 每次打开总是报错 一 选择对应虚拟环境的解释器 1 点击vscode的右下角这里 2 点击后可能会在vscode上方出现下图样子 xff0c 如果出现下图 xff0c 则点击第二项Select
  • TabError: inconsistent use of tabs and spaces in indentation

    错误原因是tab制表符和空格混用了 从其他地方复制源码容易出现此错误 解决办法 xff1a 把处于同级缩进的所有缩进修改统一 比较流行的几个编辑器都能标识tab和空格 xff0c 比如我用的vscode 用鼠标框选 不知道是tab还是空格的
  • 关于深度学习的问题笔记

    感谢沐神教我深度学习 x1f64f 损失为什么要平均 xff1f 平均即除以batch size xff0c 若不除 xff0c 则批越大梯度越大 xff0c 梯度下降的步长就越大 除以batch size可使梯度与批大小无关 也可以不在损
  • 简单(炫酷)的单链表快速排序写法

    昨天在复习快排的时候 在B站看到一个小哥哥说某大厂的面试让写一个单链表的快速排序 我们见的最多的快排写法都是从两端向中间扫描 这种写法在单链表上不能实现 哥们分析道 快排的核心思想是每次扫描后 所有pivot左侧的元素都比pivot小 右侧
  • char* char[]

    C 43 43 判断char 的指向 char a 61 34 Peter 34 char b 61 34 Peter 34 char c 61 new char 6 strcpy s c 6 34 Peter 34 这里a指向常量区 b指
  • HTTP 基本认证 HttpBasic

    HTTP 的认证机制 基本认证 摘要认证 一 基本认证 用BASE64 算法加密后的字符串放在HTTP Request中的Header Authorization中发送给服务端 xff0c 这种方式叫HTTP基本认证 Basic Authe
  • libcurl异步调用

    span class token keyword int span span class token function main span span class token punctuation span span class token
  • 标准c++库、stl库,boost库,qt库

    C 43 43 标准库 C C xff0b xff0b 标准库主要包含3部分 xff1a STL IO流及本地化 C的函数库 标准库不是STL STL是标准模板库 是标准库的一个子集 它是一个可复用的组件库 xff0c 其中包含了很多实用的
  • 生成2023年节假日/工作日维表

    项目中有一张维表 xff0c 维护的是历史节假日工作日的信息 xff0c 估计在很多场合都有类似的需求 到了新年 xff0c 需要生成新一年的数据 xff0c 下面看看如何在维表中插入新一年的数据 1 查询节假日 根据国务院发布的休假信息
  • C++智能指针

    参考 xff1a 头文件auto ptr使用示例 unique ptr类模板声明示例 shared ptr模板声明通过辅助类模拟实现 shared ptrshared ptr使用示例 weaked ptrweak ptr 用法weak pt
  • 使用SiftGPU对两幅图像进行特征点匹配

    前言 继上一篇博客中谈到使用Changchang Wu的SiftGPU xff0c 使用GLSL语言在Windows系统下的编译方法http blog csdn net qq 36007951 article details 7847234