zoukankan      html  css  js  c++  java
  • opencv的基本数据结构(一)(转)

    从2001年以来,opencv的函数库一直是基于C接口构建的,因此在opencv1.0版本中,一般使用IplImage的C结构体在内存中存储图像,因此,我们在很多较经典的书籍或者开源项目中依然可见IplImage。但是用其存储图像的时候必须在退出前将图像内存手动release掉,即添加语句cvReleaseImage(&IplImage);,否则会造成内存泄漏。Mat类带来了自动的内存管理,同时它的操作也更加简单,比如用imshow显示图像,imread读取图像等等,跟Matlab有点接近。下面是将图像容器类mat转化成IplImage结构体的一种方法,最后别忘了cvReleaseImage(&pImg)。

    Mat frame,frame1;
    IplImage* pImg;
    frame=capture.read();
    frame1=frame.clone();
    pImg=cvCreateImage(cvSize(frame.cols,frame.rows),8,3);
    pImg->imageData=(char*)frame1.data;
    ...

    Mat是一个类,它由两个数据部分组成:矩阵头和一个指向存储所有像素值的矩阵的指针。其中矩阵头包含了矩阵的尺寸、存储方法、储存地址等信息,由此可以看出矩阵头所占的内存很小,通常是一个常数值,而具体存储所有像素值的矩阵则非常大。因此,在程序中传递图像并创建副本时,大的开销是由矩阵造成的,而不是信息头。其实上面给的mat转IplImage结构体就是一个例子,显然复制图像会增加算法的复杂度,降低程序的性能。形象点说,在一个班级里,矩阵头就相当于存储了班级里有多少人、男女比多少、平均身高等信息,而矩阵就储存了班级中所有同学的所有基本信息,每一个同学就相当于是一个像素矩阵中的一个元素,那么根据不同的存储方法就得到了不同的元素表示方法,显然矩阵要比矩阵头复杂得多。

    为了解决上述代码存在的问题。opencv使用了引用计数机制,其思路就是让每个Mat对象有自己的信息头,但是共享同一个矩阵。也就是让矩阵指针指向同一地址,共用一片内存来实现。复制图像的时候只是复制了矩阵头的信息和矩阵指针,并不是复制了整个矩阵。例如下面这段代码:

    Mat A,C;//仅创建信息头部分
    A= imread("1.jpg",CV_LOAD_IMAGE_COLOR);//这里为矩阵开辟内存
    Mat B(A);//使用拷贝构造函数
    C=A;

    这段代码中,A、B和C都是Mat类型,它们都指向同一个也是唯一一个数据矩阵。虽然它们的信息头不同,但通过任何一个对象所做的改变也会影响其它对象。而通过clone()或者copyTo()来复制一个图像,就包括了矩阵本身,也因此,改变复制对象的内容并不会改变源矩阵,例如frame1显然是复制frame,因此对frame1的操作并不改变frame。

    Mat的常见属性

    属性说明
    data uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
    dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
    rows 矩阵的行数
    cols 矩阵的列数
    size 矩阵的大小,size(cols,rows)
    channels() 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三个通道组成
    type() 表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)如:,CV_8UC3
    depth() 矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_8UC3,一个3通道的16位的有符号整数。那么,depth则是CV_8UC
    elemSize() 矩阵一个元素占用的字节数(不区分通道,即多个通道的总和)
    elemSize1() 矩阵一个元素每个通道占用的字节数(区分通道,单个通道的值)
    flags 一个int型数字,保存了许多有用的信息,flags说明

    创建Mat的方式:

     

    1、Mat M 
    创建一个矩阵头,没有数据。 
    2、Mat M(2,2,CV_8UC3,Scalar(0,0,1)); 
    2*2大小的矩阵,每个元素为3通道8位无符号整数,如下: 

    0 0 1 0 0 1 
    0 0 1 0 0 1 
    3、Mat M(2,2,CV_8UC1,Scalar(10)); 
    与上面类似: 
    10 10 
    10 10 
    4、Mat M(2,2,CV_8UC1,Scalar::all(0));
    5、以逗号分隔符初始化赋值:Mat M = (Mat_(3,3) << 1,2,3,4,5,6,7,8,9); 
    6、为已经存在的IplImage指针创建信息头,例如:

    IplImage* img=cvLoadImage("1.jpg",1);
    Mat mtx(img);//转换IplImage*为Mat

    7、利用create()函数

    Mat M;
    M.create(4,4,CV_8UC(2)); cout<<"M="M<<endl;

    但是这种方法不能为矩阵设初值,只是在改变尺寸时重新为矩阵数据开辟内存而已。

    8、Mat还有一些matlab式函数用来创建和初始化矩阵: 
    Mat E = Mat::eye(4,4,CV_64F); //单位矩阵
    Mat Z = Mat::zeros(4,4,CV_32F); //0矩阵
    Mat O = Mat::ones(4,4,CV_8UC1); //1矩阵
    9、为已经存在的对象创建新的信息头

    Mat E=Mat::eye(4,4,CV_64F);
    Mat Row=E.row(1).clone();
    cout<<Row<<endl;
  • 相关阅读:
    洛谷 P5677 [GZOI2017]配对统计(树状数组)
    洛谷 P2471 [SCOI2007]降雨量(RQM)
    洛谷 P4588 [TJOI2018]数学计算(线段树)
    洛谷 P1198 [JSOI2008]最大数(线段树)
    扫描线 && 洛谷 P5490 【模板】扫描线(线段树)
    洛谷 P6033 [NOIP2004 提高组] 合并果子 加强版(桶排序,队列)
    目标检测------>>>>R2CNN_Faster-RCNN_Tensorflow项目环境得配置
    python实现aes-256-gcm加密和解密-自已动手写个加解密软件(二)
    虚拟机改密码方案
    316python 基础之计算机基础、Python简介、变量、注释、基础数据类型初识、if、while、语句
  • 原文地址:https://www.cnblogs.com/cvtoEyes/p/8502602.html
Copyright © 2011-2022 走看看