OpenCV入门(10):基本操作之ROI、通道分离与合并、创建空白图像

一、图像 ROI(Region of Interest)

ROI 是指图像中我们感兴趣的区域。通过提取 ROI,我们可以只对图像的特定部分进行处理,从而提高处理效率。

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


1.1 提取 ROI

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

核心步骤:

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

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

#include <QApplication>
#include <QDebug>

// 添加相关头文件和包
#include <opencv2/opencv.hpp>
using namespace cv;

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

    // 1. 读取原始图像
    cv::Mat originalImage = cv::imread("./test.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) 开始,提取一个 300x200 大小的区域
    int x = 150;
    int y = 100;
    int width = 300;
    int height = 200;

    // 安全检查:确保定义的 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 对象,指定 ROI 的位置和尺寸
    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 a.exec();
}

关键代码就是:

// 创建一个 cv::Rect 对象,指定 ROI 的位置和尺寸
cv::Rect roiRect(x, y, width, height);

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

效果图如下所示:

Blog_OpenCV_Learnl_22.png


1.2 修改 ROI

提取 ROI 后,可以对其进行修改,然后将修改后的 ROI 放回原图像中。将上面代码修改下:

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

// 4. 修改 ROI
roiImage = cv::Scalar(0, 0, 255);  // 将ROI设置为红色(BGR格式)

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

效果图如下所示:

Blog_OpenCV_Learnl_23.png


二、图像通道分离与合并

在 OpenCV 中,图像通常是以 cv::Mat 对象的形式表示的,它是一个多维数组,可以用来存储图像数据。在 OpenCV 中,图像可以是单通道的(灰度图),也可以是三通道的(彩色图,如 RGB 或 BGR)。对于三通道图像,你可以分离出各个通道(例如,红色、绿色、蓝色通道),也可以将多个单通道图像合并成一个三通道图像。


2.1 图像通道分离

要分离一个三通道图像的各个通道,你可以使用 cv::split 函数。例如,将一个 BGR 图像分离成三个单独的通道:

#include <QApplication>
#include <QDebug>

// 添加相关头文件和包
#include <opencv2/opencv.hpp>
using namespace cv;

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

    // 读取图像
    cv::Mat img = cv::imread("./test.jpg");
    if (img.empty()) {
        std::cout << "图像加载失败!" << std::endl;
        return -1;
    }

    // 分离通道
    std::vector<cv::Mat> channels;
    cv::split(img, channels);

    // channels[0] 是蓝色通道
    // channels[1] 是绿色通道
    // channels[2] 是红色通道

    // 显示蓝色通道
    cv::imshow("Blue Channel", channels[0]);

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

    return a.exec();
}

效果图如下所示:

Blog_OpenCV_Learnl_24.png


2.2 图像通道合并

要将分离的通道合并回一个三通道图像,你可以使用 cv::merge 函数。例如,将三个单通道图像合并成一个 BGR 图像:

#include <QApplication>
#include <QDebug>

// 添加相关头文件和包
#include <opencv2/opencv.hpp>
using namespace cv;

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

    // 创建三个单通道图像示例(在实际应用中,你可能从某个地方获取这些通道)
    cv::Mat blue(480, 640, CV_8UC1, cv::Scalar(255)); // 蓝色通道,全白
    cv::Mat green(480, 640, CV_8UC1, cv::Scalar(0));  // 绿色通道,全黑
    cv::Mat red(480, 640, CV_8UC1, cv::Scalar(0));    // 红色通道,全黑

    // 将单通道图像合并成一个三通道图像
    std::vector<cv::Mat> channels;
    channels.push_back(blue); // 蓝色通道
    channels.push_back(green); // 绿色通道
    channels.push_back(red); // 红色通道

    cv::Mat image;
    cv::merge(channels, image); // 合并通道

    // 显示结果图像(应该是全蓝的)
    cv::imshow("Merged Image", image);

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

    return a.exec();
}

效果图如下所示:

Blog_OpenCV_Learnl_25.png


三、创建空白图像并赋值

API:

static MatExpr zeros(Size size, int type);
  • size:空白图像尺寸
  • type:通道数

示例:

#include <QApplication>
#include <QDebug>

// 添加相关头文件和包
#include <opencv2/opencv.hpp>
using namespace cv;

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

    // 创建空白图像
    Mat m3 = Mat::zeros(Size(400,400), CV_8UC3);	// 8uc1无符号8位,通道1
    m3 = Scalar(0, 0, 255);	// 赋值 B G R
    imshow("Image", m3);	//以上就创建了一个纯红色图像

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

    return a.exec();
}

效果图如下所示:

Blog_OpenCV_Learnl_30.png


posted @ 2025-08-05 17:09  fengMisaka  阅读(47)  评论(0)    收藏  举报