Mat作为OpenCV中使用率最高的类,它的数据包括两个部分:矩阵头和指向像素矩阵的指针。
- 矩阵头:描述像素矩阵,主要包括矩阵的尺寸、存储方式、存储地址等,矩阵头的大小固定。
- 矩阵指针:矩阵指针所指对象代表了图像本身,其尺寸会根据图像的不同而不同。像素矩阵一般比矩阵头大几个数量级,因此,拷贝图像会产生很大的计算量。
深拷贝和浅拷贝的区别:cv::Mat的深拷贝和浅拷贝的却别就在于是否重新拷贝一份数据指针指向的数据?浅拷贝只是重新拷贝Mat的矩阵头,并不拷贝数据指针指向的数据,也就是说新生成的和之前的共用一块相同的数据空间,但是深拷贝则是连同数据一起重新拷贝一份。
1. cv::Mat
void Func(cv::Mat Input){
Input = cv::Mat::ones(4, 4, CV_32F); //修改了Input,但是并不修改函数外的Mat
//...
}
这种方法只是将Mat的矩阵头拷贝了一份,此时在函数Func()中可以更改Input的矩阵头中的参数,但是并不会影响到函数外的Mat,因为这种方法对矩阵的头进行的是值传递。
2. const cv::Mat
void Func(const cv::Mat Input){
Input = cv::Mat::ones(4, 4, CV_32F); //错误,不能修改Input
//...
}
函数依然是按值传递,由于const的限制input的矩阵头中的数据不能修改,也就是不能在函数里面修改矩阵的大小等参数,因为这些参数保存在矩阵头中。
3. cv::Mat&
void Func(cv::Mat& Input){
Input = cv::Mat::ones(4, 4, CV_32F); //修改了Mat的矩阵头,函数外的Mat也受到影响
//...
}
在使用引用的时候,修改矩阵Input将会影响到函数外的Mat,也就是矩阵头中包含的任何参数修改都会影响到外部的Mat。
4. const cv::Mat&
void Func(const cv::Mat& Input){
Input = cv::Mat::ones(4, 4, CV_32F); //修改了Mat的矩阵头,函数外的Mat也受到影响
//...
}
在使用const引用的时候,将不能修改矩阵头参数。
总结
总之,不管是以何种的方式传入Mat,值得注意的是都是传入的Mat矩阵头中的参数。
如果你在函数中修改了矩阵头的参数,比方说存储地址,那么在函数内修改Mat中的值(比如图像值),则不会影响函数外部的Mat。
如果你没有修改矩阵头的参数,那么在函数中通过矩阵指针修改Mat的值,那么函数外部也会发生变化。
例如:
#include <iostream>
#include <opencv2/core.hpp>
void func(cv::Mat temp){
temp.at<u_char>(1,1) = 5;
}
int main() {
cv::Mat A = cv::Mat::ones(3, 3, CV_8U);
func(A);
std::cout << A << std::endl;
return 0;
}
输出:
[ 1, 1, 1;
1, 5, 1;
1, 1, 1]
解释:temp是值传递,重新拷贝外部Mat的矩阵头构造了temp,但是矩阵头中的参数与外部一模一样,当修改矩阵的数值时,外部的矩阵就也跟着发生变化了。当在函数内部操作temp使得矩阵头发生变化,就有可能引起数据地址发生变化,那么再修改矩阵值时可能就不会导致外部矩阵值发生变化了。