opencv的SIFT样例(CPP/python)

Python代码的实现:

import cv2
import numpy as np
import time
import os
def main():
    images = os.listdir('./images/')
    pre_image = cv2.imread('./images/1.jpg', 0)
    print("images:",images)

    # 初始化 SIFT 和 SURF
    sift = cv2.xfeatures2d.SIFT_create()
    # surf = cv2.xfeatures2d.SURF_create()
    bf = cv2.BFMatcher()
    start_time = time.time()

    for img in images:
        img2 = cv2.imread(os.path.join('./images', img), 0)

        # 寻找关键点和计算描述符
        kp1, des1 = sift.detectAndCompute(pre_image, None)
        kp2, des2 = sift.detectAndCompute(img2, None)

        ti = time.time()
        # 匹配关键点
        matches = bf.knnMatch(des1, des2, k=2)
        # 应用比值测试来获取好的匹配点
        good = []
        for m, n in matches:
            if m.distance < 0.75 * n.distance:
                good.append([m])

        # 可视化匹配结果
        img3 = cv2.drawMatchesKnn(pre_image, kp1, img2, kp2, good, None, flags=2)
        print("knnMatch spend time:{} second".format(time.time()-ti))

    print("this spend time is :{} second".format(time.time()-start_time))

if __name__ == "__main__":
    main()
  
#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <iostream>
#include <vector>
#include <ctime>
#include <sys/types.h>
#include <dirent.h>
#include <iostream>
#include <chrono>

void readFilesInDir(const std::string& dir_path, std::vector<std::string>& files)
{
    DIR *dir;
    struct dirent *ent;
    if ((dir = opendir(dir_path.c_str())) != NULL)
    {
        while ((ent = readdir(dir)) != NULL)
        {
            if (ent->d_name[0] != '.')
            {
                files.push_back(ent->d_name);
            }
        }
        closedir(dir);
    }
}
int main()
{
    std::vector<std::string> files;
    readFilesInDir("./images", files);

    cv::Ptr<cv::xfeatures2d::SIFT> sift = cv::xfeatures2d::SIFT::create();
    cv::BFMatcher bf;
    cv::Mat pre_image = cv::imread("./images/1.jpg", 0);
    clock_t start = clock();
    auto _start = std::chrono::high_resolution_clock::now();

    for (const auto& file : files)
    {
        cv::Mat img2 = cv::imread("./images/" + file, 0);

        std::vector<cv::KeyPoint> kp1, kp2;
        cv::Mat des1, des2;

        sift->detectAndCompute(pre_image, cv::noArray(), kp1, des1);
        sift->detectAndCompute(img2, cv::noArray(), kp2, des2);
        std::vector<std::vector<cv::DMatch>> matches;
        auto _t = std::chrono::high_resolution_clock::now();
        bf.knnMatch(des1, des2, matches, 2);
        std::vector<cv::DMatch> goodMatches;

        auto _e = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::milli> _elapsed = _e - _t;

        double _ex = _elapsed.count() / 1000.0;
        std::cout << "step spend time is :" << _ex << " s" << std::endl;


        for (int i = 0; i < matches.size(); ++i)
        {
            if (matches[i][0].distance < 0.75 * matches[i][1].distance)
            {
                goodMatches.push_back(matches[i][0]);
            }
        }
        cv::Mat img3;
        cv::drawMatches(pre_image, kp1, img2, kp2, goodMatches, img3, cv::Scalar::all(-1), cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> elapsed = end - _start;
    double elapsedSeconds = elapsed.count() / 1000.0;
    std::cout << "this spend time is: " << (double)(clock() - start) / CLOCKS_PER_SEC << " s : " << elapsedSeconds << " seconds" << std::endl;
    return 0;
}

结论说明:
两种代码在同一个环境上的,相同的图片大小和数量(19张图片),运行耗时如下:
python

spend time is : 57.90586733818054 second

c++

spend time is: 57.71 seconds

差距不会很明显,但是如果文件很多,并且使用多线程/多进程,会有一个比较明显的差距。

### 使用 OpenCV 实现 SIFT 特征点提取 为了利用 OpenCV 进行 SIFT (Scale-Invariant Feature Transform) 特征点的提取,可以遵循特定的过程并编写相应的代码。SIFT 算法能够识别图像中的局部特征,即所谓的“关键点”,这些关键点对于尺度和旋转变化具有不变性[^3]。 在 C++ 和 OpenCV 中实现此功能涉及几个步骤: #### 加载输入图像 首先需要加载用于执行特征提取的输入图像。这可以通过调用 `cv::imread` 函数完成,该函数允许从文件路径读取图片数据,并将其存储在一个矩阵变量中以便后续处理[^2]。 ```cpp #include <opencv2/opencv.hpp> using namespace cv; int main() { Mat img = imread("path_to_image.jpg"); if(img.empty()){ cout << "Could not open or find the image" << endl; return -1; } } ``` #### 创建 SIFT 对象实例化 接着创建一个 SIFT 类的对象,它负责计算给定图像的关键点及其描述符。需要注意的是,在较新的 OpenCV 版本里,由于专利原因,默认安装可能不包含非自由算法模块;因此,如果遇到找不到 SIFT 的情况,则需额外安装 opencv-contrib-python 或者编译带有 Xfeatures2d 支持的版本[^1]。 ```cpp Ptr<SIFT> sift = SIFT::create(); vector<KeyPoint> keypoints; Mat descriptors; sift->detectAndCompute(img, noArray(), keypoints, descriptors); ``` 上述代码片段展示了如何通过 `detectAndCompute()` 方法同时获取关键点位置 (`keypoints`) 及对应的描述子向量(`descriptors`) 。其中第二个参数为掩码(mask),这里设置为空表示整个图像都参与运算。 #### 显示结果 最后一步是可视化所得到的结果。OpenCV 提供了一个方便的方法叫做 `drawKeypoints` ,可以直接绘制出所有的关键点到原图之上形成一幅新图像,便于观察效果。 ```cpp Mat outputImage; drawKeypoints(img, keypoints, outputImage, Scalar(0, 255, 0), DrawMatchesFlags::DEFAULT ); imshow("Detected Keypoints",outputImage); waitKey(0); // Wait indefinitely until a key is pressed. return 0; ``` 这段完整的程序实现了基于 OpenCV 库的 SIFT 特征点检测过程,并提供了直观的方式查看最终成果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>