OpenCV实战——图像感兴趣区域

Posted 盼小辉丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV实战——图像感兴趣区域相关的知识,希望对你有一定的参考价值。

OpenCV实战(3)——图像感兴趣区域

0. 前言

在实际应用场景下,图像处理函数有时只需要应用于图像的部分区域。OpenCV 中使用了一种优雅而简单的机制来定义图像中的子区域并将可以将其视为常规图像进行操作。本节中,我们将学习如何定义图像内的感兴趣区域 (region of interest, ROI)。

1. 感兴趣区域

为了说明如何定义感兴趣区域 (region of interest, ROI),我们将一个尺寸较小图像复制到一个更大的图像上。例如,我们要将以下 OpenCV logo 插入到测试图像中:


为了完成该目标,需要定义可以应用复制操作的 ROIROI 的位置将决定 logo 在图像中的插入位置。

1.1 ROI 实例

首先,读取 logo 图像并定义 ROI。我们可以使用 Rect 来定义 ROI

// 读取 logo
cv::Mat logo=  cv::imread("logo.png"); 
cv::Rect myRoi = cv::Rect(image.cols-log.cols,image.rows-logo.rows
							logo.cols, logo.rows)

定义了 ROI 之后,我们可以创建一个新的 cv::Mat 实例 imageROI,将 ROI 应用到这个新的 cv::Mat 实例上,可以其作为常规的 cv::Mat 实例进行操作。此时,ROI 是一个 cv::Mat 对象,它指向与其父图像相同的数据缓冲区,并具有指定 ROI 坐标的标头。插入 logo 的方式如下:

// 定义图像感兴趣区域位于图像右下角
cv::Mat imageROI(image, myRoi);
// 插入 logo
logo.copyTo(imageROI)

在以上代码中,image 是目标图像,logologo 图像,编译并执行代码可以得到以下结果:

1.2 定义 ROI

定义 ROI 的一种方法是如上一小节所示使用 cv::Rect 实例,它通过指定左上角的位置(构造函数的前两个参数)和矩形的大小(即宽度和高度,使用后两个参数指定)来描述一个矩形区域。在示例代码中,我们使用图像的大小和 logo 大小令 logo 覆盖图像右下角的位置。需要注意的是,ROI 应该始终完全处于父图像内。
ROI 也可以使用行和列范围来描述,范围是从开始索引到结束索引(不包括两者)的连续序列,在 OpenCV 中使用 cv::Range 结构表示范围。因此,可以使用两个范围定义 ROI,上一节示例中的 ROI 也可以等效地定义如下:

// 也可以使用 cv::Range 定义感兴趣区域
imageROI= image(cv::Range(image.rows-logo.rows,image.rows), 
                cv::Range(image.cols-logo.cols,image.cols));

在以上代码中,cv ::Matoperator() 函数会返回另一个 cv::Mat 实例,然后可以在后续调用中使用该实例。 ROI 的任何变换都会影响相应区域的原始图像,因为图像和 ROI 共享相同的图像数据。由于 ROI 的定义不需要数据的复制,因此无论 ROI 的大小如何,它都会在恒定的时间内执行。
如果要定义由图像的某些行组成的 ROI,可以使用以下代码:

cv::Mat imageROI = image.rowRange(start, end);

同样,对于由某些图像列组成的 ROI,可以使用以下代码:

cv::Mat imageROI = image.colRange(start, end);

OpenCV 方法和函数包括许多可选参数,当我们第一次使用某个函数时,应该花时间查看文档以了解有关此函数提供的可能参数的相关信息。例如,关于 ROI 的一种非常常见的可选参数是可以定义图像蒙版。

2. 使用图像掩码

有些 OpenCV 操作允许我们定义一个掩码,使用掩码可以限制给定函数或方法在图像中的应用区域(默认情况下,函数或方法会对所有图像像素进行操作)。掩码是一个 8 位图像,在希望应用操作的位置为非零值;在对应于掩码零值的像素位置,图像不受操作影响。例如,可以使用掩码调用 copyTo 方法,使用掩码仅复制显示 logo 的彩色部分:

// 定义图像的感兴趣区域
imageROI= image(cv::Rect(image.cols-logo.cols,image.rows-logo.rows,
							logo.cols,logo.rows));
// 也可以使用 cv::Range 定义感兴趣区域
// imageROI= image(cv::Range(image.rows-logo.rows,image.rows), 
//                 cv::Range(image.cols-logo.cols,image.cols));
// 将 logo 图像作为掩码
cv::Mat mask(logo);
// 通过仅在非零掩码的位置复制插入
logo.copyTo(imageROI, mask);

执行以上代码可以得到下图:


logo 的背景是黑色的(值为 0),因此,可以很容易将其用作蒙版。当然,我们也可以在应用程序中自定义掩码;大多数基于 OpenCV 像素的操作都允许我们使用掩码进行操作。

3. 完整代码示例

完整代码如下:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
int main() 
	// 定义新窗口
	cv::namedWindow("Image"); 
	// 读取图像
	cv::Mat image=  cv::imread("1.png"); 
	// 读取 logo
	cv::Mat logo=  cv::imread("logo.png"); 
	// 定义图像的感兴趣区域
	cv::Mat imageROI(image, 
					cv::Rect(image.cols-logo.cols, // ROI 坐标
							image.rows-logo.rows,
							logo.cols,logo.rows));// ROI 尺寸
	// 插入 logo
	logo.copyTo(imageROI);
	cv::imshow("Image", image); // 展示图像
	cv::waitKey(0);
	// 重新读取原始图像
	image=  cv::imread("1.png");
	// 定义图像的感兴趣区域
	imageROI= image(cv::Rect(image.cols-logo.cols,image.rows-logo.rows,
								logo.cols,logo.rows));
	// 也可以使用 cv::Range 定义感兴趣区域
	// imageROI= image(cv::Range(image.rows-logo.rows,image.rows), 
	//                 cv::Range(image.cols-logo.cols,image.cols));
	// 将 logo 图像作为掩码
	cv::Mat mask(logo);
	// 通过仅在非零掩码的位置复制插入
	logo.copyTo(imageROI, mask);
	cv::imshow("Image", image); // 展示图像
	cv::waitKey(0); 
    return 0;

小结

在图像处理领域,感兴趣区域 (region of interest, ROI) 可以简单理解为从图像中选择的一个图像区域,这个区域是图像分析算法所关注的重点。使用 ROI 限定需要进行进一步处理的目标区域,可以减少图像处理时间,并增加处理精度。本节介绍了两种定义 ROI 的方法,并介绍了掩码在图像处理中的作用及用法。

系列链接

OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构

以上是关于OpenCV实战——图像感兴趣区域的主要内容,如果未能解决你的问题,请参考以下文章

基于opencv的感兴趣区域ROI的操作

opencv图像及视频感兴趣区域设置

使用 OpenCV 将感兴趣区域从 RGB 视频转换为深度视频

用Python-OpenCV提取图像中的感兴趣区域以及图像的深拷贝和浅拷贝问题附示例代码

OpenCV-C++选择提取感兴趣区域(ROI区域)附用鼠标选取ROI区域的代码

ROI