OpenCV基础图像容器-Mat用法总结

一、前言

OpenCV的API库在最开始时一直是基于C接口构建的,使用C语言结构体指针IplImage*存储图像,需要繁琐的内存管理,如果创建了IplImage指针,使用完成后不release掉的话就会造成内存泄漏,使用起来极为不便!辛运的是,OpenCV2.0版本中引入了新的C++接口,通过类进行自动内存管理,并定义了一种新的数据类型Mat来存储图像矩阵。

二、概述

Mat是一个容器类,支持C++中一般容器对元素的操作,同时作为一种矩阵数据存储类,由两个数据部分构成:1、矩阵头:包含矩阵尺寸、存储方式、存储地址等信息;2、指向存储所有像素值的矩阵的指针。矩阵头的尺寸是常数,但尺寸本身的尺寸会因图像的不同而不同。
通常创建和传递矩阵时会造成很大开销,在进行较大矩阵复制时,OpenCV引入了计数机制,让每个Mat对象都有自己的信息头,但共享同一个矩阵,者通过让矩阵指针指向同一地址实现,所以拷贝构造函数只复制信息头和矩阵指针,而不复制矩阵,避免了大量的空间时间开销。
然而某些时候你还是会复制矩阵本身,(不只是信息头和矩阵指针),这时可以使用函数clone()和copyTo()函数。

构造Mat矩阵时:

  • 使用赋值运算符和拷贝构造函数只复制信息头,改变任何一个矩阵都会影响到其他矩阵。
  • 使用函数Clone()和copyTo()来复制一幅图像的矩阵,新创建的矩阵和原矩阵相互独立,改变其中一个矩阵不会影响到其他矩阵。

OpenCV中Mat容器类的定义有很多行,下面列出来一些关键属性如下所示:

class CV_EXPORTS Mat
{
public:
//********Mat类的构造函数********
Mat();   //图像容器类Mat的默认构造函数
//......其他构造函数定义并初始化,在此省略 【下面讨论】
~Mat();  //Mat的析构函数
...
//********图像矩阵的属性********
int flags;  //图像矩阵是否连续
int dims;   //矩阵的维数,取值应该大于或等于2
int rows,cols;  //矩阵的行列数
uchar* data;    //指向数据的指针
int* refcount;  //指向引用计数的指针,如果数据由用户分配则为NULL
//......

//......其他的很多函数和数据结构
};

三、Mat对象创建

1、使用Mat( )构造函数

Mat::Mat()      //无参数构造Mat方法

Mat::Mat(int rows, int cols, int type)   //【1】创建行数为rows,列数为cols,类型为type的图像矩阵

Mat::Mat(Size size, int type)  //【2】创建大小为size,类型为type的图像

Mat::Mat(int rows, int cols, int type, const Scalar& s)  //【3】创建行数为rows,列数为cols,类型为type的图像,并将所有元素初始化为s

Mat::Mat(Size size, int type, const Scalar& s)  //【4】创建大小为size,类型为type,初始元素为s

Mat::Mat(const Mat& m)  //【5】将m赋值给新创建的对象:数据共享

Mat::Mat(int rows, int cols, int type, void* data, size_t step = AUTO_STEP)  
//【6】创建行数为rows,列数为cols,类型为type的图像,构造函数不创建图像数据所需内存而是直接使用data所指内存图像的步长由step指定

Mat::Mat(Size size, int type, void* data, size_t step = AUTO_STEP) 
//【7】创建大小为size,类型为type的图像,构造函数不创建图像数据所需内存而是直接使用data所指内存图像的步长由step指定

Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)  
//【8】创建新的图像为m数据的一部分,其具体的范围由rowRange和colRange指定:数据共享

Mat::Mat(const Mat& m, const Rect& roi)  //【9】创建新的矩阵为m的一部分,具体的范围由roi指定:数据共享

在构造函数中很多地方都用到Type,Type可以是CV_8UC1、CV_16UC3、CV_64FC4等等,这些写法都用具体的定义,如下:
C V _   [ 位 数 ] [ 带 符 号 与 否 ] [ 数 据 类 型 ] C [ 通 道 数 ] CV\_~[位数][带符号与否][数据类型]C[通道数] CV_ [][][]C[]

比如,CV_8UC3表示8位3通道unsigned整型。

Mat M(5, 5, CV_8UC3);     //创建5行5列,8位3通道无符号整型的图像矩阵

数据共享:指不同Mat图像矩阵矩阵指针指向同一个矩阵地址,当改变一个矩阵时其他矩阵也会跟着改变。

2、使用Create( )函数创建Mat类

Mat M1.create(4,4,CV_8UC1); //创建一个尺寸为4×4,type为8UC1的图像矩阵

【注意】使用create( )函数无法初始化Mat类,只是在改变尺寸时重新为矩阵数据开辟内存而已。也就是说,如果create()函数指定的参数与图像之前的尺寸相同,则不进行实质的内存申请操作,如果尺寸不同,则减少原始数据内存的索引并重新申请内存。

3、使用MATLAB风格创建Mat类
OpenCV也可以使用Matlab的风格创建函数如:zeros(),ones()和eyes(),在使用这些函数时只需要指定图像的大小和类型。

Mat M1=Mat::zeros(3,3,CV_8UC1);  //创建尺寸为3×3,类型为8UC1的全0矩阵

Mat M2=Mat::ones(4,4,CV_32FC3);  //创建尺寸为4×4,类型为8UC3的全1矩阵

Mat M3=Mat::eye(5,5,CV_64FC1);  //创建尺寸为5×5,类型为64FC1的单位矩阵

4、使用子类Mat_创建Mat矩阵
OpenCV定义了一个Mat的模板子类为Mat_,使用逗号分隔式初始化小型矩阵,如:

Mat M=(Mat_<double>(3,3) << 0,-1,0,
						   -1,5,-1,
							0,-1,0);

5、使用clone( )或copyTo方法创建Mat矩阵
copyTo( )是深拷贝,但是否申请新的内存空间,取决于dst矩阵头中的大小信息是否与src一至,若一致则只深拷贝并不申请新的空间,否则先申请空间后再进行拷贝.
clone( )是完全的深拷贝,在内存中申请新的空间

Mat A  = Mat::ones(4,5,CV_32F);

Mat B = A.clone()    //clone 是完全的深拷贝,在内存中申请新的空间,与A独立

Mat C;
A.copyTo(C) //此处的C矩阵大小与A大小不一致,则申请新的内存空间,并完成拷贝,等同于clone()

Mat D = A.col(1);
A.col(0).copyTo(D) //此处D矩阵大小与A不一致,因此不会申请空间,而是直接进行拷贝,相当于把A的第1列赋值给D

关于clone()、copyTo()、和”=”(重赋值运算符重载)三种实现矩阵赋值的方式的比较
       ~~~~~~       ”=”是使用重载的方式将矩阵值赋值给新的矩阵,而这种方式下,被赋值的矩阵和赋值矩阵之间共享数据,改变任何一个矩阵的值会影响到另外一个矩阵。而clone()和copyTo()两种方法在赋值后,两个矩阵的存储空间是独立的,不存在共享数据的情况。

6、IplImage指针转Mat矩阵
IPLImage指针创建信息头可实现IPLImage*到Mat矩阵转换,代码如下:

IplImage* img=cvLoadImage("1.jpg",1);
Mat mtx(img);  //IplImage* -> Mat

四、C++实现Mat图像矩阵创建

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

int main()
{
    Mat M1(3,3,CV_8UC3,Scalar(0, 0, 255));
    cout << "M1 = " << endl << " "  << M1 << endl;

    Mat M2(Size(3, 2), CV_8UC3, Scalar(1,2,3));
    cout << "M2 = " << endl << " " << M2 << endl;

    Mat M3(M2);
    cout << "M3 = " << endl << " " << M3 << endl;

    Mat M4(M2, Range(1,2), Range(1,2));
    cout << "M4 = " << endl << " " << M4 << endl;

    waitKey(0);
    return 0;
}

参考书籍、Blog:
【1】《OpenCV3编程入门》
【2】opencv学习(一)之Mat类

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值