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);
效果图如下所示:

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);
效果图如下所示:

二、图像通道分离与合并
在 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();
}
效果图如下所示:

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();
}
效果图如下所示:

三、创建空白图像并赋值
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();
}
效果图如下所示:


浙公网安备 33010602011771号