OpenCv学习笔记(一)--OpenCv中Mat类源码的详细解读(1)

来源:互联网 发布:tensorflow源代码语言 编辑:程序博客网 时间:2024/04/30 10:29

OpenCv学习笔记(一)OpenCv中Mat类源码的详细解读(一)


(一)Mat类的引述


1–自2010年以来,OpenCv的函数库一直是基于C接口构件的,因此,在最初的几个OpenCv版本中,一直使用IplImage的C语言结构体在内存中存储图像。直到今天,这仍旧出现在很多的旧版书籍中,比如经典的《Learning OpenCv》
2–对于OpenCv1.x的时代,基于C语言接口而创建的图像存储格式IplImage*,如果在退出之前忘了release掉指向图像的指针变量的话,那么就会造成–内存泄露,当然这在一些小程序中的话,手动管理内存也不算什么问题,但是一旦程序规模比较大的时候,那么就有可能造成严重的内存泄露问题,这导致我们在设计程序的时候,过多的去考虑和业务逻辑没有关系的一些问题,使用起来很不方便。
3–幸运的是,随着OpenCv中,C++接口的出现,带来了全新的概念—-类的概念,这使得我们有了另一个选择,自动的内存管理。
4–也就是说OpenCv在2.0版本及其以后的版本中引入了一个新的C++接口,利用自动内存管理的方法给出了解决问题的方法。使用这种方法,我们在图像处理或者计算机视觉程序开发的过程中,不需要再在内存管理的问题上纠结,反而可以将更多的时间和精力投注到业务逻辑或者问题的处理之上。
5–C++接口唯一的不足是,当前许多的嵌入式开发系统只支持C语言(这个问题大家可以思考一下),如果是在android系统上的话,是可以利用C++语言去开发图像处理库的.so库
6–OpenCv2.x版本的时代,使用Mat类作为主要数据结构的时代,图像处理变得更加简单,并且更加像实验性语言Matlab一样,比如大家所熟悉的imread,imwrite,imshow等函数



(二)关于Mat类,首先,我们需要知道两点:

 1--我们不必在为其手动开辟空间 2--不必在不需要时,再去手动的释放空间

(三)Mat类的结构:

 1--总之,Mat是C++中的一个类,其定义形式如---class Mat{};这个类里面包括最基本的C++类中的基    本的结构,比如:    1--构造函数    2--析构函数    3--成员方法    4--数据成员 2--class Mat是一个类,它由两个部分组成:    1--矩阵头--包括:       1--矩阵尺寸       2--存储方法       3--存储地址等    2--一个指向存储图像所有像素的矩阵的指针--(矩阵---数组)---根据所选存储方法的不同,矩阵可以       是不同的维数 3--矩阵头---的尺寸是常数值,但是,矩阵本身的尺寸会根据图像的不同而不同,通常比矩阵头的尺寸大好    几个数量级。因此,当在程序中传递图像并创建副本的时候,大的开销是由矩阵造成的,而不是信息头 4--OpenCv是一个图像处理库,包含了大量的图像处理函数,为了解决问题,通常我们要使用多个库函数,因    此,在函数中传递图像是常有的事,同时,我们也不要忘了,我们现在正在讨论时的计算量很大的图像处    理算法,因此,不到万不得已,不应该进行大图像的复制,因为这会降低程序的---运行速度 5--为了解决此类问题,OpenCv使用了---引用计数机制。其思路是:让每个Mat对象都有自己的信息头,但是    共享一个矩阵。这通过让矩阵指针指向同一个地址实现。而复制构造函数则只复制信息头和矩阵指针,而    不复制矩阵本身 来看看下面这段代码:
        //【1】这里Mat仅仅创建了信息头,而没有给矩阵本身开辟内存空间        Mat A,C;        //【2】在这里.为存储图像像素信息的矩阵本身开辟类存空间,并将矩阵空间的首地址赋给Mat对象A        A=imread("1.jpg",CV_LOAD_IMAGE_COLOR);        //【3】使用复制构造函数,给Mat对象B初始化,其实只是将对象A的信息头和矩阵指针复制给了B        //【4】复制构造函数进行的是----浅复制        Mat B(A);        //【5】复制运算符------------浅复制        C=A;
 6--以上代码中,所有的Mat对象最终都指向同一个,也是唯一一个数据矩阵.虽然他们的信息头不同,但通过    任何一个对象所做的改变也会影响其他对象.实际上,不同的对象只是访问相同数据的不同途径而已。 7--在这里,还要提及一个非常棒的功能;我们可以创建只引用部分数据的信息头。比如想要创建一个感兴趣    区域(ROI),只需要创建包含边界信息的信息头:
        //【1】使用矩形界定边界        Mat D(A,Rect(10,10,100,100));        //【2】使用行和列来界定边界        Mat E=A(Range:all(),Range(1,3));
 8--那么,现在有一个问题是--如果一个矩阵体属于多个Mat对象,那么当我们不在需要它时,谁来负责清理    呢?    1--简答的回答是:最后一个使用它的对象.通过引用计数机制来实现。我们无论什么时候复制一个Mat       对象的信息头,都会增加矩阵的引用次数。反之,当一个头被释放后,这个技术就会减少一;当计数值       为零,矩阵就会被清理。 9--但是,有些时候,你仍会想复制矩阵本身(不只是信息头和矩阵指针),这时,你就可以使用clone()或者    copyTo()函数
        //【1】使用clone()函数,对Mat对象进行---深复制---不仅复制它的信息头和矩阵指针,还有复制              //它的矩阵体        //【2】Mat对象A深复制给F        Mat F=A.clone();        //【3】定义一个Mat对象G        //【4】通过copyTo函数进行深复制        A.copyTo(G);
 10--现在改变Mat对象F和G,就不会影响Mat信息头

(四)本节知识点的小结

1--OpenCv函数中输出图像的内存分配是自动完成的(如果不是特别指定的话)2--使用OpenCv的C++接口时,不需要考虑内存释放的问题3--赋值运算符和赋值构造函数--都属于--浅复制---只复制了信息头和矩阵指针,没有赋值矩阵体4--使用clone()和copyTo()函数--属于--深复制---是用来复制--一副图像的矩阵

0 0
原创粉丝点击