从Opencv的Mat结构学习深拷贝与浅拷贝(C++)

若A拷贝B,浅拷贝就是A拷贝了B的内存地址,两个内存地址是一样的。深拷贝就是A创建了新的内存空间,然后把B的值复制了一份。一般来说,=号是浅拷贝。

先说一下遇到的问题:

cv::Mat src = cv::imread("image/fact.jpg");
Mat srcm1, srcm2, srcmcopy;
srcm1 = src.clone();
src.copyTo(srcm2);
srcmcopy = src;
std::cout << "&src = "<< &src <<std::endl;
std::cout << "&srcm1 = "<< &srcm1 <<std::endl;
std::cout << "&srcm2 = "<< &srcm2 <<std::endl;
std::cout << "&srcmcopy = "<< &srcmcopy <<std::endl;

输出:
&src = 0000007F985AF490
&srcm1 = 0000007F985AF530
&srcm2 = 0000007F985AF5B0
&srcmcopy = 0000007F985AF630

设想中,应该 &src和&srcmcopy的地址一样,但是发现不一样。

查了资料发现忘了一件事,那就是Mat是个类,它的数据是由其中的一个指针成员变量来控制的。那么A拷贝B的时候,浅拷贝应该是A创建了一个新的对象空间,把B的值复制过来,指针成员变量也复制过来了,指向同一块地方。深拷贝则是指针成员变量指向了新的内存地址,只不过该地址的内存存的数据是一样的。

Mat类的基本结构示意图如下:

 因此,&src和&srcmcopy,这两个仅代表两个对象的地址。那么如何证明这两个对象的数据是同一个内存地址呢?

src.data == srcmcopy.data

用mat.data来表示。但是这时我又犯了第二个错误:

&(src.data) == &(srcmcopy.data)

我去比较了这两个data的地址,发现仍然不一样。结论:

&(src.data)&(srcmcopy.data)不相同的原因,是因为Mat类的实现机制。Mat对象的data成员变量指向的是存储图像数据的内存空间的起始地址,这个地址是通过Mat对象的构造函数从外部传入的,而不是在Mat对象内部分配的内存空间。

src对象和srcmcopy对象创建时,它们的data成员变量分别指向不同的内存空间。当你将src对象的值赋给srcmcopy对象时,srcmcopy对象的data成员变量被复制了src对象的data成员变量的值(即存储图像数据的内存空间的起始地址),因此两个Mat对象的data成员变量指向同一块内存空间。但是,&(src.data)&(srcmcopy.data)并不相同,因为它们分别存储的是两个不同的指针变量的地址。

src.datasrcmcopy.data存储的是图像数据所在内存空间的起始地址,也可以说是指向该内存空间的指针。因为在OpenCV中,Mat对象本身并不存储图像数据,而是存储一个指向图像数据所在内存空间的指针,这个指针就是data成员变量。

测试代码:

Mat src = imread("test.jpg");
Mat srcm1, srcm2, srcmcopy; //三种拷贝方法
srcm1 = src.clone();// 深拷贝
src.copyTo(srcm2);// 深拷贝
srcmcopy = src; // 浅拷贝

cout << "src.data = " << static_cast<void*>(src.data) << endl;
cout << "srcmcopy.data = " << static_cast<void*>(srcmcopy.data) << endl;

cout << "srcm1.data = " << static_cast<void*>(srcm1.data) << endl; 
cout << "srcm2.data = " << static_cast<void*>(srcm2.data) << endl;
cout << "&src.data = " << static_cast<void*>(&src.data) << endl;
cout << "&srcmcopy.data = " << static_cast<void*>(&srcmcopy.data) << endl;

输出:
src.data = 000001E661BBC080
srcmcopy.data = 000001E661BBC080

srcm1.data = 000001E6620EC080
srcm2.data = 000001E66261C080
&src.data = 0000004F55AFF650
&srcmcopy.data = 0000004F55AFF7F0

有个更直观的例子来证明深拷贝和浅拷贝。

// 这个3(C3代表通道数为3),最终导致3*8=24,一行24个。本来是1*8,只有8个。
Mat m3 = Mat::zeros(Size(400, 400), CV_8UC3); 
m3 = Scalar(0, 0, 255); //给三通道赋值

Mat m4,m5,m6;
m3.copyTo(m4);
m4 = Scalar(0, 255, 255);

m5 = m3.clone();
m5 = Scalar(0, 255, 255);


m6 = m3;
//m6 = Scalar(0, 255, 255);  由于浅拷贝,因为这行代码,也会改变m3的显示。

imshow("5",m5);
imshow("6",m6);
imshow("图像", m3);
imshow("图像4", m4);
waitkey(0);

 若:m6 = Scalar(0, 255, 255);,会发现原始图像m3也变了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值