前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >OpenCV copyTo、clone、“=”与拷贝构造函数的区别

OpenCV copyTo、clone、“=”与拷贝构造函数的区别

作者头像
chaibubble
发布于 2022-05-07 01:23:15
发布于 2022-05-07 01:23:15
1.6K00
代码可运行
举报
运行总次数:0
代码可运行

opencv中为矩阵复制提供了copyTo函数、clone函数、重载运算符和拷贝构造函数,用法非常简单:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	  Mat srcimage = imread("1.jpg");
	  Mat firstimage,secondimage,thirdimage;
	  
	  srcimage.copyTo(firstimage);
	  
	  secondimage = srcimage.clone();
	  
	  thirdimage = srcimage;
	  
	  Mat  fourthimage(srcimage);

但是在他们四者间存在着较大的区别,我们先写个简单的代码测试一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	  Mat srcimage = imread("2.jpg");
	  Mat firstimage,secondimage,thirdimage;

	  double t1 = (double)getTickCount();
	   srcimage.copyTo(firstimage);
	  t1 = (double)getTickCount() - t1;

	  double t2 = (double)getTickCount();
	  secondimage = srcimage.clone();
	  t2 = (double)getTickCount() - t2;

	  double t3 = (double)getTickCount();
	  thirdimage = srcimage;
	  t3 = (double)getTickCount() - t3;

	  double t4 = (double)getTickCount();
	  Mat  fourthimage(srcimage);
	  t4 = (double)getTickCount() - t4;
	
      printf("copyTo  execution time = %lfms\n", t1*1000. / getTickFrequency());
	  printf("clone  execution time = %lfms\n", t2*1000. / getTickFrequency());
	  printf(" =  execution time = %lfms\n", t3*1000. / getTickFrequency());
	  printf(" 构造函数  execution time = %lfms\n", t4*1000. / getTickFrequency());
	  getchar();

为了让效果明显,选择了一张很大的图片,这样图片的尺寸是3120*4160,实验结果如下:

我们可以看到,copyTo函数、clone函数占用时间差不多,但是“= ”运算符与拷贝构造函数用的时间却非常少,这是为什么呢?

造成这样的情况的原因是因为Mat的数据类型以及它的数据组成造成的。

Mat类

在opencv 2.x之前,OpenCV基于 C 语言接口而建。为了在内存(memory)中存放图像,当时采用名为 IplImage 的C语言结构体作为基本的图像容器。但是该方式有一个极大的弊端就是要手动内存管理,其依据是用户要为开辟和销毁内存负责。虽然对于小型的程序来说手动管理内存不是问题,但一旦代码开始变得越来越庞大,你需要越来越多地纠缠于这个问题,而不是着力解决你的开发目标。 之后,新的Mat类型代替了之前的IplImage,这次改变也带来了Opencv最强大的数据类型—Mat。**Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是不同的维数)的指针。**矩阵头的尺寸是常数值,但矩阵本身的尺寸会依图像的不同而不同,通常比矩阵头的尺寸大数个数量级。因此,当在程序中传递图像并创建拷贝时,大的开销是由矩阵造成的,而不是信息头。所以,除非有必要,否则我们不应该拷贝大的图像,因为这会降低程序速度。 为了搞定这个问题,OpenCV使用引用计数机制。其思路是让每个 Mat 对象有自己的信息头,但共享同一个矩阵。这通过让矩阵指针指向同一地址而实现。而拷贝构造函数则 只拷贝信息头和矩阵指针 ,而不拷贝矩阵。但某些时候你仍会想拷贝矩阵本身(不只是信息头和矩阵指针),这时可以使用函数 clone() 或者 copyTo() 。

从上面的话我们可以看到,copyTo函数、clone函数拷贝的不仅仅是信息头,还有矩阵本身,而“= ”运算符与拷贝构造函数仅仅拷贝了信息头,他们指向的其实是一个矩阵,也就是在上的程序中,我们改变srcimage ,thirdimage和fourthimage中的任何一个,另外两个也会跟着变化,我们再改一下代码测试一下(为了屏幕能放下,我们把图片换一下):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
      Mat srcimage = imread("1.jpg");
	  Mat firstimage,secondimage,thirdimage;
	  imshow("result1",srcimage);

	   double t1 = (double)getTickCount();
	   srcimage.copyTo(firstimage);
	   Point center = Point(55,55);  
	   int r = 10;  
	   circle(firstimage,center,r,Scalar(0,0,255),-1);  
	   t1 = (double)getTickCount() - t1;
	   imshow("result2",firstimage);

	  double t2 = (double)getTickCount();
	  secondimage = srcimage.clone();
	  t2 = (double)getTickCount() - t2;

	  double t3 = (double)getTickCount();
	  thirdimage = srcimage;
	  t3 = (double)getTickCount() - t3;

	  double t4 = (double)getTickCount();
	  Mat  fourthimage(srcimage);
	  t4 = (double)getTickCount() - t4;
	
	  Point a = Point (0,0);  
	  Point b = Point (thirdimage.cols,thirdimage.rows);  
	  line(thirdimage,a,b,Scalar(255,0,0));  

      printf("copyTo  execution time = %lfms\n", t1*1000. / getTickFrequency());
	  printf("clone  execution time = %lfms\n", t2*1000. / getTickFrequency());
	  printf(" =  execution time = %lfms\n", t3*1000. / getTickFrequency());
	  printf(" 构造函数  execution time = %lfms\n", t4*1000. / getTickFrequency());

	  imshow("result3",srcimage);
	  waitKey(0);
	  getchar();

可以看到,在原图刚刚读入的时候,显示了窗口result1,此时显示的就是读入的图片,firstimage是由srcimage通过copyTo的方法拷贝的,我们把firstimage画一个圆,然后用result2窗口显示,thirdimage是由srcimage通过“=”运算符拷贝的,我们将thirdimage画个线,并用result3再一次显示srcimage,然后我们可以看到,result3中srcimage已经变了,变成了和thirdimage一样的效果,说明之前的说法是正确的,他们共有了同一个矩阵。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-02-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++】类和对象之拷贝构造函数篇
在前面学习了6个默认成员函数中的构造函数和析构函数 【C++】构造函数和析构函数详解,接下来继续往后看拷贝构造函数。
zxctscl
2024/02/25
1380
【C++】类和对象之拷贝构造函数篇
【C++】拷贝构造函数与赋值的区别
将一个类拷贝到另一个类中,自然是需要对应的参数的,参数就是类,这里可以传递指针,引用更好,只是传值形参的话,会造成无限递归。
啊QQQQQ
2024/11/19
1150
【C++】拷贝构造函数与赋值的区别
C++奇迹之旅:深入思考拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
学习起来吧
2024/04/20
1220
C++奇迹之旅:深入思考拷贝构造函数
C++的拷贝构造函数
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
鲜于言悠
2024/05/24
690
C++的拷贝构造函数
C++之拷贝构造函数的浅copy和深copy
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空;换句话来说,就是我们在类中,不用我们程序猿自己写,编译就自动提供了无参构造函数(只是我们肉眼看不到!)
用户6280468
2022/03/21
4080
C++之拷贝构造函数的浅copy和深copy
【OpenCV教程】core 模块 - Mat - 基本图像容器
从真实世界中获取数字图像有很多方法,比如数码相机、扫描仪、CT或者磁共振成像。无论哪种方法,我们(人类)看到的是图像,而让数字设备来“看“的时候,都是在记录图像中的每一个点的数值。
小白学视觉
2019/07/15
8320
【OpenCV教程】core 模块 - Mat - 基本图像容器
【c++】类和对象(四)深入了解拷贝构造函数
拷贝构造函数是构造函数的一个重载形式,拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用,这个我们后面进行讲解
用户11029103
2024/04/02
1150
【c++】类和对象(四)深入了解拷贝构造函数
拷贝构造函数剖析【C++】
拷贝构造函数 知识点: 解释:拷贝构造函数是一种特殊的构造函数,它具有一般构造函数的所有特性,但其形参是本类对象的引用。 作用:使用一个已经存在的对象(由拷贝构造函数参数指定)去初始化同类的一个新对象。 定义格式:构造函数名 (&类名); 三种使用情况: 用一个对象去初始化同类的另一个对象; 函数的形参是类的对象,调用函数时形参与实参的结合; 函数返回值是类的对象,函数执行返回调用; 注意: 拷贝构造函数的参数采用引用方式。若把一个真实的类对象作为参数传到拷贝构造函数,引起无穷
攻城狮杰森
2022/07/09
5650
从零开始学C++之构造函数与析构函数(二):初始化列表(const和引用成员)、拷贝构造函数
文章主要讲述了在C++中,拷贝构造函数和赋值运算符的调用顺序,以及临时对象和右值引用的使用情况。具体来说,拷贝构造函数和赋值运算符的调用顺序是:首先调用拷贝构造函数,然后调用赋值运算符。如果一个对象被声明为右值引用,则其拷贝构造函数和赋值运算符会被调用两次。同时,如果一个对象被声明为右值引用,则其拷贝构造函数和赋值运算符会被调用两次。
s1mba
2017/12/28
1.4K0
从零开始学C++之构造函数与析构函数(二):初始化列表(const和引用成员)、拷贝构造函数
c++ 构造函数详解
上述程序崩溃。在使用t1复制t2时,进行的是浅拷贝,只是将成员的值进行赋值。此时,t1.p = t2.p, 即两个指针指向了堆里的同一个空间。这样,析构函数会被调用两次,这就是错误出现的原因。此问题的解决方法是“深拷贝”。
ruochen
2021/05/20
5790
c++ 构造函数详解
OpenCV 应用边缘检测与霍夫线变换实现旋转角度检测
使用opencv的图片旋转功能,把它旋转一个角度,旋转方法参考: http://blog.csdn.net/chaipp0607/article/details/63263347
chaibubble
2022/05/07
9730
OpenCV 应用边缘检测与霍夫线变换实现旋转角度检测
EasyC++71,拷贝构造函数
我们上一篇文章当中聊了面向对象中的一些坑,有的时候我们命名重载了构造函数和析构函数,但还是有问题。
TechFlow-承志
2022/08/26
2480
拷贝构造函数,深拷贝,浅拷贝
深浅拷贝的区别:     浅拷贝是将原始对象中的数据型字段拷贝到新对象中去,将引用型字段的“引用”复制到新对象中去,不把“引用的对象”复制进去,所以原始对象和新对象引用同一对象,新对象中的引用型字段发生变化会导致原始对象中的对应字段也发生变化。
zhangjiqun
2024/12/16
580
c++拷贝构造函数
拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
全栈程序员站长
2021/09/30
1.1K0
c++拷贝构造函数
拷贝构造函数 浅拷贝与深拷贝
上一期中我们讲述了构造函数的相关内容,谈到构造函数在形式上有几种分类,即带参数的、不带参数的以及参数列表初始化的,还有一种传引用的构造函数,称为拷贝构造函数,顾名思义,就是起到拷贝的功能,通过一个已经存在的类对象的相关数据初始化一个新的类对象。
叶茂林
2023/07/30
2770
OpenCV进行图像相似度对比的几种办法
PSNR(Peak Signal to Noise Ratio),一种全参考的图像质量评价指标。
流川疯
2019/01/18
6.7K0
OpenCV学习笔记:MAT解析
但手动地做还是可以的:大多数OpenCV函数仍会手动地为输出数据开辟空间。当传递一个已经存在的 Mat 对象时,开辟好的矩阵空间会被重用。也就是说,我们每次都使用大小正好的内存来完成任务。
bear_fish
2018/09/19
7920
OpenCV学习笔记:MAT解析
C++拷贝构造函数
假定有类T 则下列情况调用的函数是不一样的: T a = b; a=b; 第一种情况调用的是拷贝构造函数 第二种情况调用的是赋值运算符。 默认的拷贝构造函数执行的是浅拷贝,在对象涉及到动态分配的存储空间时,会出现问题。 在a中修改变量值后,b中的也发生改变。 出现内存泄漏(只new但是没有delete就会出现这样的问题) 一个地址被多次释放也会出错 要解决上面的问题,就要执行深拷贝 深拷贝使得每一个对象成员都有自己的内存空间。 要执行深拷贝,那么就要自己定义拷贝构造函数。 主要操作在于,对于动态分配的空间,
灯珑LoGin
2022/10/31
5950
C++之拷贝构造函数
拷贝构造函数最常见的是当我们创建的对象是用该类的另一个对象来进行初始化的,此时调用的构造函数就是拷贝构造函数。拷贝构造函数实质上就是构造函数的重载。当你不显式定义拷贝构造函数的时候,C++会给你提供一个默认拷贝构造函数,这和它提供默认构造函数是一样的。但是当你一旦显式定义了构造函数和拷贝构造函数,那么C++将不再提供默认构造函数和默认拷贝构造函数。
zy010101
2020/04/08
7350
基于opencv的gpu与cpu对比程序,代码来自opencv的文档中
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/gpu/gpu-basics-similarity/gpu-basics-similarity.html
流川疯
2019/01/18
1.6K0
相关推荐
【C++】类和对象之拷贝构造函数篇
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文