从OpenCV2的Mat说起
tkorays(http://blog.csdn.net/tkorays)
我回忆所见远比我当前耳目所得更有价值。
在使用OpenCV的过程中,有一个类是你必然每次都要用到的,它就是Mat。可以这么说OpenCV里最重要的一个类就是Mat了。“工欲善其事,必先利其器”,Mat就是我们的器。
这里我们不会去深入探讨Mat的源码,而是从使用的角度来探讨下Mat这个类,继而展开,讨论下与Mat相关的一些数据结构以及操作等。
Mat基本
1. Mat的内存管理问题
Mat的内存分配与释放都是由OpenCV自动管理的,因此我们可以不用太关心内存分配与释放问题。对于使用过的Mat可以让程序自己去释放,如果你觉得不安心,也可以手动释放。
OpenCV里多个Mat的头可能指向同一个数据块,我们不用担心释放了对其他数据是否造成影响,OpenCV引入了计数机制,最终,数据是由最后一个使用数据的Mat来释放。因此,每释放一个Mat,计数器减一,直到为0则释放数据块。
2. 你真的会复制Mat数据?
当你复制一个Mat的时候需要想想,你是只复制了Mat头、而指针还是指向原来的数据块,或者不仅复制了头、数据块也被复制到一个新的存储空间?注意下,如果多个Mat指向同一个数据块时,你对某一个Mat操作是会影响其他Mat的,一不小心你就干了件蠢事了。
因此,在必要的时候你应该使用copyTo或者clone将数据块复制过去。
3. Mat的数据指针
你知道怎么获取Mat里面的原始数据吗?答案很简单,这个数据指针就是*data,它是一个uchar类型的指针。因此你完全可以对它进行“暴力”地操作。比如对一个已经分配内存的Mat我可以重写它的数据memcpy(M.data,(void*)data,size_of_the_data);
4. Mat的数据获取
方法一:at法。使用Mat::at<Type>(inti,int j),对于3通道可以这样:Mat::at<Vec3b>(int i,int j)[int k];其他通道类似。
方法二:使用数据指针*data。
方法三:使用迭代器。注意迭代器扫描速度比较慢,但是不容易出错。
5. 输出数据自动内存分配
在一些语句中,我们没必要对Mat的内存进行事先分配,实际上,在一些输出的语句中,OpenCV能根据已知条件自动为我们分配内存。如cvtColor的输出,VideoCapture的>>输出。如果我们已经指定了大小,则这些函数操作不会再重新分配。部分带有函数不支持自动内存分配,如cv::mixChannels, cv::RNG::fill。
Mat拓展
1. 与OpenCV 1.x里面的C数据结构的转换
图1 Mat操作符
从上图我们可以看到Mat支持的一些运算符,其中一些可以帮助我们将Mat转化为IplImage、CvMat、CvMatND这些低版本的数据结构。使用方法:
如:
IplImage* img =&M.operator IplImage();
CvMat* img =&M.operator CvMat();
2. 智能指针类Ptr
任务繁重时候,你可能会对C版本的内存管理吐槽一番。不支持自动内存管理在很多时候不是很方便,或者说它阻碍了我们的开发进度,我们需要对每个分配的内存进行检查,是否释放了。
而OpenCV提供了Ptr这样一个类模板,可以包装其他没有考虑到内存管理的类,实现内存自动管理。因此上面的代码可以写成:
Ptr<IplImage>img = &M.operator IplImage();
这里Ptr用来对老版本的数据结构进行指针操作,更安全有效,可以防止内存的不正常使用。所以是不是觉得处理那些没有考虑内存自动管理的类时就方便多了?
Boost库和现在的c++11标准里都有这样的类(shared_ptr)。
3. Mat_类
Mat_是继承自Mat的一个模板类,它继承了Mat的大部分功能,而它还实现了()操作符。使用M(i,j)即可获得元素,代码比Mat的at更加简洁。
4. Matx类
Matx是一个比较小的矩阵类,它的类型大小在编译时就是可以确定的。因此它的灵活性也就降低了。Matx也可以像Mat_一样通过M(i,j)这样的方式获取元素。
by tkorays(http://blog.csdn.net/tkorays)