OpenCV(C++接口)学习笔记4-Mat::operator = 的陷阱(被黑过一次,此陷阱很隐秘)
2015-04-18 21:12
639 查看
当我们想要将一个Mat对象的数据复制给另一个Mat对象时,应该怎么做呢?
我们发现,OpenCV提供了重载运算符Mat::operator = ,那么,是否按照下列语句就可以轻松完成对象的赋值呢?
我们可以从reference manual 中看到:
Mat::operator =
Provides matrix assignment operators.
C++: Mat& Mat::operator=(const Mat& m)
Parameters
m – Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning
new data, the old data is de-referenced via Mat::release() .
这意味着,操作之后,b与a将共享同一片数据,不会发生数据的复制。
同样,我们可以从源代码中看出:
那么如果我们需要复制Mat对象,应该如何操作呢?
(1)Mat::copyTo函数
那么,这两个函数有什么区别呢?
我们查看源代码:
举个例子如下
B=A;那么B和A的数据地址是一样的
见下图:
A的数据地址 data=0x000000000038e5e0
B的数据地址 data=0x000000000038e5e0
A.at<double>(0,0)=5.0;
然后修改了A数据地址指向的内容,那么B的地址指向的内容也会发生改变。所以,就神不知鬼不觉的改变了B的内容,虽然我们只想改变A的内容,但结果是把B的内容也改了。
分析:Mat A的内存地址:0x000000000042eb10 Mat B的内存地址:0x000000000042eba0
Mat C的内存地址:0x000000000042ec30
所以,Mat C=A*B,会开辟一段新的内存存放A*B的值,
Mat D的地址:0x000000000042ec30
分析:Mat A 的地址 0x000000000023e6b0 Mat B 的地址 0x000000000023e740
Mat C的地址 0x000000000023e7d0
Mat D的地址 0x000000000023e7d0
D=C,则D,C的内存地址是一样的,想当于引用 Mat& C=D;对D,C任何一方的数据改变,都会同时改变D,C的数据
我们发现,OpenCV提供了重载运算符Mat::operator = ,那么,是否按照下列语句就可以轻松完成对象的赋值呢?
Mat a; Mat b = a;答案是否定的!
我们可以从reference manual 中看到:
Mat::operator =
Provides matrix assignment operators.
C++: Mat& Mat::operator=(const Mat& m)
Parameters
m – Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning
new data, the old data is de-referenced via Mat::release() .
这意味着,操作之后,b与a将共享同一片数据,不会发生数据的复制。
同样,我们可以从源代码中看出:
inline Mat& Mat::operator = (const Mat& m) { if( this != &m ) { if( m.refcount ) CV_XADD(m.refcount, 1); release(); flags = m.flags; if( dims <= 2 && m.dims <= 2 ) { dims = m.dims; rows = m.rows; cols = m.cols; step[0] = m.step[0]; step[1] = m.step[1]; } else copySize(m); data = m.data; datastart = m.datastart; dataend = m.dataend; datalimit = m.datalimit; refcount = m.refcount; allocator = m.allocator; } return *this; }该重载运算符只是将各个数据指针的地址进行了赋值,并没有复制数据的操作。
那么如果我们需要复制Mat对象,应该如何操作呢?
(1)Mat::copyTo函数
Mat a; Mat b; a.copyTo(b);(2)Mat::clone函数
Mat a; Mat b = a.clone();
那么,这两个函数有什么区别呢?
我们查看源代码:
inline Mat Mat::clone() const { Mat m; copyTo(m); return m; }从源代码可以发现,其实clone()函数就是copyTo()的另一个实现而已。
举个例子如下
Mat A=Mat::zeros(1,1,CV_64F); Mat B=A; A.at<double>(0,0)=5.0; cout<<B.at<double>(0,0)<<endl;
B=A;那么B和A的数据地址是一样的
见下图:
A的数据地址 data=0x000000000038e5e0
B的数据地址 data=0x000000000038e5e0
A.at<double>(0,0)=5.0;
然后修改了A数据地址指向的内容,那么B的地址指向的内容也会发生改变。所以,就神不知鬼不觉的改变了B的内容,虽然我们只想改变A的内容,但结果是把B的内容也改了。
<span style="color:#ff0000;"> </span> Mat A=Mat::ones(1,1,CV_64F); Mat B=Mat::ones(1,1,CV_64F); B.at<double>(0,0)=5.0; Mat C=A*B; Mat D=C; cout<<D.at<double>(0,0)<<endl; A.at<double>(0,0)=2.0; C=A*B; cout<<C.at<double>(0,0)<<endl;
分析:Mat A的内存地址:0x000000000042eb10 Mat B的内存地址:0x000000000042eba0
Mat C的内存地址:0x000000000042ec30
所以,Mat C=A*B,会开辟一段新的内存存放A*B的值,
Mat D的地址:0x000000000042ec30
Mat A=Mat::ones(1,1,CV_64F); Mat B=Mat::ones(1,1,CV_64F); B.at<double>(0,0)=5.0; Mat C=A*B; Mat D=C; cout<<D.at<double>(0,0)<<endl; A.at<double>(0,0)=2.0; D=A*B; cout<<C.at<double>(0,0)<<endl;
分析:Mat A 的地址 0x000000000023e6b0 Mat B 的地址 0x000000000023e740
Mat C的地址 0x000000000023e7d0
Mat D的地址 0x000000000023e7d0
D=C,则D,C的内存地址是一样的,想当于引用 Mat& C=D;对D,C任何一方的数据改变,都会同时改变D,C的数据
相关文章推荐
- OpenCV(C++接口)学习笔记4-Mat::operator = 的陷阱
- OpenCV(C++接口)学习笔记1-图像的读取、显示、保存
- OpenCV(C++接口)学习笔记2-像素级的图像操作
- OpenCV学习C++接口 Mat像素遍历详解
- OpenCV学习C++接口 Mat像素遍历详解
- OpenCV(C++接口)学习笔记1-图像读取、显示、保存
- OpenCV(C++接口)学习笔记3-求算法的运行时间
- OpenCv学习笔记--支持向量机SVM之C++的实现(1)
- opencv中C接口与C++接口的相互转换(Mat 和 CvMat,IplImage相互转化)
- OpenCV学习笔记 cv.Mat 与 .txt 文件数据的读写操作
- OpenCv学习笔记(四)--Mat基本图像容器Mat对象信息头,矩阵体的创建,深复制,浅复制详解
- 【基于C++和Python的Opencv3学习笔记之滑动条的使用】
- opencv学习笔记--深度解析Mat
- 【基于C++和Python的Opencv3学习笔记之基本图形的绘制】
- Opencv2 学习笔记<一>:cv::Mat数据访问方式
- OPENCV学习笔记1-1_Mat 创建
- OpenCV学习C++接口:图像锐化
- OpenCV学习C++接口:图像锐化
- OpenCv学习笔记(二)—cv::Mat学习
- 我的OpenCV学习笔记(25):c++版本的高斯混合模型的源代码完全注释