Opencv中的Mat类介绍
文章目录
1. Mat类简介
Mat类是Opencv中储存图像非常常见的一种数据结构。Mat类可以看做是存放矩阵的容器,他包含了两部分,分别是用来存放图片信息的信息头,和一个指向图片储存矩阵的指针。信息头往往占用空间比较小,而且各个图片之间的信息头是完全独立的。而图片储存矩阵往往占用较大的空间,并且可以多个图片的矩阵指针指向同一个内存空间。
2. Mat类的拷贝
从Mat类的数据储存结构来看,Mat类图像储存是通过矩阵指针实现的。这样的话,在做图片复制的时候,就必须要考虑的一个问题是:我们需要复制的是矩阵指针的地址,还是需要重新创建一个内存空间,把图片存储矩阵重新拷贝一份。所以Mat类的拷贝具有浅拷贝和完全拷贝两种。
2.1 使用拷贝构造函数进行拷贝
Mat类中具有自己的拷贝构造函数,其函数原型如下
Mat(const Mat& m);
使用拷贝构造函数进行图片的拷贝有两种写法,并且这两种写法是等价的。
Mat m = imread("1.jpg);
Mat m1 = m;
Mat m2(m);
使用拷贝构造函数进行图片拷贝是一种浅拷贝,其结果是,m1和m2并没有自己独立的图片储存空间,而是把自己的矩阵指针指向了m的指针的地址。所以,当我们对m,m1,m2三个图片中的一个有所操作的时候,其他两个图片也会受到影响,有如下的测试代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
//创建了Mat类型的变量m,并且通过拷贝构造的方法拷贝到了变量m1和m2
Mat m = imread("a.jpg");
Mat m1 = m;
Mat m2(m);
//创建了矩阵r和向量s,用于在图m1上绘图
Rect r(0, 0, 300, 300);
Scalar s(255, 0, 255);
rectangle(m1, r, s);
//显示所有的三张图片
imshow("m", m);
imshow("m1", m1);
imshow("m2", m2);
waitKey(0);
return 0;
}
运行结果如下:
2.2 使用clone()函数或者copyTo()函数进行拷贝
使用这两种方法拷贝,是一种完全拷贝,会为图片生成独立的图片储存矩阵,与原图片不公用数据,这样的话,操作其中一个,其他的并不会受到影响,缺点是占用空间大,而且速度比较慢。
写法如下:
Mat m = imread("a.jpg");
Mat m1;
m.copyTo(m1);
Mat m2=m.clone();
测试代码:
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main()
{
//创建了Mat类型的变量m,并且拷贝到了变量m1和m2
Mat m = imread("a.jpg");
Mat m1;
m.copyTo(m1);
Mat m2=m.clone();
//创建了矩阵r和向量s,用于在图m1上绘图
Rect r(0, 0, 300, 300);
Scalar s(255, 0, 255);
rectangle(m, r, s);
//显示所有的三张图片
imshow("m", m);
imshow("m1", m1);
imshow("m2", m2);
waitKey(0);
return 0;
}
3.Mat类创建矩阵
由于Mat类本身就是一种矩阵处理的类,所以可以通过Mat类进行矩阵的创建
3.1Mat类创建二维矩阵
利用Mat类的构造函数进行
Mat类有很多构造函数可以用来创建矩阵结构,并且给与赋值,这里距离介绍一种,其函数定义为
Mat(int rows, int cols, int type, const Scalar& s);
这个构造函数具有四个参数,其特点是能够定义矩阵的结构并且能够赋予初值
第一个参数表示矩阵的行数
第二个参数表示矩阵的列数
第三个参数表示矩阵储存数据的类型,具有格式 CV_[位数][有无符号][数据类型][通道数],如
CV_8UC3 //表示存储数据为8位无符号char类型,并且具有三个通道
第四个参数是一种向量类型的变量,能够给予矩阵赋予初值,这个向量最多有四个维度。
使用举例:
Mat m(3, 3, CV_8UC3, Scalar(100, 10, 0));
利用成员函数create创建矩阵
使用这种方法创建的矩阵只是一种开辟内存空间,而不能赋予初值
Mat m;
m.create(3, 3, CV_8UC3);
Matlab式的矩阵创建
Mat类中有三个static的函数eye(),zeros(),ones()用于创建矩阵,与matlab中的同名函数用法相似
,因为是静态函数,所以他们可以脱离具体实例对象单独存在,调用的时候前面加上所属类名即可调用,用法如下
Mat E = Mat::eye(4, 4, CV_32F);
Mat Z = Mat::zeros(4, 4, CV_32F);
Mat O = Mat::ones(4, 4, CV_32F);
输出:
逗号分隔的方式创建矩阵
如果矩阵比较小,可以通过这种方法进行输入,有点类似于每个数字都自己输入的样子
Mat C =(Mat_<double>(3,3)<<1,1,1,1,1,1,1,1,1);
3.2Mat类创建多维矩阵
Mat类除了能够像上面的例子那样创建二维矩阵,也可以通过定义维度的方法创建多维矩阵,这种构造函数定义如下:
Mat(int ndims, const int* sizes, int type, const Scalar& s);
第一个参数是矩阵的维度,比如写3代表是三维矩阵
第二个参数是一个int类型的指针,表示每个维度的数据长度是多少
第三个参数表示储存数据的类型是什么
第四个参数用来赋予初始值的
使用方法如下:
int size[3]={3,3,3};
Mat(3,size,CV_8UC3,Scalar::all(0));
4.Mat类的格式化输出
Mat类的格式化输出仅限于二维的矩阵。或者说,使用cout来输出Mat类型的变量,仅限于二维的。这里只举几个例子。
4.1 默认格式
Mat m=Mat::zeros(5,5,CV_64F);
cout<<m<<endl;
4.2 python格式
Mat m = Mat::zeros(5, 5, CV_64F);
cout << format(m,Formatter::FMT_PYTHON)<< endl<<endl;
4.3 c语言格式
Mat m = Mat::zeros(5, 5, CV_64F);
cout << format(m, Formatter::FMT_C) << endl << endl;
4.4 numpy格式
Mat m = Mat::zeros(5, 5, CV_64F);
cout << format(m, Formatter::FMT_NUMPY) << endl<<endl;