4.2.5 Mat的源码分析
4.2.5.1 创建Mat
以创建如下三个类型的Mat为例:
Mat mat(512, 512, CV_8UC3);//3通道uchar类型
Mat mat(512, 512, CV_8UC4);//4通道uchar类型
Mat mat(512, 512, CV_32FC3);//3通道float类型
//首先,初始化成员变量
//dims:维度;rows:行数;cols:列数;data:数据指针;
//datastart:数据起始指针;dataend:数据结束指针;
Mat::Mat(int _rows, int _cols, int _type)
: flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0),
datastart(0), dataend(0), datalimit(0), allocator(0),
u(0), size(&rows), step(0)
{
create(_rows, _cols, _type);
}
void Mat::create(int _rows, int _cols, int _type)
{
_type &= TYPE_MASK;
int sz[] = {_rows, _cols};
create(2, sz, _type);
}
void Mat::create(int d, const int* _sizes, int _type)
{
//释放内存空间
release();
flags = (_type & CV_MAT_TYPE_MASK) | MAGIC_VAL;
//赋值成员MatSize size和MatStep step;
setSize(*this, d, _sizes, 0, true);
if( total() > 0 )
{
MatAllocator *a = allocator, *a0 = getDefaultAllocator();
if(!a)
a = a0;
//分配内存空间
u = a->allocate(dims, size, _type, 0, step.p,
ACCESS_RW, USAGE_DEFAULT);
}
//增加引用计数
addref();
//完成成员指针赋值
finalizeHdr(*this);
}
/** 每个通道项的大小,
0x28442211 = 0010 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */
#define CV_ELEM_SIZE1(type) ((0x28442211 >> CV_MAT_DEPTH(type)*4) & 15)
#define CV_ELEM_SIZE(type) (CV_MAT_CN(type)*CV_ELEM_SIZE1(type))
void setSize(Mat& m, int _dims, const int* _sz, const size_t* _steps,
bool autoSteps)
{
//_dims=2
m.dims = _dims;
//{ CV_8UC3: esz=3}、{ CV_8UC4: esz=4}、{ CV_32FC3: esz=12}
size_t esz = CV_ELEM_SIZE(m.flags);
//{ CV_8UC3: esz1=1}、{ CV_8UC4: esz1=1}、{ CV_32FC3: esz1=4}
size_t esz1 = CV_ELEM_SIZE1(m.flags);
size_t total = esz;
for( int i = _dims-1; i >= 0; i-- )
{
//_sz[] = {_rows, _cols}={512,512}
int s = _sz[i];
m.size.p[i] = s;
m.step.p[i] = total;
int64 total1 = (int64)total*s;
total = (size_t)total1;
}
//结果:
m.size.p[]={512,512};
CV_8UC3:m.step.p[]={1536,3}
CV_8UC4:m.step.p[]={2048,4}
CV_32FC3:m.step.p[]={6144,12}
}
UMatData* allocate(int dims, const int* sizes, int type,
void* data0, size_t* step, AccessFlag /*flags*/,
UMatUsageFlags /*usageFlags*/) const CV_OVERRIDE
{
//{ CV_8UC3: total =3}、{ CV_8UC4: total =4}、{ CV_32FC3: total =12}
// sizes[] = {_rows, _cols}={512,512}
size_t total = CV_ELEM_SIZE(type);
for( int i = dims-1; i >= 0; i-- )
{
step[i] = total;
total *= sizes[i];
}
//CV_8UC3:m.step.p[]={1536,3}、total= 786432=(3*512)*512
//CV_8UC4:m.step.p[]={2048,4}、total= 786432=(4*512)*512
//CV_32FC3:m.step.p[]={6144,12}、total= 3145728=(12*512)*512
//分配空间大小
uchar* data = data0 ? (uchar*)data0 : (uchar*)fastMalloc(total);
UMatData* u = new UMatData(this);
u->data = u->origdata = data;
u->size = total;
if(data0)
u->flags |= UMatData::USER_ALLOCATED;
return u;
}
//umatdata可以与矩阵数据一起分配,而不是作为单独的对象。因此,它没有构造函数或析构函数;应该使用init()显式初始化它。
struct CV_EXPORTS UMatData
{
enum MemoryFlag {
COPY_ON_MAP=1, HOST_COPY_OBSOLETE=2,
DEVICE_COPY_OBSOLETE=4, TEMP_UMAT=8,TEMP_COPIED_UMAT=24,
USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64,
ASYNC_CLEANUP=128
};
UMatData(const MatAllocator* allocator);
~UMatData();
// 提供对结构的原子访问
void lock();
void unlock();
bool hostCopyObsolete() const;
bool deviceCopyObsolete() const;
bool deviceMemMapped() const;
bool copyOnMap() const;
bool tempUMat() const;
bool tempCopiedUMat() const;
void markHostCopyObsolete(bool flag);
void markDeviceCopyObsolete(bool flag);
void markDeviceMemMapped(bool flag);
const MatAllocator* prevAllocator;
const MatAllocator* currAllocator;
int urefcount;
int refcount;
uchar* data;
uchar* origdata;
size_t size;
UMatData::MemoryFlag flags;
void* handle;
void* userdata;
int allocatorFlags_;
int mapcount;
UMatData* originalUMatData;
};
void Mat::addref()
{
if( u )
CV_XADD(&u->refcount, 1);
}
void finalizeHdr(Mat& m)
{
m.updateContinuityFlag();
int d = m.dims;
if( d > 2 )
m.rows = m.cols = -1;
if(m.u)
m.datastart = m.data = m.u->data;
if( m.data )
{
m.datalimit = m.datastart + m.size[0]*m.step[0];
if( m.size[0] > 0 )
{
m.dataend = m.ptr() + m.size[d-1]*m.step[d-1];
for( int i = 0; i < d-1; i++ )
m.dataend += (m.size[i] - 1)*m.step[i];
}
else
m.dataend = m.datalimit;
}
else
m.dataend = m.datalimit = 0;
}
4.2.5.2 拷贝Mat
同样以如下三个类型的Mat的拷贝为例:
Mat mat(512, 512, CV_8UC3);//3通道uchar类型
Mat mat(512, 512, CV_8UC4);//4通道uchar类型
Mat mat(512, 512, CV_32FC3);//3通道float类型
Mat dst;
mat.copyTo(dst);
void Mat::copyTo( OutputArray _dst ) const
{
if( dims <= 2 )
{
_dst.create( rows, cols, type() );
Mat dst = _dst.getMat();
if( rows > 0 && cols > 0 )
{
Mat src = *this;
//{ CV_8UC3: elemSize()=3、sz ={786432(512*512*3), 1}}
//{ CV_8UC4: elemSize()=4、sz ={1048576(512*512*4), 1}}
//{ CV_32FC3: elemSize()=12、sz ={ 3145728 (512*512*12), 1}}
Size sz = getContinuousSize2D(src, dst, (int)elemSize());
const uchar* sptr = src.data;
uchar* dptr = dst.data;
//{ CV_8UC3: sz.width =786432}
//{ CV_8UC4: sz.width =1048576}
//{ CV_32FC3: sz.width =3145728}
// sz.height=1
//{ CV_8UC3: src.step =1536=512*3}
//{ CV_8UC4: src.step =2048=512*4}
//{ CV_32FC3: src.step =6144=512*12}
for (; sz.height--; sptr += src.step, dptr += dst.step)
memcpy(dptr, sptr, sz.width);
}
return;
}
}
inline MatStep::operator size_t() const
{
CV_DbgAssert( p == buf );
//{ CV_8UC3: buf[0]= 1536=512*3}
//{ CV_8UC4: buf[0]=2048=512*4}
//{ CV_32FC3: buf[0]=6144=512*12}
return buf[0];
}
size_t Mat::elemSize() const
{
//CV_8UC3: step.p[]={1536,3}
//CV_8UC4: step.p[]={2048,4}
//CV_32FC3: step.p[]={6144,12}
//dims=2
size_t res = dims > 0 ? step.p[dims - 1] : 0;
return res;
}
Size getContinuousSize2D(Mat& m1, Mat& m2, int widthScale)
{
const Size sz1 = m1.size();
if (sz1 != m2.size()) // reshape all matrixes to the same size (#4159)
{
...
}
return getContinuousSize_(m1.flags & m2.flags,
m1.cols, m1.rows, widthScale);
}
static inline Size getContinuousSize_(int flags, int cols, int rows, int widthScale)
{
//cols=512、rows=512
//{ CV_8UC3: widthScale =3}
//{ CV_8UC4: widthScale =4}
//{ CV_32FC3: widthScale =12}
int64 sz = (int64)cols * rows * widthScale;
//has_int_overflow=false
//isContiguous=true
bool has_int_overflow = sz >= INT_MAX;
bool isContiguous = (flags & Mat::CONTINUOUS_FLAG) != 0;
return (isContiguous && !has_int_overflow)
? Size((int)sz, 1)
: Size(cols * widthScale, rows);
}