SIFT的两个版本:OpenCV和VL_SIFT

2023-11-20

暂时记录一下

OpenCV版本:

#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/core.hpp>
#include<opencv2/features2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

int main(int argc, char* argv[]) {

    Mat img_object = imread("a.jpg", IMREAD_GRAYSCALE);
    Mat img_scene = imread("b.jpg", IMREAD_GRAYSCALE);

    Ptr<SIFT> detector = SIFT::create(argc > 1 ? atoi(argv[1]) : 400);

    if (img_object.empty() || img_scene.empty()) {
        cout << "Could not open or find the image!\n" << endl;
        return -1;
    }

    std::vector<KeyPoint> keypoints_object, keypoints_scene;
    Mat descriptors_object, descriptors_scene;
    detector->detectAndCompute(img_object, noArray(), keypoints_object, descriptors_object);
    detector->detectAndCompute(img_scene, noArray(), keypoints_scene, descriptors_scene);

    //-- Step 2: Matching descriptor vectors with a FLANN based matcher
    // Since SURF is a floating-point descriptor NORM_L2 is used
    Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
    std::vector< std::vector<DMatch> > knn_matches;
    matcher->knnMatch(descriptors_object, descriptors_scene, knn_matches, 2);

    //-- Filter matches using the Lowe's ratio test
    const float ratio_thresh = 0.85f;
    std::vector<DMatch> good_matches;
    for (size_t i = 0; i < knn_matches.size(); i++)
    {
        if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance)
        {
            good_matches.push_back(knn_matches[i][0]);
        }
    }
    img_object = imread("a.jpg");
    img_scene = imread("b.jpg");

    for (auto& k : keypoints_object) {
        circle(img_object, k.pt, k.size, CV_RGB(255, 0, 0));
    }
    for (auto& k : keypoints_scene) {
        circle(img_scene, k.pt, k.size, CV_RGB(0, 255, 0));
    }
    //-- Draw matches
    Mat img_matches;
    drawMatches(img_object, keypoints_object, img_scene, keypoints_scene, good_matches, img_matches, Scalar::all(-1),
        Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

    //-- Localize the object
    std::vector<Point2f> obj;
    std::vector<Point2f> scene;

    for (size_t i = 0; i < good_matches.size(); i++)
    {
        //-- Get the keypoints from the good matches
        obj.push_back(keypoints_object[good_matches[i].queryIdx].pt);
        scene.push_back(keypoints_scene[good_matches[i].trainIdx].pt);
    }
    /*
        Mat H = findHomography(obj, scene, RANSAC);

        //-- Get the corners from the image_1 ( the object to be "detected" )
        std::vector<Point2f> obj_corners(4);
        obj_corners[0] = Point2f(0, 0);
        obj_corners[1] = Point2f((float)img_object.cols, 0);
        obj_corners[2] = Point2f((float)img_object.cols, (float)img_object.rows);
        obj_corners[3] = Point2f(0, (float)img_object.rows);
        std::vector<Point2f> scene_corners(4);

        perspectiveTransform(obj_corners, scene_corners, H);

        //-- Draw lines between the corners (the mapped object in the scene - image_2 )
        line(img_matches, scene_corners[0] + Point2f((float)img_object.cols, 0),
            scene_corners[1] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4);
        line(img_matches, scene_corners[1] + Point2f((float)img_object.cols, 0),
            scene_corners[2] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4);
        line(img_matches, scene_corners[2] + Point2f((float)img_object.cols, 0),
            scene_corners[3] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4);
        line(img_matches, scene_corners[3] + Point2f((float)img_object.cols, 0),
            scene_corners[0] + Point2f((float)img_object.cols, 0), Scalar(0, 255, 0), 4);
        */
        //-- Show detected matches
    imshow("Good Matches & Object detection", img_matches);

    waitKey();
    return 0;
}

如果要用SURF,改这行代码即可:

//Ptr<SIFT> detector = SIFT::create(argc > 1 ? atoi(argv[1]) : 400);
Ptr<SURF> detector = SURF::create(argc > 1 ? atoi(argv[1]) : 400);

SURF是受专利保护的,所以编译OpenCV的时候需要把Contrib包一起编译,还要勾选OPENCV_ENABLE_NONFREE
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210314181942339.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,tex

_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTY2NTIyNQ==,size_16,color_FFFFFF,t_70#pic_center)

SURF比较慢,精度怎样不做比较。

VLFeat 的SIFT版本据说比OpenCV好。

官网:https://www.vlfeat.org/

代码下载来后,为Visual Studio 2019建立工程文件 libvlfeat_sift.vcxproj 和vl目录同一级。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations"> 
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{dfd18de8-c6e6-45dc-88a3-91545155cac8}</ProjectGuid>
    <RootNamespace>libvlfeatsift</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>MultiByte</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>MultiByte</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup> 
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <TargetName>$(ProjectName)d</TargetName>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>false</SDLCheck>
      <PreprocessorDefinitions>VL_BUILD_DLL;_LIB;_CRT_SECURE_NO_WARNINGS;VL_DISABLE_SSE2;VL_DISABLE_AVX;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>
      </SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>false</SDLCheck>
      <PreprocessorDefinitions>VL_BUILD_DLL;_LIB;_CRT_SECURE_NO_WARNINGS;VL_DISABLE_SSE2;VL_DISABLE_AVX;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>
      </SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClInclude Include="vl\aib.h" />
    <ClInclude Include="vl\array.h" />
    <ClInclude Include="vl\covdet.h" />
    <ClInclude Include="vl\dsift.h" />
    <ClInclude Include="vl\fisher.h" />
    <ClInclude Include="vl\framework.h" />
    <ClInclude Include="vl\generic.h" />
    <ClInclude Include="vl\getopt_long.h" />
    <ClInclude Include="vl\gmm.h" />
    <ClInclude Include="vl\heap-def.h" />
    <ClInclude Include="vl\hikmeans.h" />
    <ClInclude Include="vl\hog.h" />
    <ClInclude Include="vl\homkermap.h" />
    <ClInclude Include="vl\host.h" />
    <ClInclude Include="vl\ikmeans.h" />
    <ClInclude Include="vl\imopv.h" />
    <ClInclude Include="vl\imopv_sse2.h" />
    <ClInclude Include="vl\kdtree.h" />
    <ClInclude Include="vl\kmeans.h" />
    <ClInclude Include="vl\lbp.h" />
    <ClInclude Include="vl\liop.h" />
    <ClInclude Include="vl\mathop.h" />
    <ClInclude Include="vl\mathop_avx.h" />
    <ClInclude Include="vl\mathop_sse2.h" />
    <ClInclude Include="vl\mser.h" />
    <ClInclude Include="vl\pch.h" />
    <ClInclude Include="vl\pgm.h" />
    <ClInclude Include="vl\qsort-def.h" />
    <ClInclude Include="vl\quickshift.h" />
    <ClInclude Include="vl\random.h" />
    <ClInclude Include="vl\rodrigues.h" />
    <ClInclude Include="vl\scalespace.h" />
    <ClInclude Include="vl\shuffle-def.h" />
    <ClInclude Include="vl\sift.h" />
    <ClInclude Include="vl\slic.h" />
    <ClInclude Include="vl\stringop.h" />
    <ClInclude Include="vl\svm.h" />
    <ClInclude Include="vl\svmdataset.h" />
    <ClInclude Include="vl\vlad.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="vl\aib.c" />
    <ClCompile Include="vl\array.c" />
    <ClCompile Include="vl\covdet.c" />
    <ClCompile Include="vl\dsift.c" />
    <ClCompile Include="vl\fisher.c" />
    <ClCompile Include="vl\generic.c" />
    <ClCompile Include="vl\getopt_long.c" />
    <ClCompile Include="vl\gmm.c" />
    <ClCompile Include="vl\hikmeans.c" />
    <ClCompile Include="vl\hog.c" />
    <ClCompile Include="vl\homkermap.c" />
    <ClCompile Include="vl\host.c" />
    <ClCompile Include="vl\ikmeans.c" />
    <ClCompile Include="vl\imopv.c" />
    <ClCompile Include="vl\imopv_sse2.c" />
    <ClCompile Include="vl\kdtree.c" />
    <ClCompile Include="vl\kmeans.c" />
    <ClCompile Include="vl\lbp.c" />
    <ClCompile Include="vl\liop.c" />
    <ClCompile Include="vl\mathop.c" />
    <ClCompile Include="vl\mathop_avx.c" />
    <ClCompile Include="vl\mathop_sse2.c" />
    <ClCompile Include="vl\mser.c" />
    <ClCompile Include="vl\pgm.c" />
    <ClCompile Include="vl\quickshift.c" />
    <ClCompile Include="vl\random.c" />
    <ClCompile Include="vl\rodrigues.c" />
    <ClCompile Include="vl\scalespace.c" />
    <ClCompile Include="vl\sift.c" />
    <ClCompile Include="vl\slic.c" />
    <ClCompile Include="vl\stringop.c" />
    <ClCompile Include="vl\svm.c" />
    <ClCompile Include="vl\svmdataset.c" />
    <ClCompile Include="vl\vlad.c" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

使用vl_sift

#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;
#define PI 3.1415926
extern "C" {
#include <vl/generic.h>
#include <vl/stringop.h>
#include <vl/sift.h>
#include <vl/getopt_long.h>
};
struct QKeyPoint {
    float o;
    float x;
    float y;
    float r;
    float main_angle;
    int angle_cnt;
    float desc[4][128];

};

void vl_sift_extract(VlSiftFilt* vl_sift, vl_sift_pix* data, vector<KeyPoint>& kpts, Mat& desc) {
    if (vl_sift_process_first_octave(vl_sift, data) == VL_ERR_EOF) return;
    double angles[4];
    vector<float*> temp;
    //
   // float* d = reinterpret_cast<float*>(desc.data);
    do {
        vl_sift_detect(vl_sift);
        VlSiftKeypoint* p = vl_sift->keys;
        for (int i = 0; i < vl_sift->nkeys; i++, p++) {
            KeyPoint kp(Point2f(p->x, p->y), p->sigma);
            int angle_cnt = vl_sift_calc_keypoint_orientations(vl_sift, angles, p);
            if (angle_cnt > 0) {
                kp.angle = angles[0] / PI * 360;
                float* d = new float[128];
                vl_sift_calc_keypoint_descriptor(vl_sift, d , p, angles[0]);
                temp.push_back(d);
            }
            kp.octave = p->o; 
            kpts.push_back(kp);
        }


    } while (vl_sift_process_next_octave(vl_sift) != VL_ERR_EOF);
    desc = Mat::zeros(temp.size(), 128, CV_32FC1);
    float* d = reinterpret_cast<float*>(desc.data);
    for (int i = 0; i < temp.size(); i++ , d+= 128) {
        memcpy(d, temp[i], 128 * sizeof(float));
        delete[]temp[i];
    }

} 
const char* name1 = "a.jpg";
const char* name2 = "b.jpg";
int main(int argc, char* argv[]) {
    Mat img = imread(name1, IMREAD_GRAYSCALE);
    Mat float_img;
    img.convertTo(float_img, CV_32F);

    Mat color_img_a = imread(name1);
    Mat color_img_b = imread(name2);

    VlSiftFilt* vl_sift = vl_sift_new(img.cols, img.rows, 4, 3, 0);
    vl_sift_set_peak_thresh(vl_sift, atof(argv[1]));
    vl_sift_set_edge_thresh(vl_sift, atof(argv[2]));

    vector<KeyPoint> kpts_a, kpts_b;

    Mat desc_a, desc_b;

    vl_sift_extract(vl_sift, (vl_sift_pix*)(float_img.data), kpts_a, desc_a);
    img = imread(name2, IMREAD_GRAYSCALE);
    img.convertTo(float_img, CV_32F);

    VlSiftFilt* vl_sift2 = vl_sift_new(img.cols, img.rows, 4, 3, 0);
    vl_sift_set_peak_thresh(vl_sift2, atof(argv[1]));
    vl_sift_set_edge_thresh(vl_sift2, atof(argv[2]));

    vl_sift_extract(vl_sift2, (vl_sift_pix*)(float_img.data), kpts_b, desc_b);

    cout << " Features : " << kpts_a.size() << ", " << kpts_b.size() << endl;
    for (auto& k : kpts_a) {
        circle(color_img_a, k.pt, k.size, CV_RGB(255, 0, 0)); 
    }
    for (auto& k : kpts_b) {
        circle(color_img_b, k.pt, k.size, CV_RGB(0, 255, 0)); 
    }
     Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(DescriptorMatcher::FLANNBASED);
     vector<  vector<DMatch> > knn_matches;
     matcher->knnMatch(desc_a, desc_b, knn_matches, 2);
    


    //-- Filter matches using the Lowe's ratio test
    const float ratio_thresh = 0.75f;
    std::vector<DMatch> good_matches;
    for (size_t i = 0; i < knn_matches.size(); i++)
    {
        if (knn_matches[i][0].distance < ratio_thresh * knn_matches[i][1].distance)
        {
            good_matches.push_back(knn_matches[i][0]);
        }
    }

    //-- Draw matches
    Mat img_matches;
    drawMatches(color_img_a, kpts_a, color_img_b, kpts_b, good_matches, img_matches, Scalar::all(-1),
    Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
          


    vl_sift_delete(vl_sift);
    vl_sift_delete(vl_sift2);
    //imshow("SIFT Match Testing", img_matches);
    imwrite("match-result.jpg", img_matches); 
    return 0;
}

没有大变化的话,匹配效果还可以。

在这里插入图片描述
在这里插入图片描述

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

SIFT的两个版本:OpenCV和VL_SIFT 的相关文章

  • ESP32开发阶段启用 Secure Boot 与 Flash encryption

    Secure Boot 与 Flash encryption详情 请参考 https blog csdn net espressif article details 79362094 1 开发环境 AT版本 2 4 0 0 发布 IDF 与
  • git忽略文件地址

    git忽略文件地址 Objective C gitignore gitignore
  • String和StringBuffer的常见用法

    链接 https www nowcoder com questionTerminal fe6b651b66ae47d7acce78ffdd9a96c7 answerType 1 f discussion来源 牛客网 String的用法 ja
  • dubbo配置提供者和消费者

    1 找到对应的文件 提供者 消费者 参考dubbo官网 http dubbo apache org zh cn docs user quick start html
  • 【NLP】第 6 章 :微调预训练模型

    到目前为止 我们已经了解了如何使用包含预训练模型的huggingface API 来创建简单的应用程序 如果您可以从头开始并仅使用您自己的数据来训练您自己的模型 那不是很棒吗 如果您没有大量空闲时间或计算资源可供使用 那么使用迁移学习 是最
  • 连接池

    总结 1 连接池 java对外提供了连接的接口 连接池的存在就省去了每次创建和释放连接 2 连接池的连接条件 1 将commons pool 1 5 6 jar的jar包引进java项目下的lib文件夹 3 用连接池对象代替dao 层的Co
  • TP6.0 自定义命令创建类文件

    一 修改框架核心扩展包 1 新增指令配置项 2 创建逻辑层类文件模板 3 创建 Logic php 文件 4 执行命令 创建逻辑层类文件 二 不用修改框架源码 推荐 1 创建一个自定义命令类文件 以逻辑层类文件为例 2 复制创建模型类的命令
  • 解决 npm或pnpm : 无法加载文件 C:\Users\bts\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本

    vscode 使用 npm 或 pnpm打开网页时出现此问题 解决方法 点击左下角开始 找到Windows PowerShell 点击右键找到更多 找到以管理员身份运行 输入命令 set ExecutionPolicy RemoteSign
  • 使用禅道 api 添加用户完整流程与分析

    在使用禅道系统时 有时为了方便 需要与其他系统对接 如其他系统添加用户后可以直接同步到禅道系统 而不是在禅道系统重新添加一遍用户 禅道系统提供了二次开发的api 但是里面的内容并不详细 故笔者写这篇文章进行记录 这里先以 postman进行
  • STM32与ESP8266-MQTT固件的应用

    本文以Clion作为编译器 STM32F407作为芯片 通过串口以AT指令与ESP8266 01S进行通信 让其连接到腾讯云物联网平台 一 ESP8266 01S ESP8266 01S原本固件是不支持MQTT的 因此需要在安信可官网去下载
  • mysql union保持原有查询的排序

    摘要 mysql中对union之后的结果进行排序比较简单 但业务中也会遇到需要保持各个union结果集自身的排序情况 本文将介绍一种想要保持union前各个查询结果集的排序规则不变的处理方式 为各个结果集编排独立排序 规则描述与数据准备 数
  • Linux设备驱动入门

    Linux驱动配置 什么是驱动程序 驱动程序是应用层和硬件设备之间的一个软件层 它向应用层提供了一组标准化的调用接口 同时完全隐藏设备的工作细节 无操作系统时的设备驱动 有操作系统时候的设备驱动 有了操作系统之后 设备驱动反而变得更加复杂了
  • 黑白二维数组,判断两个二维数组之间的相似率

    include
  • 排序算法---希尔排序---详解&&代码

    希尔排序 希尔排序 从整体宏观上有序逐步细节到局部的有序 希尔排序是一种改进版的插入排序 普通的插入排序算法中 是从第2个节点开始 依次插入到有序序列中 这种做法虽然 一次成形 但研究发现时间效率上这么做并不划算 希尔排序的时间复杂度为O
  • Maven 父子POM文件 相同依赖不同版本的问题

    Maven 父子POM文件 相同依赖不同版本的问题 默认用父一级的版本 而且子POM文件的版本处会有黄色Warn 解决 增加
  • qt.qpa.plugin: Could not load the Qt platform plugin “xcb“ in

    在运行mmdetection的时候发现qt5里面缺了啥 qt qpa plugin Could not load the Qt platform plugin xcb in 卸载了好多Qt5 重新安装 都没有用 尝试1 sudo gedit

随机推荐