一.写在前面
Mat 对象OpenCV2.0之后引进的图像数据结构,自动分配内存,不存在内存泄漏问题,是面向对象的数据结构。分了两个部分,头部与数据部分。
IpIImage 是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题。
官方文档写的很清楚:
写文档的还挺幽默的。
F12看一下都有哪些构造函数?
//////////////////////////////////////////// Mat //////////////////////////////////////////
inline
Mat::Mat()
: 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)
{}
inline
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);
}
inline
Mat::Mat(int _rows, int _cols, int _type, const Scalar& _s)
: 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);
*this = _s;
}
inline
Mat::Mat(Size _sz, 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( _sz.height, _sz.width, _type );
}
inline
Mat::Mat(Size _sz, int _type, const Scalar& _s)
: 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(_sz.height, _sz.width, _type);
*this = _s;
}
inline
Mat::Mat(int _dims, const int* _sz, 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(_dims, _sz, _type);
}
inline
Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s)
: 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(_dims, _sz, _type);
*this = _s;
}
inline
Mat::Mat(const std::vector<int>& _sz, 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(_sz, _type);
}
inline
Mat::Mat(const std::vector<int>& _sz, int _type, const Scalar& _s)
: 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(_sz, _type);
*this = _s;
}
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);
}
}
inline
Mat::Mat(int _rows, int _cols, int _type, void* _data, size_t _step)
: flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_rows), cols(_cols),
data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0),
allocator(0), u(0), size(&rows)
{
CV_Assert(total() == 0 || data != NULL);
size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type);
size_t minstep = cols * esz;
if( _step == AUTO_STEP )
{
_step = minstep;
}
else
{
CV_DbgAssert( _step >= minstep );
if (_step % esz1 != 0)
{
CV_Error(Error::BadStep, "Step must be a multiple of esz1");
}
}
step[0] = _step;
step[1] = esz;
datalimit = datastart + _step * rows;
dataend = datalimit - _step + minstep;
updateContinuityFlag();
}
inline
Mat::Mat(Size _sz, int _type, void* _data, size_t _step)
: flags(MAGIC_VAL + (_type & TYPE_MASK)), dims(2), rows(_sz.height), cols(_sz.width),
data((uchar*)_data), datastart((uchar*)_data), dataend(0), datalimit(0),
allocator(0), u(0), size(&rows)
{
CV_Assert(total() == 0 || data != NULL);
size_t esz = CV_ELEM_SIZE(_type), esz1 = CV_ELEM_SIZE1(_type);
size_t minstep = cols*esz;
if( _step == AUTO_STEP )
{
_step = minstep;
}
else
{
CV_DbgAssert( _step >= minstep );
if (_step % esz1 != 0)
{
CV_Error(Error::BadStep, "Step must be a multiple of esz1");
}
}
step[0] = _step;
step[1] = esz;
datalimit = datastart + _step*rows;
dataend = datalimit - _step + minstep;
updateContinuityFlag();
}
template<typename _Tp> inline
Mat::Mat(const std::vector<_Tp>& vec, bool copyData)
: flags(MAGIC_VAL | traits::Type<_Tp>::value | CV_MAT_CONT_FLAG), dims(2), rows((int)vec.size()),
cols(1), data(0), datastart(0), dataend(0), datalimit(0), allocator(0), u(0), size(&rows), step(0)
{
if(vec.empty())
return;
if( !copyData )
{
step[0] = step[1] = sizeof(_Tp);
datastart = data = (uchar*)&vec[0];
datalimit = dataend = datastart + rows * step[0];
}
else
Mat((int)vec.size(), 1, traits::Type<_Tp>::value, (uchar*)&vec[0]).copyTo(*this);
}
#ifdef CV_CXX11
template<typename _Tp, typename> inline
Mat::Mat(const std::initializer_list<_Tp> list)
: Mat()
{
CV_Assert(list.size() != 0);
Mat((int)list.size(), 1, traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this);
}
template<typename _Tp> inline
Mat::Mat(const std::initializer_list<int> sizes, const std::initializer_list<_Tp> list)
: Mat()
{
size_t size_total = 1;
for(auto s : sizes)
size_total *= s;
CV_Assert(list.size() != 0);
CV_Assert(size_total == list.size());
Mat((int)sizes.size(), (int*)sizes.begin(), traits::Type<_Tp>::value, (uchar*)list.begin()).copyTo(*this);
}
常用方法:
void copyTo(Mat mat)
void convertTo(Mat dst, int type)
Mat clone()
int channels()
int depth()
bool empty();
uchar* ptr(i=0)
部分复制:一般情况下只会复制Mat对象的头和指针部分,不会复制数据部分
Mat A= imread(imgFilePath);
Mat B(A) // 只复制
完全复制:如果想把Mat对象的头部和数据部分一起复制,可以通过如下两个API实现
Mat F = A.clone(); 或 Mat G; A.copyTo(G);
1.输出图像的内存是自动分配的
2.使用OpenCV的C++接口,不需要考虑内存分配问题
3.赋值操作和拷贝构造函数只会复制头部分
4.使用clone与copyTo两个函数实现数据完全复制
lcv::Mat::Mat构造函数
Mat M(2,2,CV_8UC3, Scalar(0,0,255))
其中前两个参数分别表示行(row)跟列(column)、第三个CV_8UC3中的8表示每个通道占8位、U表示无符号、C表示Char类型、3表示通道数目是3,第四个参数是向量表示初始化每个像素值是多少,向量长度对应通道数目一致
lcv::Mat::create实现
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127,127);
cout << “M = ” << endl << ” ” << M << endl << endl;
uchar* firstRow = M.ptr<uchar>(0);
printf(“%d”, *firstRow);