1. 浅拷贝(Shallow Copy)
-
特点:
-
共享数据内存,新对象和原对象指向同一块内存数据。
-
修改任一对象的数据会影响另一个对象(因为内存共享)。
-
高效(仅复制矩阵头信息,不复制实际数据)。
-
-
实现方式:
-
直接赋值:
cv::Mat img1 = imread("image.jpg"); cv::Mat img2 = img1; // 浅拷贝
-
使用
clone()
的误用:
若对浅拷贝后的对象调用clone()
,仍需注意原对象是否被修改。
-
-
示例:
cv::Mat mat1 = (cv::Mat_<int>(2,2) << 1, 2, 3, 4); cv::Mat mat2 = mat1; // 浅拷贝 mat2.at<int>(0,0) = 99; // 修改 mat2 会影响 mat1 std::cout << mat1 << std::endl; // 输出 [99, 2; 3, 4]
2. 深拷贝(Deep Copy)
-
特点:
-
独立分配内存,新对象和原对象完全隔离。
-
修改任一对象不会影响另一个对象。
-
开销较大(需复制全部数据)。
-
-
实现方式:
-
clone()
方法:cv::Mat img1 = imread("image.jpg"); cv::Mat img2 = img1.clone(); // 深拷贝
-
copyTo()
方法:cv::Mat img2; img1.copyTo(img2); // 深拷贝
-
-
示例:
cv::Mat mat1 = (cv::Mat_<int>(2,2) << 1, 2, 3, 4); cv::Mat mat2 = mat1.clone(); // 深拷贝 mat2.at<int>(0,0) = 99; // 修改 mat2 不会影响 mat1 std::cout << mat1 << std::endl; // 输出 [1, 2; 3, 4]
3. 关键区别总结
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
内存共享 | 是(修改互相影响) | 否(数据独立) |
性能 | 高效(仅复制矩阵头) | 较慢(复制全部数据) |
实现方法 | = 赋值 | clone() 或 copyTo() |
适用场景 | 只读操作或临时引用 | 需独立修改数据时 |
4. 特殊情况与注意事项
(1) ROI(Region of Interest)的浅拷贝
-
通过
cv::Mat roi = img(cv::Rect(x,y,w,h))
创建的 ROI 是浅拷贝。 -
修改 ROI 会影响原图:
cv::Mat image = imread("image.jpg"); cv::Mat roi = image(cv::Rect(0,0,100,100)); // ROI 浅拷贝 roi.setTo(0); // 原图中对应区域也会变黑!
(2) copyTo()
的掩膜(Mask)功能
-
copyTo()
可结合掩膜实现选择性复制:cv::Mat dst; src.copyTo(dst, mask); // 仅复制 mask 非零区域
(3) 多通道数据的拷贝
-
深拷贝会复制所有通道数据,保持完整独立性:
cv::Mat color_img = imread("color.jpg"); cv::Mat deep_copy = color_img.clone(); // 所有通道独立
5. 如何选择拷贝方式?
-
用浅拷贝:
-
需要快速传递数据且不修改内容时(如函数参数传递只读数据)。
-
操作 ROI 时(避免内存重复分配)。
-
-
用深拷贝:
-
需独立修改数据时(如滤波、变换等操作)。
-
避免函数内修改影响外部数据时。
-
代码验证工具
可以通过以下代码检查两个矩阵是否共享内存:
bool isSameData(const cv::Mat& a, const cv::Mat& b) { return a.data == b.data; // 返回 true 表示浅拷贝 }
掌握深/浅拷贝的区别能有效避免 OpenCV 中的内存错误和逻辑问题!