c++版opencv中Mat作为行参时值错误的问题

  • 问题

void asignMat(Mat& m){
	vector<int> v;
	for(int i = 0; i < 10; i++){
		v.push_back(i);
	}
	
	m = Mat(v); //使用vector给Mat赋值
}

int main(){
	Mat testM;
	asignMat(testM);
	cout<<testM<<endl;
	
	return 0;
}

上面这段代码的预期输出是[0,1,2,3,4,5,6,7,8,9],可是运行后得到的结果确实[0,0,2,3,4,5,6,7,8,9]

如果你不是使用0,1,2,3,4,5,6,7,8,9这样的值去赋值v,那么还有可能出现一些很大的随机数

  • 分析

我们加一句打印在子函数asignMat的最后,如下:

void asignMat(Mat& m){
	vector<int> v;
	for(int i = 0; i < 10; i++){
		v.push_back(i);
	}
	
	m = Mat(v); 
	cout<<m<<endl; //添加打印
}

运行结果是[0,1,2,3,4,5,6,7,8,9],与预期相符,那么奇怪的事情就来了:为什么一个变量,退出子函数时结果还是对的,到了主函数中立马就错了?

于是我想到做实验,将子函数的操作搬到主函数中去

int main(){
	Mat testM;
	
	vector<int> v;
	for(int i = 0; i < 10; i++){
		v.push_back(i);
	}
	
	testM = Mat(v); 
	cout<<testM<<endl;
	
	return 0;
}

得到的运行结果是正确的[0,1,2,3,4,5,6,7,8,9],问题进一步可以定义为:为什么子函数中操作Mat出错,但没有子函数就正确了呢?

当然不要去怀疑电脑出问题了,或者opencv又出bug了。其实Mat的操作很多都是浅拷贝,也就是底层实现只是赋了地址给Mat,那么我们就可以理解,问题的本质是这样的:

当子函数asignMat使用局部变量v给Mat赋值(浅拷贝),当跳出子函数时,局部变量v被释放,故Mat内将变成随机的数据(现实中看到就只有一个数被修改,猜测原因为局部变量v的地址被释放,但里面的值并没有立即被重写。不一样的数可能来自某些内部机制的修改,并不明确)

由于Mat浅拷贝这个特性,在使用Mat的时候要格外小心。

  • 问题解决

void asignMat(Mat& m){
	vector<int> v;
	for(int i = 0; i < 10; i++){
		v.push_back(i);
	}
	
	m = Mat(v).clone(); //使用深拷贝
}

int main(){
	Mat testM;
	asignMat(testM);
	cout<<testM<<endl;
	
	return 0;
}

由浅拷贝变成深拷贝,使用clone()函数,可以得到正确的结果


附带一些给Mat赋值的操作

  1. 如果是小矩阵,那么可以手动输入
Mat testM = (Mat_<int>(1,3) << 1,2,3);
  1. 使用数组或者vector构造中间变量再赋值
vector<int> v;
Mat testM;
for(int i = 0; i < 10; i++){
	v.push_back(i);
}

testM = Mat(v);
int v[10];
Mat testM;
for(int i = 0; i < 10; i++){
	v[i] = i;
}

testM = Mat(1, 10, CV_32S, v);

注意:在选择CV_32S时,需要理解它的含义:CV_(位数)+(数据类型)+(通道数)
其中
位数:根据元素的类型

  • char为1字节(8位)
  • short为2字节(16位)
  • long和int为4字节(32位)
  • float为4字节(32位)
  • double为8字节(64位)

数据类型:U为无符号整型,S为有符号整型,F为浮点型
通道数:数据维度,如RGB图片为3,灰度图为1

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值