Opencv中文网

感兴趣区域(Region of Interest, ROI)

在图像处理的过程中,我们往往只对图像中的某个区域感兴趣,那么可以定义一个矩形Rect或指定感兴趣的行列范围(Range),这个就是感兴趣区域(简称ROI)。

一、矩形ROI

定义矩形ROI需要用到OpenCV中的Rect类型。Rect表示一个矩形,最基础的4个参数分别是(x,y,width,height),其中,x、y表示矩形的左上角坐标,width和height分别表示矩形的宽和高。因为矩形是一个二维平面,除了有宽和高,必须得注明矩形在某个图像中的坐标位置。另外,x、y、width、height都是int类型。

假如,图像的宽和高分别是500像素和300像素,要在这张图中定义一个感兴趣区域,那么,ROI的宽和高就不能超过500像素和300像素。当然,如果ROI的宽和高都等于0,那也没有意义。

Rect其实是Rect2i的别称。Rect2i是Rect_<int>类型,类似的还有Rect_<float>(别名为Rect2f),Rect_<double>(别名是Rect2d),由此可见,Rect_是一个模板类,类似C#中的泛型类。

观察下面代码

#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
    Mat girl = imread("images/girl.jpg", IMREAD_COLOR);//3通道(CV_8UC3)
    if (girl.empty()) {
        return 0;
    }
    imshow("girl", girl);//显示原图像
    Rect rect(0, 0, girl.cols/2, girl.rows/2);
    Mat photo = girl(rect);
    //转为伪灰度
    photo.forEach<Vec3b>([](Vec3b& pixel, const int* /*position*/) {
        uchar gray = 0.299 * pixel[2] + 0.587 * pixel[1] + 0.114 * pixel[0];
        pixel[0] = pixel[1] = pixel[2] = gray;
     });
    imshow("photo", photo);//显示ROI图像
    imwrite("photo.jpg", photo);
    imshow("girl2", girl);//显示原图像
    imwrite("girl.jpg", girl);
    waitKey(0);//等待按键
    return 0;
}

在代码中,首先加载一张3通道8位图并显示,其原图的效果如下所示

原图

Rect rect(0, 0, girl.cols/2, girl.rows/2);表示定义一个矩形,矩形左上角坐标为(0,0),矩形宽和高均为图像宽高的一半,那么这个矩形的面积等于图像的1/4。

Mat photo = girl(rect);表示以这个矩形从原图中获取一个ROI图像,注意,此时,photo和girl的图像数据共享内存,只不过,photo所能遍历的图像数据为原图的1/4。

接着将photo里面的图像数据转为伪灰度,最后分别显示photo和girl。最终效果如下两张图所示。

ROI图像
被影响到的原图

结论,虽然我们只是将ROI图像的彩色3通道转换为伪灰度,但是,原图左上角的1/4也同时被修改了。如果希望在修改ROI图像时,不影响原图。那么可以采用深拷贝技术,即:

Mat photo = girl(rect).clone();

二、感兴趣行列ROI

另一种定义ROI区域的方式是使用OpenCV提供Range,它有两个关键参数,分别是start和end,表示开始和结束的索引。下面是它的使用方式,同样可以达到上面的效果。

Mat photo = girl(Range(0, girl.rows/2), Range(0, girl.cols/2));

在这句代码中,一共定义了2个Range,前者表示从0行到图像行数的1/2,后者表示从0列到图像列数的1/2。

——重庆教主 2025年5月14日

copyright @重庆教主 WPF中文网 联系站长:(QQ)23611316 (微信)movieclip (QQ群).NET小白课堂:864486030 | 本文由WPF中文网原创发布,谢绝转载 渝ICP备2023009518号-1