从Mat_中提取数据失败 以及 Mat_与Mat的区别

关键字:CV_DbgAssert(CV_ELEM_SIZE1(traits::Depth<_Tp>::value) == elemSize1());

目录

问题与解决方案

关于从Mat中提取数据

关于Mat和Mat_


使用相机标定得到的外参数矩阵时出了点问题,记录一下

 

问题与解决方案

矩阵cMatrix,类型是Mat_<float>

直接cout<<cMatrix; 可以得到全部的数据

而要提取其中某一位的数据时却会报错,比如输出cMatrix(0,0)

 

 

换一种形式,如果是cMatrix.at<float>(0,0);

elemSize()是每个元素的大小,单位字节

elemSize1()是每个通道大小,单位字节

最后面多了个1,注意区分。如果存储的是单通道图像,两个函数的返回值是一样的;

如果是三通道图像,elemSize()返回值 = elemSize1()的返回值 x 3

 

但是如果是输出cMatrix.at<double>(0,0)就能得到数据

得到985.766

为什么会这样,我们看一下就行了

cout << sizeof(float) << endl;

cout << sizeof(double) << endl;

cout << sizeof(985.7658038785936) << endl;

输出的结果是:

4

8

8

也就是说尽管cMatrix声明的类型是Mat_<float>,但在里面存放的数据可不是float,而是double

解决方法:要么把cMatrix类型改成Mat_<double>,要么读取数据的时候使用cMatrix.at<double>(r,c)

 

为什么double只能保留到小数点三位小数呢?因为我使用的是cout,默认输出6位(丢人啊!基础不牢学艺不精啊!!!)

double a = 0.1234567;

cout<<a;//得到0.123456

更新

时隔许久,又一次使用Mat_<double>的时候,存入的数据是0.997056

RTMatrix(0,0) = 0.997056;

使用cout输出整个RTMatrix,其中对应(0,0)位置的值为0.9970560000000001,小数点后多出了很多位。但如果单独输出RTMatrix(0,0)则输出的是0.997056。

这是浮点数的精度问题,了解一下知道就行,具体可以看:

https://bbs.csdn.net/topics/391958585

https://blog.csdn.net/mydriverc2/article/details/84344059

关于从Mat中提取数据

下面摘自OpenCV文档的at()条目:

Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends on the image from which you are trying to retrieve the data. The table below gives a better insight in this:

请记住,在at操作符中使用的标识符不能随机选择(即at<>中的标识符是不能随便选择的)。这取决于您试图检索数据的图像(取决于你的Mat里是什么类型数据)。下面的表格更方便理解:

如果你的矩阵类型是CV_8U,使用Mat.at<uchar>(y,x);

如果你的矩阵类型是CV_8S,使用Mat.at<schar>(y,x);

如果你的矩阵类型是CV_16U,使用Mat.at<ushort>(y,x);

如果你的矩阵类型是CV_16S,使用Mat.at<short>(y,x);

如果你的矩阵类型是CV_32S,使用Mat.at<int>(y,x);

如果你的矩阵类型是CV_32F,使用Mat.at<float>(y,x);

如果你的矩阵类型是CV_64F,使用Mat.at<double>(y,x);

摘自opencv文档 

与我犯的错误结合起来思考,并不是你声明Mat_<xx>,每个通道里就会是xx类型的数据,而是要看你实际存放的数据是什么

 

关于Mat和Mat_

参考这篇博客:为什么要定义Mat_类https://blog.csdn.net/u011817406/article/details/79417052

Mat类中有很多模板方法,这些模板方法的参数类型要到运行期才能确定(根据上面的表,比如at就是模板方法,at<float>只有在运行时才会知道要返回float类型),这样有它的好处,使用起来非常灵活。

但是这种灵活却使简单的调用代码变得复杂,比如我要遍历一个Mat,每一次我都要写at<float>(y,x),写的越来越多,犯错的可能也越来越大,而且就算你哪一次写错了,把float写成了int,编译器也不会报错,因为这在语法上没有问题。

于是就有了Mat_类来简化代码

不使用Mat_类时

Mat cMatrix = Mat::eye(3, 3, CV_32F);

testM.at<float>(0, 0) = 2.5;

cout << testM.at<float>(0,0) << endl;//输出结果2.5

当使用了Mat_类之后我们就不需要每次at都写类型了

Mat_<float> cMatrix = Mat::eye(3, 3, CV_32F);

cMatrix(0, 0) = 2.5;

cout << cMatrix(0,0) << endl;//输出结果2.5

cout << cMatrix.at<float>(0,0) << endl;//输出结果2.5

可以直接使用cMatrix(0,0)来代替cMatrix.at<float>(0,0)

 


插一个在外网上看到的,找时间实验一下

What you always have to keep in mind is that you cannot just cast them from one into the other (or it probably won't do what you want), especially between differently sized types.So always make sure you use real conversion functions for converting between them, like cv::convert or cv::Mat::convertTo. Don't just try to access the elements of e.g. a cv::Mat of CV_8U type using e.g. cv::Mat::at<float> or cv::Mat_<float>.

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值