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拷貝是深拷貝。