1、通过构造函数拷贝
// 函数声明
Mat(const Mat& m);
// 函数实现的源码
inline
Mat::Mat(const Mat& m)
: flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data),
datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator),
u(m.u), size(&rows), step(0)
{
if( u )
CV_XADD(&u->refcount, 1);
if( m.dims <= 2 )
{
step[0] = m.step[0]; step[1] = m.step[1];
}
else
{
dims = 0;
copySize(m);
}
}
有源码可以清晰的看出来,通过构造函数的拷贝,是没有拷贝数据的,因此是浅拷贝。
2、通过operator = 重载操作
// 函数声明
Mat& operator = (const Mat& m);
// 函数源码
inline
Mat& Mat::operator = (const Mat& m)
{
if( this != &m )
{
if( m.u )
CV_XADD(&m.u->refcount, 1);
release();
flags = m.flags;
if( dims <= 2 && m.dims <= 2 )
{
dims = m.dims;
rows = m.rows;
cols = m.cols;
step[0] = m.step[0];
step[1] = m.step[1];
}
else
copySize(m);
data = m.data;
datastart = m.datastart;
dataend = m.dataend;
datalimit = m.datalimit;
allocator = m.allocator;
u = m.u;
}
return *this;
}
矩阵赋值是O(1)操作。 这意味着不复制数据,但数据被共享,引用计数器(如果有的话)被递增。即Mat类型图像直接赋值也是浅拷贝。
3、通过Clone方法拷贝
// 函数声明
Mat clone() const CV_NODISCARD;
//源码
inline
Mat Mat::clone() const
{
Mat m;
copyTo(m);
return m;
}
// 调用的是copyTo这个函数,那么我们看一下这个函数的源码
//copyTo函数声明
void copyTo( OutputArray m ) const;
// 源码
/* dst = src */
void Mat::copyTo( OutputArray _dst ) const
{
CV_INSTRUMENT_REGION();
#ifdef HAVE_CUDA
if (_dst.isGpuMat())
{
_dst.getGpuMat().upload(*this);
return;
}
#endif
int dtype = _dst.type();
if( _dst.fixedType() && dtype != type() )
{
CV_Assert( channels() == CV_MAT_CN(dtype) );
convertTo( _dst, dtype );
return;
}
if( empty() )
{
_dst.release();
return;
}
if( _dst.isUMat() )
{
_dst.create( dims, size.p, type() );
UMat dst = _dst.getUMat();
CV_Assert(dst.u != NULL);
size_t i, sz[CV_MAX_DIM] = {0}, dstofs[CV_MAX_DIM], esz = elemSize();
CV_Assert(dims > 0 && dims < CV_MAX_DIM);
for( i = 0; i < (size_t)dims; i++ )
sz[i] = size.p[i];
sz[dims-1] *= esz;
dst.ndoffset(dstofs);
dstofs[dims-1] *= esz;
dst.u->currAllocator->upload(dst.u, data, dims, sz, dstofs, dst.step.p, step.p);
return;
}
// 真正数据拷贝的地方(二维或者一维)
if( dims <= 2 )
{
_dst.create( rows, cols, type() );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
if( rows > 0 && cols > 0 )
{
Mat src = *this;
Size sz = getContinuousSize2D(src, dst, (int)elemSize());
CV_CheckGE(sz.width, 0, "");
const uchar* sptr = src.data;
uchar* dptr = dst.data;
#if IPP_VERSION_X100 >= 201700
CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R_L, sptr, (int)src.step, dptr, (int)dst.step, ippiSizeL(sz.width, sz.height)) >= 0)
#endif
// 拷贝数据
for (; sz.height--; sptr += src.step, dptr += dst.step)
memcpy(dptr, sptr, sz.width);
}
return;
}
// 多维的拷贝
_dst.create( dims, size, type() );
Mat dst = _dst.getMat();
if( data == dst.data )
return;
if( total() != 0 )
{
const Mat* arrays[] = { this, &dst };
uchar* ptrs[2] = {};
NAryMatIterator it(arrays, ptrs, 2);
size_t sz = it.size*elemSize();
for( size_t i = 0; i < it.nplanes; i++, ++it )
memcpy(ptrs[1], ptrs[0], sz);
}
}
clone函数是通过Mat的方法copyTo拷贝的图像,因此拷贝图像的时候,可以使用copyTo进行拷贝操作。clone拷贝是深拷贝。