opencv Mat选取图像局部区域

简述

Mat 类提供了多种方便的方法来选择图像的局部区域。使用这些方法时需要注意,这些方法并不进行内存的复制操作。如果将局部区域赋值给新的 Mat 对象,新对象与原始对象共用相同的数据区域,不新申请内存,因此这些方法的执行速度都比较快。

1 单行或单列选择

提取矩阵的一行或者一列可以使用函数 row()或 col()。函数的声明如下:

Mat Mat::row(int i) const
Mat Mat::col(int j) const

参数 i 和 j 分别是行标和列标。例如取出 A 矩阵的第 i 行可以使用如下代码:

Mat line = A.row(i);

例如取出 A 矩阵的第 i 行,将这一行的所有元素都乘以 2,然后赋值给第 j 行,可以这样写:

A.row(j) = A.row(i)*2;

2 用 Range 选择多行或多列

Range 是 OpenCV 中新增的类,该类有两个关键变量 start 和 end。Range 对象可以用来表示矩阵的多个连续的行或者多个连续的列。其表示的范围为从 start 到 end,包含 start,但不包含 end。Range 类的定义如下:

class Range
{
  public:
    ...
    int start, end;
};

Range 类还提供了一个静态方法 all(),这个方法的作用如同 Matlab 中的 ,“:”表示所有的行或者所有的列。

// 创建一个单位阵
Mat A = Mat::eye(10, 10, CV_32S);
// 提取第 1 到 3 列(不包括 3)
Mat B = A(Range::all(), Range(1, 3));
// 提取 B 的第 5 至 9 行(不包括 9)
// 其实等价于 C = A(Range(5, 9), Range(1, 3))
Mat C = B(Range(5, 9), Range::all());

3 提取感兴趣区域

从图像中提取感兴趣区域(Region of interest)有两种方法,一种是使用构造函数,如下例所示:

//创建宽度为 320,高度为 240 的 3 通道图像
Mat img(Size(320,240),CV_8UC3);
//roi 是表示 img 中 Rect(10,10,100,100)区域的对象
Mat roi(img, Rect(10,10,100,100));

除了使用构造函数,还可以使用括号运算符,如下:

Mat roi2 = img(Rect(10,10,100,100));

当然也可以使用 Range 对象来定义感兴趣区域,如下:

//使用括号运算符
Mat roi3 = img(Range(10,100),Range(10,100));
//使用构造函数
Mat roi4(img, Range(10,100),Range(10,100));

4 取对角线元素

矩阵的对角线元素可以使用 Mat 类的 diag()函数获取,该函数的定义如下:

Mat Mat::diag(int d) const

参数 d=0 时,表示取主对角线;当参数 d>0 是,表示取主对角线下方的次对角线, d=1 时,如表示取主对角线下方,且紧贴主多角线的元素;当参数 d<0 时,表示取主对角线下方的次对角线。当参数 d>0 时,表示取主对角线上方的次对角线。如同 row()和 col()函数,diag()函数也不进行内存复制操作,其复杂度也是 O(1)。

5 测试

void fun_Range()
{
	uchar maxtrix[5][6] = {{ 1, 0, 1, 1, 2, 0 }, { 0, 1, 0, 0, 1, 2 }, { 2, 1, 2, 2, 1, 2 }, { 2, 1, 2, 2, 1, 0 }, { 0, 0, 1, 1, 0, 2 }};
	//等价于 Mat srcMat(Size(6,5), CV_8UC1, maxtrix);
	//Size(int cols, int rows) 与 opencv中创建Mat的行、列顺序相反
	Mat srcMat(5, 6, CV_8UC1, maxtrix); 
 	
//	Mat srcMat = (Mat_<int>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); //另之中初始化Mat矩阵的方式

	//打印矩阵
	int width = srcMat.cols;
	int height = srcMat.rows;
	printf("原矩阵:\n");
	for (int i = 0; i < height; ++i)
	{
		for (int j = 0; j < width; ++j)
		{
			int index = i * width + j;
			printf("%d ", (int)srcMat.data[index]);
		}
		printf("\n");
	}
    //必须要克隆
	//Mat line = srcMat(Range(0,2), Range::all()).clone();
//	Mat line = srcMat.col(2).clone();
	Mat line = srcMat.diag(1).clone();

	//打印矩阵
	int width2 = line.cols;
	int height2 = line.rows;
	printf("目标矩阵:\n");
	for (int m = 0; m < height2; ++m)
	{
		for (int n = 0; n < width2; ++n)
		{
			int index = m * width2 + n;
			printf("%d ", (int)line.data[index]);
		}
		printf("\n");
	}
	return;
}

获取Mat的局部矩阵后,需要克隆给新的Mat,因为如果不clone()的话,局部矩阵指向的还是原矩阵的指针,会导致对局部矩阵数据处理时,出现紊乱现象。

另外:测试打印矩阵也可直接使用cout打印。

Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "Total matrix:" << endl;
cout << C << endl;

Mat row = C.rowRange(1,3).clone();
cout << "Row range:" << endl;
cout << row << endl;

Mat col = C.colRange(1,3).clone();
cout << "Col range:" << endl;
cout << col <<endl;

 

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值