随笔 - 632  文章 - 17  评论 - 54  阅读 - 93万

OpenCV实现图搜图简单案例

一、概述

  使用OpenCV实现一个简单的图搜索的小功能

  特点:暴力匹配

  实现原理:

    1.将图片集合生成特征描述,并存入文件

    2.加载目标图像,并生成图像特征描述

    3.加载图像特征描述文件列表

    4.图像特征描述和集合中的特征描述列表进行匹配

    5.如果匹配成功就说明搜索有值,如果没有匹配成功说明没有搜索结果。

    

 

二、代码示例

复制代码
#include "ORBImageMatch.h"

ORBImageMatch::ORBImageMatch(QWidget* parent)
    : QWidget(parent)
{
    this->setWindowTitle("图像匹配(相似度比较)");
    this->setFixedSize(QSize(320, 480));

    Button* btn1 = new Button(this);
    btn1->setText("选择第一张图");
    Button* btn2 = new Button(this);
    btn2->setText("选择第二张图");
    Button* btn3 = new Button(this);
    btn3->setText("开始匹配");
    Button* btn4 = new Button(this);
    btn4->setText("生成特征文件");
    QVBoxLayout* vLayout = new QVBoxLayout(this);
    vLayout->setAlignment(Qt::AlignTop);
    vLayout->addWidget(btn1);
    vLayout->addWidget(btn2);
    vLayout->addWidget(btn3);
    vLayout->addWidget(btn4);


    connect(btn1, &Button::clicked, [=]() {
        filePath1 = QFileDialog::getOpenFileName(this, tr("请选择图片"), "C:/Users/DBF-DEV-103/Downloads/", tr("Image Files(*.jpg *.png *.webp *.jpeg)"));
        searchImage();
        });

    connect(btn2, &Button::clicked, [=]() {
        filePath2 = QFileDialog::getOpenFileName(this, tr("请选择图片"), "C:/Users/DBF-DEV-103/Downloads/", tr("Image Files(*.jpg *.png *.webp *.jpeg)"));
        });

    connect(btn3, &Button::clicked, [=]() {
        matchImage();
        });

    //选择所有文件并生成特征
    connect(btn4, &Button::clicked, [=]() {
        // 打开文件对话框,选择目录
        QString directory = QFileDialog::getExistingDirectory(this, tr("请选择需要是生成特征的文件"),
        "C:/Users/DBF-DEV-103/Downloads",
        QFileDialog::ShowDirsOnly
        | QFileDialog::DontResolveSymlinks);

    // 检查是否选择了目录
    if (directory.isEmpty()) {
        // 用户没有选择目录
        qDebug() << "请选择目录";
        return;
    }
    //qDebug() << "directory=" << directory;
    // 获取目录下所有文件的列表
    QStringList fileList = QDir(directory).entryList(QDir::Files);
    batchGenerateImageCharacteristics(directory, fileList);
        });
}

void ORBImageMatch::matchImage() {
    // 加载目标图片和仓库图片
    cv::Mat targetImage = cv::imread(filePath1.toStdString().c_str(), cv::IMREAD_GRAYSCALE);
    cv::Mat repositoryImage = cv::imread(filePath2.toStdString().c_str(), cv::IMREAD_GRAYSCALE);

    // 初始化ORB检测器
    cv::Ptr<cv::ORB> orbDetector = cv::ORB::create();
    std::vector<cv::KeyPoint> keypointsRepository, keypointsTarget;
    cv::Mat descriptorsRepository, descriptorsTarget;

    // 检测特征点并计算描述符
    orbDetector->detectAndCompute(repositoryImage, cv::noArray(), keypointsRepository, descriptorsRepository);
    orbDetector->detectAndCompute(targetImage, cv::noArray(), keypointsTarget, descriptorsTarget);

    // 创建暴力匹配器对象
    cv::BFMatcher matcher;
    std::vector<cv::DMatch> matches;

    // 进行匹配
    matcher.match(descriptorsTarget, descriptorsRepository, matches);//对特征带你进行匹配然后比较距离

    // 根据匹配结果判断是否存在
    double minDist = 100;
    for (auto match : matches) {
        qDebug() << "distance=" << match.distance;
        if (match.distance < minDist)
            minDist = match.distance;
    }

    // 设定阈值
    if (minDist < 100) {
        qDebug() << "目标图片在仓库中存在";
    }
    else {
        qDebug() << "目标图片在仓库中不存在";
    }
    //c/c++ opencv保存特征到本地及加载本地特征并匹配相似度
}

//批量生成特征文件
void ORBImageMatch::batchGenerateImageCharacteristics(QString directory, QStringList fileList) {
    for (QString filePath : fileList) {
        qDebug() << "filePath=" << directory + "/" + filePath;
        QString imageFilePath = directory + "/" + filePath;
        cv::Mat targetImage = cv::imread(imageFilePath.toStdString().c_str(), cv::IMREAD_GRAYSCALE);
        cv::Ptr<cv::ORB> orbDetector = cv::ORB::create();
        std::vector<cv::KeyPoint> keypointsTarget;
        cv::Mat  descriptorsTarget;
        // 检测特征点并计算描述符
        orbDetector->detectAndCompute(targetImage, cv::noArray(), keypointsTarget, descriptorsTarget);
        //将得到的特征存起来
        // 创建FileStorage对象并打开文件
        QFileInfo fileInfo(filePath);
        QString fileName = fileInfo.completeBaseName(); // 返回不带扩展名的文件名
        QString mDirectory = directory + "/features/";
        QString fileFullName = "C:/Uxxxxs/xxxxxxx/Downloads/features/" + fileName + ".yml";
        qDebug() << "fileFullName=" << fileFullName;
        cv::FileStorage fs(fileFullName.toStdString().c_str(), cv::FileStorage::WRITE);
        if (!fs.isOpened()) {
            std::cerr << "Error: 无法打开文件" << std::endl;
            return;
        }
        // 将特征存储到文件

        //fs.write(fileName.toStdString(), descriptorsTarget);
        cv::String mFileName = cv::String(fileName.toStdString());
        fs << "feature_" + mFileName << descriptorsTarget;
        // 关闭文件
        fs.release();
        std::cout << descriptorsTarget << std::endl;
    }

}

//搜索图片
void ORBImageMatch::searchImage() {
    // 加载目标图片和仓库图片
    cv::Mat targetImage = cv::imread(filePath1.toStdString().c_str(), cv::IMREAD_GRAYSCALE);

    // 初始化ORB检测器
    cv::Ptr<cv::ORB> orbDetector = cv::ORB::create();
    std::vector<cv::KeyPoint>  keypointsTarget;
    cv::Mat  descriptorsTarget;

    // 检测特征点并计算描述符
    orbDetector->detectAndCompute(targetImage, cv::noArray(), keypointsTarget, descriptorsTarget);

    // 创建暴力匹配器对象
    cv::BFMatcher matcher;
    std::vector<cv::DMatch> matches;

    //加载特征列表
    // 打开文件对话框,选择目录
    QString directory = "C:/Uxxxxs/xxxxxxx/Downloads/features/";

    // 检查是否选择了目录
    if (directory.isEmpty()) {
        // 用户没有选择目录
        qDebug() << "请选择目录";
        return;
    }
    //qDebug() << "directory=" << directory;
    // 获取目录下所有文件的列表
    QStringList fileList = QDir(directory).entryList(QDir::Files);
    vector<QString> vectors;
    for (QString filePath : fileList) {
        QFileInfo fileInfo(filePath);
        QString fileName = fileInfo.completeBaseName(); // 返回不带扩展名的文件名
        QString fileFullName = directory + filePath;
        qDebug() << "fileFullName=" << fileFullName;
        // 初始化FileStorage对象
        cv::FileStorage fs(fileFullName.toStdString().c_str(), cv::FileStorage::READ);
        if (!fs.isOpened()) {
            qDebug() << "Failed to open " << fileFullName;
            return;
        }

        // 假设特征存储在名为"features"的节点下
        cv::Mat descriptors;
        const String feature_name = "feature_" + fileName.toStdString();
        fs[feature_name] >> descriptors;
        // 进行匹配
        matcher.match(descriptorsTarget, descriptors, matches);//对特征带你进行匹配然后比较距离
        // 根据匹配结果判断是否存在
        double minDist = 100;
        for (auto match : matches) {
            qDebug() << "distance=" << match.distance;
            if (match.distance < minDist)
                minDist = match.distance;
        }

        // 设定阈值
        if (minDist < 100) {
            //qDebug() << "目标图片在仓库中存在";
            vectors.push_back(fileFullName);
        }
        else {
            //qDebug() << "目标图片在仓库中不存在";
        }
        // 关闭FileStorage对象
        fs.release();
    }
    if (vectors.size() > 0) {
        qDebug() << "检测到相似图片";
    }
    else {
        qDebug() << "未检测到相似图片";
    }

    for (auto mPath : vectors) {
        qDebug() << "mPath=" << mPath;
    }

}
ORBImageMatch::~ORBImageMatch()
{
}
复制代码

 

  

posted on   飘杨......  阅读(183)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
历史上的今天:
2021-07-30 forever的安装与简单使用
2021-07-30 CentOS7.3如果命令行的命令几乎都无法使用
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示