OpenCV实战(3)——图像感兴趣区域
0. 前言
在实际应用场景下,图像处理函数有时只需要应用于图像的部分区域。
OpenCV
中使用了一种优雅而简单的机制来定义图像中的子区域并将可以将其视为常规图像进行操作。本节中,我们将学习如何定义图像内的感兴趣区域 (
region of interest
,
ROI
)。
1. 感兴趣区域
为了说明如何定义感兴趣区域 (
region of interest
,
ROI
),我们将一个尺寸较小图像复制到一个更大的图像上。例如,我们要将以下
OpenCV logo
插入到测试图像中:
为了完成该目标,需要定义可以应用复制操作的
ROI
,
ROI
的位置将决定
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
是目标图像,
logo
是
logo
图像,编译并执行代码可以得到以下结果:
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 ::Mat
的
operator()
函数会返回另一个
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>intmain(){// 定义新窗口
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);return0;}
小结
在图像处理领域,感兴趣区域 (
region of interest
,
ROI
) 可以简单理解为从图像中选择的一个图像区域,这个区域是图像分析算法所关注的重点。使用
ROI
限定需要进行进一步处理的目标区域,可以减少图像处理时间,并增加处理精度。本节介绍了两种定义
ROI
的方法,并介绍了掩码在图像处理中的作用及用法。
系列链接
OpenCV实战(1)——OpenCV与图像处理基础
OpenCV实战(2)——OpenCV核心数据结构
版权归原作者 盼小辉丶 所有, 如有侵权,请联系我们删除。