C++ 程序使用 OpenCV 可视化和分析两个图像之间特征点的对应关系

文章目录

代码功能

  1. 创建图像和生成随机特征点

    • 程序首先创建两个灰度图像(m_image_Left_BGRm_image_Right_BGR),并将它们转换为彩色图像。
    • 然后,生成两组随机特征点(mvKeysmvKeysRight),分别对应于这两个图像。
  2. 关联左右图特征点

    • 使用一个二维向量 vRowIndices 假设存储与左图特征点在 Y 轴上对应的右图特征点索引。这里简单地假设左图中的每个特征点对应于右图中具有相同索引的特征点。
  3. 合并图像并绘制特征点

    • 对于左图的每个特征点,程序创建一张包含左右图的合并图像。
    • 在合并图像上绘制坐标轴,并显示图像的宽度和高度。
    • 在合并图像的左侧部分(对应于 m_image_Left_BGR),标记左图特征点的位置,并在右侧部分(对应于 m_image_Right_BGR)标记对应的右图特征点的位置。
  4. 保存和绘制特征点信息

    • 对于每个左图特征点及其对应的右图特征点,程序绘制一个红色圆圈表示特征点的位置,并添加包含特征点索引和坐标的文本标签。
    • 然后,将包含这些信息的合并图像保存为 PNG 文件,文件名基于左图特征点的索引和对应的右图特征点的索引。
  5. 文件保存路径

    • 保存的文件路径被设置为当前目录下的一个子目录。

总的来说,这个程序用于可视化和分析两个图像之间特征点的对应关系。它在合并的图像上显示了左右图的特征点,以及相关的坐标信息,这在图像处理、立体视觉或特征点匹配分析中非常有用。

源码文件

cpp 复制代码
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>

#include <string>  // 确保包含这个头文件

using namespace std;

std::vector<cv::KeyPoint> generateRandomKeyPoints(const cv::Mat& image, int numPoints) {
    std::vector<cv::KeyPoint> keypoints;
    cv::RNG rng;
    for (int i = 0; i < numPoints; ++i) {
        cv::Point2f pt(rng.uniform(0.f, (float)image.cols), rng.uniform(0.f, (float)image.rows));
        keypoints.push_back(cv::KeyPoint(pt, 1.f));
    }
    return keypoints;
}

int main() {
    // 创建两个简单的灰度图像,并转换为彩色图像
    cv::Mat m_image_Left_BGR = cv::Mat::zeros(240, 320, CV_8UC1);
    cv::Mat m_image_Right_BGR = cv::Mat::zeros(240, 320, CV_8UC1);
    cv::cvtColor(m_image_Left_BGR, m_image_Left_BGR, cv::COLOR_GRAY2BGR);
    cv::cvtColor(m_image_Right_BGR, m_image_Right_BGR, cv::COLOR_GRAY2BGR);

    // 生成一些随机特征点
    std::vector<cv::KeyPoint> mvKeys = generateRandomKeyPoints(m_image_Left_BGR, 100);
    std::vector<cv::KeyPoint> mvKeysRight = generateRandomKeyPoints(m_image_Right_BGR, 100);

    // 假设 vRowIndices 是一个二维向量,存储与左图特征点在 Y 轴上对应的右图特征点索引
    std::vector<std::vector<size_t>> vRowIndices(m_image_Left_BGR.rows);
    for (int i = 0; i < mvKeys.size(); ++i) {
        vRowIndices[mvKeys[i].pt.y].push_back(i); // 为了演示,我们简单地假设每个左图特征点与相同索引的右图特征点对应
    }

       for(int iL=0; iL<mvKeys.size(); iL++)
        {
            const cv::KeyPoint &kpL = mvKeys[iL];

            // 循环绘制和左目当前特征点 和 vRowIndices[i]
            // 1. 这里生成一张大图包括左右目
            const int height = max(m_image_Left_BGR.rows, m_image_Right_BGR.rows);
            const int width = m_image_Left_BGR.cols + m_image_Right_BGR.cols;
            cv::Mat output(height, width, CV_8UC3, cv::Scalar(0, 0, 0));
            m_image_Left_BGR.copyTo(output(cv::Rect(0, 0, m_image_Left_BGR.cols, m_image_Left_BGR.rows)));
            m_image_Right_BGR.copyTo(output(cv::Rect(m_image_Left_BGR.cols, 0, m_image_Right_BGR.cols, m_image_Right_BGR.rows)));

            // 左目绘制x轴
            cv::line(output, cv::Point(5, 5), cv::Point(m_image_Left_BGR.cols - 100, 5), cv::Scalar(0, 0, 255), 2);
            cv::arrowedLine(output, cv::Point(m_image_Left_BGR.cols - 100, 5), cv::Point(m_image_Left_BGR.cols - 10, 5), cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
            cv::putText(output, "X", cv::Point(m_image_Left_BGR.cols - 150, 30), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
            cv::putText(output, "Width Col: " + std::to_string(m_image_Left_BGR.cols), cv::Point(m_image_Left_BGR.cols - 150, 50), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);

            // 右目绘制x轴
            cv::line(output, cv::Point(m_image_Left_BGR.cols + 5, 5), cv::Point(m_image_Left_BGR.cols + m_image_Right_BGR.cols - 100, 5), cv::Scalar(0, 0, 255), 2);
            cv::arrowedLine(output, cv::Point(m_image_Left_BGR.cols + m_image_Right_BGR.cols - 100, 5), cv::Point(m_image_Left_BGR.cols + m_image_Right_BGR.cols - 10, 5), cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
            cv::putText(output, "X", cv::Point(m_image_Left_BGR.cols + m_image_Right_BGR.cols - 150, 30), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
            cv::putText(output, "Width Col: " + std::to_string(m_image_Right_BGR.cols), cv::Point(m_image_Left_BGR.cols + m_image_Right_BGR.cols - 150, 50), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 1, cv::LINE_AA);

            // 左目绘制Y轴
            cv::line(output, cv::Point(5, 5), cv::Point(5, m_image_Left_BGR.rows - 100), cv::Scalar(0, 255, 0), 2);
            cv::arrowedLine(output, cv::Point(5, m_image_Left_BGR.rows - 100), cv::Point(5, m_image_Left_BGR.rows - 5), cv::Scalar(0, 255, 0), 2, cv::LINE_AA);
            cv::putText(output, "Y", cv::Point(10, m_image_Left_BGR.rows - 20), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2, cv::LINE_AA);
            cv::putText(output, "Height Row: " + std::to_string(m_image_Left_BGR.rows), cv::Point(10, m_image_Left_BGR.rows - 40), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);

            // 右目绘制Y轴
            cv::line(output, cv::Point(m_image_Left_BGR.cols + 5, 5), cv::Point(m_image_Left_BGR.cols + 5, m_image_Right_BGR.rows - 100), cv::Scalar(0, 255, 0), 2);
            cv::arrowedLine(output, cv::Point(m_image_Left_BGR.cols + 5, m_image_Right_BGR.rows - 100), cv::Point(m_image_Left_BGR.cols + 5, m_image_Right_BGR.rows - 5), cv::Scalar(0, 255, 0), 2, cv::LINE_AA);
            cv::putText(output, "Y", cv::Point(m_image_Left_BGR.cols + 10, m_image_Right_BGR.rows - 20), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 2, cv::LINE_AA);
            cv::putText(output, "Height Row: " + std::to_string(m_image_Right_BGR.rows), cv::Point(m_image_Left_BGR.cols + 10, m_image_Right_BGR.rows - 40), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);

            // 2. 这里把左目特征点绘制大图的左目上
            circle(output, kpL.pt, 2, cv::Scalar(255, 0, 0), 2);
            cv::putText(output,"iL " + std::to_string(int(iL)) + ", X " + std::to_string(int(kpL.pt.x)) + ", Y " + std::to_string(int(kpL.pt.y)),
                        cv::Point(kpL.pt.x - 25, kpL.pt.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.4,
                        cv::Scalar(255, 0, 0), 1);

            for(size_t iC=0; iC<vRowIndices[kpL.pt.y].size(); iC++) {
                const size_t iR = vRowIndices[kpL.pt.y][iC];
                const cv::KeyPoint &kpR = mvKeysRight[iR];

                // 3. 这里把右目特征点绘制大图的右目上,并且每一个特征点是一张图像
                circle(output, (kpR.pt + cv::Point2f((float) m_image_Left_BGR.cols, 0.f)), 2,cv::Scalar(255, 0, 0), 2);
                cv::putText(output,"iC " + std::to_string(int(iC)) + ", X " + std::to_string(int(kpR.pt.x)) + ", Y " + std::to_string(int(kpR.pt.y)),
                            cv::Point(kpR.pt.x + m_image_Left_BGR.cols - 15,kpR.pt.y - 15),
                            cv::FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 0, 0), 1);
                cv::imwrite("./" + to_string(iL) + "_" + to_string(iC) + ".png",output);
            }
        }


    return 0;
}

编译文件

bash 复制代码
cmake_minimum_required(VERSION 3.10)
project(ImagePyramid)

# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 找到OpenCV包
find_package(OpenCV REQUIRED)

# 包含OpenCV头文件
include_directories(${OpenCV_INCLUDE_DIRS})

# 添加可执行文件
add_executable(ImagePyramid main.cpp)

# 链接OpenCV库
target_link_libraries(ImagePyramid ${OpenCV_LIBS})
相关推荐
NAGNIP9 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab10 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab10 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP13 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年13 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼14 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS14 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区15 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈15 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
端平入洛16 小时前
delete又未完全delete
c++