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

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

作者头像
chaibubble
发布2022-05-07 09:23:15
1K0
发布2022-05-07 09:23:15
举报

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

代码语言:javascript
复制
	  Mat srcimage = imread("1.jpg");
	  Mat firstimage,secondimage,thirdimage;
	  
	  srcimage.copyTo(firstimage);
	  
	  secondimage = srcimage.clone();
	  
	  thirdimage = srcimage;
	  
	  Mat  fourthimage(srcimage);

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

代码语言:javascript
复制
	  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
复制
      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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档