使用 C/C++ 和 OpenCV 提取图像的感兴趣区域 (ROI)

使用 C/C++ 和 OpenCV 提取图像的感兴趣区域 (ROI)

在计算机视觉中,感兴趣区域 (Region of Interest, ROI) 是指从图像中选择的一个特定区域,我们希望对其进行进一步的处理或分析。例如,在人脸识别中,ROI 就是包含人脸的矩形框。OpenCV 提供了简单而高效的方法来提取 ROI。

本文将介绍如何使用 C++ 和 OpenCV 库来从图像中提取 ROI。

主要方法:使用 cv::Rect

最常用、最直接的方法是使用 cv::Rect 对象来定义 ROI。cv::Rect 指定了一个矩形区域,包含其左上角的坐标 (x, y) 以及矩形的宽度和高度。

核心步骤

  1. 加载图像 :使用 cv::imread() 函数将图像读入一个 cv::Mat 对象。
  2. 定义矩形 :创建一个 cv::Rect 对象,指定 ROI 的位置和尺寸。
  3. 提取 ROI :利用 cv::Mat 的括号 () 运算符,并传入 cv::Rect 对象来裁剪出 ROI。
  4. 显示结果 :使用 cv::imshow() 分别显示原始图像和提取出的 ROI。

完整示例代码 👨‍💻

这是一个完整的 C++ 示例,它加载一张图片,从中提取一个指定的矩形区域,并同时显示原始图和 ROI 图。

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

int main() {
    // 1. 读取原始图像
    // 确保图像文件 (例如 "sample_image.jpg") 在你的工作目录下,或提供完整路径
    cv::Mat originalImage = cv::imread("sample_image.jpg");

    if (originalImage.empty()) {
        std::cerr << "Error: Could not load the image!" << std::endl;
        return -1;
    }

    // 2. 定义 ROI 的矩形区域
    // cv::Rect(x, y, width, height)
    // - x: ROI 左上角的 x 坐标
    // - y: ROI 左上角的 y 坐标
    // - width: ROI 的宽度
    // - height: ROI 的高度
    //
    // 假设我们想从坐标 (250, 100) 开始,提取一个 300x400 大小的区域
    int x = 250;
    int y = 100;
    int width = 300;
    int height = 400;

    // 安全检查:确保定义的 ROI 没有超出原始图像的边界
    if ((x + width > originalImage.cols) || (y + height > originalImage.rows)) {
        std::cerr << "Error: The defined ROI exceeds the image boundaries!" << std::endl;
        return -1;
    }
    
    cv::Rect roiRect(x, y, width, height);

    // 3. 提取 ROI
    // 使用矩形对象来索引原始图像,创建一个指向 ROI 的 Mat 头
    cv::Mat roiImage = originalImage(roiRect);

    // 4. 显示结果
    cv::imshow("Original Image", originalImage);
    cv::imshow("ROI Image", roiImage);

    // 等待用户按键后退出
    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

如何编译和运行 (使用 CMake)

使用 CMake 是管理 C++ 和 OpenCV 项目的标准方式。

  1. 将以上代码保存为 extract_roi.cpp。

  2. 在同一目录下创建 CMakeLists.txt 文件:

    cmake 复制代码
    cmake_minimum_required(VERSION 3.10)
    project(ExtractROI_Project)
    
    find_package(OpenCV REQUIRED)
    
    include_directories(${OpenCV_INCLUDE_DIRS})
    
    add_executable(extract_roi extract_roi.cpp)
    target_link_libraries(extract_roi ${OpenCV_LIBS})
  3. 准备一张图片,并将其命名为 sample_image.jpg(或修改代码中的文件名)。

  4. 在终端中执行以下命令进行编译和运行:

    bash 复制代码
    mkdir build
    cd build
    cmake ..
    make
    ./extract_roi

运行后,你将看到两个窗口,一个显示原始全图,另一个仅显示你提取的感兴趣区域。


重要提示:视图 vs. 拷贝 ⚠️

默认情况下,通过 image(roiRect) 操作创建的 cv::Mat 不是一个独立的数据拷贝 ,而是一个指向原始图像内存的视图 (View) 或称"头 (Header)"。

这意味着:

  • 内存共享 :roiImage 和 originalImage 共享同一块图像数据。
  • 双向影响 :如果你在 roiImage 上绘制或进行修改,这些改动会直接反映在 originalImage 的对应区域。

如何创建独立拷贝?

如果你希望对 ROI 进行修改而不影响原始图像,你需要创建一个数据的深拷贝 (Deep Copy) 。这可以通过 clone() 或 copyTo() 方法实现。

cpp 复制代码
// 方法 1: 使用 clone()
cv::Mat roi_clone = originalImage(roiRect).clone();

// 方法 2: 使用 copyTo()
cv::Mat roi_copy;
originalImage(roiRect).copyTo(roi_copy);

现在,对 roi_clone 或 roi_copy 的任何修改都将是独立的,不会影响 originalImage。


掌握 ROI 提取是进行目标检测、图像分割和许多其他高级计算机视觉任务的基础。希望这篇文章能帮助你入门!

相关推荐
Logic1013 分钟前
C语言/数据结构位运算题解:异或XOR找出游戏速通中的“独特初始能量值“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
程序猿编码10 分钟前
C++/CUDA 手写 LLM 推理引擎:拆解 vLLM 核心 PagedAttention 与连续批处理
开发语言·c++·深度学习·神经网络·推理·vllm
hold?fish:palm16 分钟前
44 二叉搜索树中第K小的元素
开发语言·c++·算法
凉茶钱31 分钟前
【吃透C++】万字解析类和对象
开发语言·c++
白杨尚青1 小时前
C++入门篇(十):string(上)——认识string:构造与三大遍历(一条龙讲透operator[]、迭代器、auto、范围for)
java·开发语言·c++·笔记·stl
FlightYe1 小时前
视界原理之2D视频(二):视频文件里有什么
android·linux·网络·c++·ffmpeg·音视频·aac
Chen—LSN1 小时前
C语言——⽂件操作(1)
c语言·开发语言·c++·经验分享·笔记·算法·链表
木由里予1 小时前
GDB 使用手册(详细版)
c语言·vscode
辛苦才能1 小时前
C++ map/set 深度解析:从关联式容器的本质到 operator[] 的三重身份
开发语言·c++
Chen—LSN2 小时前
C语言——文件操作(2)
c语言·开发语言·c++·经验分享·笔记·算法·c#