OpenCV中图像的浅拷贝与深拷贝 = copy clone区别

本文深入探讨OpenCV中图像的深拷贝与浅拷贝,介绍三种拷贝方法:重载运算符=、cvCopy和cvCloneImage,以及如何通过flip函数验证拷贝效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面介绍三种OpenCV复制图像的方法:

方法1、重载运算符=

使用重载运算符“=”进行的拷贝是一种浅拷贝,虽然它们有不同的矩阵头,但是二者共享相同的内存空间,二者内容相互关联,任何一个变量变化的同时另一个变量也随之改变。

/*OpenCV v1版本*/
IplImage img_origin = cvLoadImage(".\\picture.jpg", CV_LOAD_IMAGE_COLOR); // 读取一张彩色图 
IplImage img_copy = img_origin;  // 直接赋值,浅拷贝

/*OpenCV v2之后版本*/
Mat img_origin = imread(picture, IMREAD_COLOR);  // 读取一张彩色图 
Mat img_copy = img_origin; 

方法2、cvCopy

cvCopy的原型是:
void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask CV_DEFAULT(NULL) );
OpenCV官网关于cvCopy函数的介绍
在使用这个函数之前,必须先用cvCreateImage()一类的函数开辟一段内存,然后传递给dst。cvCopy会把src中的数据复制到dst的内存中。这是一种深拷贝,真正地拷贝了一个新的图像矩阵,此时二者相互之间没有影响,但是如果设置了ROI、COI,copy只会复制ROI、COI区域的内容。

/*OpenCV v1版本*/
IplImage img_origin = cvLoadImage(".\\picture.jpg", CV_LOAD_IMAGE_COLOR); // 读取一张彩色图 
IplImage img_copy = cvCreateImage(Size(img_origin->width, img_origin ->height), img_origin ->depth, img_origin ->nChannels); 
// 开辟一个新的内存空间,图像的大小、深度与颜色通道与原图保持一致
cvCopy(img_origin, img_copy);  // 拷贝图像

/*OpenCV v2之后版本*/
Mat img_origin = imread(picture, IMREAD_COLOR);  // 读取一张彩色图 
Mat img_copy;
img_origin.copyTo(img_copy);  //在拷贝数据前会有一步img_copy.create(this->size , this->type)  

方法3、cvCloneImage

cvCloneImage的原型是:
IplImage* cvCloneImage( const IplImage* image );
OpenCV官网关于cvCloneImage函数的介绍
在使用函数之前,不用开辟内存。该函数会自己开一段内存,然后复制好图像里面的数据,然后返回这段内存中的数据。clone是把所有的都复制过来,不论你是否设置了ROI、COI等影响,clone都会原封不动的克隆过来。用clone复制后,如果源图像在内存中消失,复制的图像也变了,而用copy复制,源图像消失后,复制的图像不变。

IplImage img_origin = cvLoadImage(<span class="hljs-string">".\\picture.jpg"</span>, CV_LOAD_IMAGE_COLOR); <span class="hljs-comment">// 读取一张彩色图 </span>
IplImage img_copy = cvCloneImage(img_origin);

这里先学习OpenCV中的一个函数

void flip(InputArray src, OutputArray dst, int flipCode)
//图像变换函数,第三个参数为1时,表示水平反转,0表示垂直反转,负数表示既有水平又有垂直反转。

为介绍OpenCV中的浅拷贝,我们还是从cv::Mat说起吧。cv::Mat类是用于保存图像以及其他矩阵数据的数据结构。当cv::Mat实例化后,分配内存;当对象离开作用域后,分配的内存自动释放。cv::Mat实现了引用计数以及浅拷贝。引用计数的作用是只有当所有引用内存数据的对象都被析构后,内存才会释放。浅拷贝是指当图像之间进行赋值时,图像数据并未发生复制,而是两个对象都指向同一块内存块。
通过OpenCV中的flip函数验证浅拷贝,具体做法:

先声明一个Mat对象img加载本地图片,并显示;
然后声明一个Mat对象img1,将img浅拷贝到img1;
在img1上垂直翻转图片,注意是在原地进行操作,不创建新的图像;
显示img,注意窗口名称应与之前不相同,观察img的图像内容是否改变。

程序如下:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat img1=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    Mat img2=img1;                //拷贝方式为浅拷贝
    imshow("First",img1);
    if(!img1.data)
    {
        cout<<"error! The image is not built!"<<endl;
        return -1;
    }
    flip(img2,img2,1);            //注意应在原地进行镜像变换
    imshow("Second",img1);
    waitKey();
    return 0;
}

运行如下,很显然,我们修改img1的内容img发生了改变。
这里写图片描述

深拷贝是指新创建的图像拥有原始图像的崭新拷贝,即拷贝图像和原始图像在内存中存放在不同地方。OpenCV中可以通过下面两种方式实现深拷贝。

1) img.copyTo(img1)
2) img1=img.clone()

通过OpenCV中的flip函数验证深拷贝,具体做法与之前相似,将img深拷贝到img1即可。
程序如下:

#include<iostream>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main()
{
    Mat img1=imread("test.jpg");  //将任意一张名为test.jpg的图片放置于工程文件夹test中
    Mat img2=img1.clone();        //拷贝方式是深拷贝
    imshow("First",img1);
    if(!img1.data)
    {
        cout<<"error! The image is not built!"<<endl;
        return -1;
    }
    flip(img2,img2,1);
    imshow("Second",img1);
    waitKey();
    return 0;
}

运行如下,深拷贝之后,任他img1七十二变,img自然不变。
这里写图片描述

了解了图像的深浅拷贝,我们使用时就要注意,尤其涉及到类时,我们应该避免返回类中的图像成员。

<think>我们有一个明确的需求:使用OpenCVcopyTo函数来裁剪图像的ROI区域,并进行深拷贝到新的Mat对象。根据引用[2]和引用[3]:-`copyTo`函数可以将一个Mat对象的内容复制到另一个Mat对象中,并且可以配合掩码(mask)使用。-引用[3]展示了使用`copyTo`进行深拷贝的基本用法:将整个图像复制到另一个Mat对象中。 但是,我们的目标是裁剪ROI区域(即图像的一部分)并进行深拷贝。我们可以结合ROI区域和`copyTo`函数来实现。步骤:1.首先,我们需要定义ROI区域(一个矩形区域)。 2.然后,我们可以使用`copyTo`函数将ROI区域的内容复制到一个新的Mat对象中。 注意:直接使用ROI(例如`Mat roi= src(rect);`)得到的是原图的浅拷贝(引用相同的内存)。如果我们想要深拷贝ROI区域,那么我们需要创建一个新的Mat对象并将ROI区域的内容复制过去。 我们可以这样做: ```cpp//假设我们有一个源图像srccv::Matsrc =cv::imread("image.jpg");//定义ROI矩形区域cv::Rect rect(x, y, width, height);//创建一个新的Mat对象来存储ROI的深拷贝cv::Mat roiCopy;//方法1:使用copyTo,将src的ROI部分复制到roiCopy//注意:这里我们获取src的ROI区域,然后对这个ROI区域调用copyTosrc(rect).copyTo(roiCopy);//方法2:也可以先创建一个目标Mat,然后使用copyTo并配合掩码(如果需要的话),但这里我们不需要掩码,所以可以省略。//但是注意,如果使用掩码,可以只复制掩码非零的部分。这里我们不需要掩码,所以直接复制整个ROI区域。//现在roiCopy就是ROI区域的深拷贝```解释: -`src(rect)`创建了一个指向源图像ROI区域的Mat头(浅拷贝),然后我们在这个临时Mat对象上调用`copyTo`函数,将其内容复制到`roiCopy`中。由于`copyTo`函数会进行深拷贝,因此`roiCopy`拥有独立的数据。引用[2]提到`copyTo`可以配合掩码使用,但在这个场景中,我们不需要掩码,所以直接使用`copyTo`即可。另外,引用[4]也提到了ROI区域的选择复制,但使用的方法可能是直接赋值(浅拷贝)或使用`copyTo`(深拷贝)。我们这里采用`copyTo`实现深拷贝。 因此,回答用户的问题:使用`copyTo`函数裁剪ROI区域并进行深拷贝,可以通过以下代码实现:```cppcv::MatroiCopy= src(roiRect).clone();//另一种方法是使用clone(),它也是深拷贝```或者```cppcv::MatroiCopy; src(roiRect).copyTo(roiCopy);``` 两种方法(`clone()`和`copyTo`)都可以实现深拷贝。但是,用户特别指定要使用`copyTo`函数,所以我们推荐第二种方法。 总结:使用`copyTo`函数裁剪ROI区域并深拷贝的步骤是: 1.定义ROI矩形(cv::Rect)。 2.使用源图像的ROI区域(通过`src(rect)`获取)调用`copyTo`函数,目标是一个新的Mat对象。这样,我们就得到了ROI区域的深拷贝。 最后,生成相关问题:1.使用`copyTo`函数时如何配合掩码进行复制? 2. OpenCV深拷贝浅拷贝区别是什么? 3.除了`copyTo`,还有哪些方法可以实现ROI区域的深拷贝?4.在OpenCV中,如何判断一个Mat对象是深拷贝还是浅拷贝?</think>### OpenCV copyTo函数裁剪ROI区域并深拷贝的方法 要使用`copyTo`函数裁剪图像的ROI区域并进行深拷贝到新Mat对象,请按照以下步骤操作: #### 1. **定义ROI区域** 使用`cv::Rect`指定感兴趣区域: ```cpp cv::Rect roiRect(x, y, width, height); // 定义矩形区域 ``` #### 2. **创建目标Mat对象** 初始化一个空Mat对象存储结果: ```cpp cv::Mat roiCopy; ``` #### 3. **执行深拷贝操作** 使用`copyTo`函数复制ROI区域: ```cpp // 方法1:直接复制ROI区域 src(roiRect).copyTo(roiCopy); // 方法2:配合掩码(可选) cv::Mat mask = cv::Mat::ones(roiRect.size(), CV_8UC1); // 创建全1掩码 src(roiRect).copyTo(roiCopy, mask); ``` #### 4. **验证深拷贝** 可通过修改原始图像验证独立性: ```cpp cv::circle(src, cv::Point(x, y), 10, cv::Scalar(0,0,255), -1); // 修改原图 cv::imshow("Original", src); // 原图被修改 cv::imshow("ROI Copy", roiCopy); // ROI拷贝不受影响 ``` #### 关键说明: 1. **深拷贝原理** `src(roiRect)`创建ROI的**浅拷贝**(引用原数据),而`copyTo()`执行**深拷贝**,将像素数据复制到独立内存中[^3][^4]。 2. **clone()的对比** `roiCopy = src(roiRect).clone()`等效于`copyTo()`,但`copyTo()`额外支持掩码操作[^2]。 3. **掩码的作用** 当添加掩码参数时,只复制掩码非零区域的像素(示例中全1掩码等效于无掩码)[^2]。 > **应用场景**:这种方法适用于需要独立处理ROI区域的场景,如图像局部增强、目标检测预处理等[^4]。 --- ### 相关问题 1. OpenCV浅拷贝深拷贝有何性能差异? 2. 如何验证一个Mat对象是否真正实现了深拷贝? 3. 使用`copyTo`时掩码参数有哪些高级应用技巧? 4. 除了`copyTo`,还有哪些方法可以实现ROI的深拷贝? 5. 在处理大图像时,如何优化ROI拷贝的内存效率? [^1]: OpenCV Mat深拷贝浅拷贝区别 [^2]: copyTo函数的掩码功能说明 [^3]: copyTo基础使用案例 [^4]: ROI区域处理的应用场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zqx951102

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值