opencv自带例子学习-图像基本容器mat

Mat

Mat是opencv2.0版本开始替换原来指针的一个数据结构,以前opencv1.0时代储存图像的变量都是以指针的形式,这样存在着一个弊端,每次定义图像变量流程便是,以传统c语言的方式去申请内存,使用完毕之后要记得手动释放,假如忘记了就会造成内存泄漏。而opencv2.0版本以后开始全面支持c++,同时也把mat作为图像数据变量的容器,它本质上是一个类,最大的优点是不需要像指针那样每次使用完都要手动释放内存,其内存管理是自动的。不需要花费精力去担心内存的管理问题,其实现的原理大致和c++新标准的智能指针类似,是采用一种引用计数的方式去记录mat变量的使用,mat变量被使用或者赋值到一个新的变量名(浅拷贝),计数器就会自动加一,变量名被销毁了计数器就自动减一,当计数器值减到0时就会自动调用析构函数释放内存。

查看文档了解一下mat类

先看看mat类的继承派生关系图

mat类继承派生

常见的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Mat ()

Mat (int rows, int cols, int type)

Mat (Size size, int type)

Mat (int rows, int cols, int type, const Scalar &s)

Mat (Size size, int type, const Scalar &s)

Mat (int ndims, const int *sizes, int type)

Mat (const std::vector< int > &sizes, int type)

Mat (int ndims, const int *sizes, int type, const Scalar &s)

Mat (const std::vector< int > &sizes, int type, const Scalar &s)

Mat (const Mat &m)

Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP)

Mat (Size size, int type, void *data, size_t step=AUTO_STEP)

Mat (int ndims, const int *sizes, int type, void *data, const size_t *steps=0)

Mat (const std::vector< int > &sizes, int type, void *data, const size_t *steps=0)

Mat (const Mat &m, const Range &rowRange, const Range &colRange=Range::all())

Mat (const Mat &m, const Rect &roi)

Mat (const Mat &m, const Range *ranges)

Mat (const Mat &m, const std::vector< Range > &ranges)

模板的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<typename _Tp >
Mat (const std::vector< _Tp > &vec, bool copyData=false)

template<typename _Tp , int n>
Mat (const Vec< _Tp, n > &vec, bool copyData=true)

template<typename _Tp , int m, int n>
Mat (const Matx< _Tp, m, n > &mtx, bool copyData=true)

template<typename _Tp >
Mat (const Point_< _Tp > &pt, bool copyData=true)

template<typename _Tp >
Mat (const Point3_< _Tp > &pt, bool copyData=true)

template<typename _Tp >
Mat (const MatCommaInitializer_< _Tp > &commaInitializer)

Mat (const cuda::GpuMat &m)

下面直接贴上代码解释,源代码为opencv samples里面的mat_the_basic_image_container.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*  For description look into the help() function. */

//头文件
#include "opencv2/core.hpp"
#include <iostream>

//命名空间,建议显示使用,如cv::imshow
using namespace std;
using namespace cv;

//帮助信息函数
static void help()
{
cout
<< "\n---------------------------------------------------------------------------" << endl
<< "This program shows how to create matrices(cv::Mat) in OpenCV and its serial"
<< " out capabilities" << endl
<< "That is, cv::Mat M(...); M.create and cout << M. " << endl
<< "Shows how output can be formatted to OpenCV, python, numpy, csv and C styles." << endl
<< "Usage:" << endl
<< "./mat_the_basic_image_container" << endl
<< "-----------------------------------------------------------------------------" << endl
<< endl;
}

int main(int,char**)
{
//输出帮助信息
help();
// create by using the constructor
//! [constructor]
Mat M(2,2, CV_8UC3, Scalar(0,0,255));//使用构造函数创建mat容器, 2x2大小、8位无符号3通道,初始化为红色(opencv默认bgr)
cout << "M = " << endl << " " << M << endl << endl;
//! [constructor]

// create by using the create function()
//! [create]
M.create(4,4, CV_8UC(2));//使用create函数创建mat容器,4x4大小、8位无符号2通道
cout << "M = "<< endl << " " << M << endl << endl;
//! [create]

// create multidimensional matrices
//! [init]
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));//创建多维矩阵、3维、每一维度为一个数组,8位无符号1通道、灰度初始化为0,三维的矩阵无法打印显示
//! [init]

// Cannot print via operator <<

// Create using MATLAB style eye, ones or zero matrix
//创建像matlab风格那样的单位矩阵、数值都为1或0的矩阵
//! [matlab]
Mat E = Mat::eye(4, 4, CV_64F); //单位矩阵
cout << "E = " << endl << " " << E << endl << endl;
Mat O = Mat::ones(2, 2, CV_32F);//数值全为1矩阵
cout << "O = " << endl << " " << O << endl << endl;
Mat Z = Mat::zeros(3,3, CV_8UC1);//数值全为0矩阵
cout << "Z = " << endl << " " << Z << endl << endl;
//! [matlab]

// create a 3x3 double-precision identity matrix
//! [comma]
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//逗号分隔符方式,用到<<运算符
cout << "C = " << endl << " " << C << endl << endl;
//! [comma]
// do the same with initializer_list
#ifdef CV_CXX11
//! [list]
C = (Mat_<double>({0, -1, 0, -1, 5, -1, 0, -1, 0})).reshape(3);//使用初始化列表的方式创建
cout << "C = " << endl << " " << C << endl << endl;
//! [list]
#endif
//! [clone]
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;//使用clone函数方式
//! [clone]

// Fill a matrix with random values
//! [random]
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));//创建包含随机数的矩阵
//! [random]

// Demonstrate the output formatting options
//! [out-default]

//格式化打印这些数据

cout << "R (default) = " << endl << R << endl << endl;//默认格式
//! [out-default]
//! [out-python]
cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;//python风格
//! [out-python]
//! [out-numpy]
cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY ) << endl << endl;//numpy风格
//! [out-numpy]
//! [out-csv]
cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV ) << endl << endl;//csv风格、即逗号分隔值风格
//! [out-csv]
//! [out-c]
cout << "R (c) = " << endl << format(R, Formatter::FMT_C ) << endl << endl;//c语言风格
//! [out-c]

//! [out-point2]
Point2f P(5, 1);//浮点型2维点
cout << "Point (2D) = " << P << endl << endl;
//! [out-point2]

//! [out-point3]
Point3f P3f(2, 6, 7);//浮点型3维点
cout << "Point (3D) = " << P3f << endl << endl;
//! [out-point3]

//! [out-vector]
vector<float> v;
v.push_back( (float)CV_PI); v.push_back(2); v.push_back(3.01f);
cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;//向量转为mat类
//! [out-vector]

//! [out-vector-points]
vector<Point2f> vPoints(20);//浮点型2维点集合
for (size_t i = 0; i < vPoints.size(); ++i)
vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "A vector of 2D Points = " << vPoints << endl << endl;
//! [out-vector-points]
return 0;
}

代码知识点

1.使用构造函数创建mat容器

1
2
Mat M(2,2, CV_8UC3, Scalar(0,0,255));//使用构造函数创建mat容器, 2x2大小、8位无符号3通道,初始化为红色(opencv默认bgr)
cout << "M = " << endl << " " << M << endl << endl;

2.使用create函数创建mat容器

1
2
M.create(4,4, CV_8UC(2));//使用create函数创建mat容器,4x4大小、8位无符号2通道
cout << "M = "<< endl << " " << M << endl << endl;

3.创建多维矩阵

1
2
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));//创建多维矩阵、3维、每一维度为一个数组,8位无符号1通道、灰度初始化为0,三维的矩阵无法打印显示

4.创建像matlab风格那样的单位矩阵、数值都为1或0的矩阵

1
2
3
4
5
6
7
8
//! [matlab]
Mat E = Mat::eye(4, 4, CV_64F); //单位矩阵
cout << "E = " << endl << " " << E << endl << endl;
Mat O = Mat::ones(2, 2, CV_32F);//数值全为1矩阵
cout << "O = " << endl << " " << O << endl << endl;
Mat Z = Mat::zeros(3,3, CV_8UC1);//数值全为0矩阵
cout << "Z = " << endl << " " << Z << endl << endl;
//! [matlab]

5.其他方式创建矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    // create a 3x3 double-precision identity matrix
//! [comma]
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//逗号分隔符方式,用到<<运算符
cout << "C = " << endl << " " << C << endl << endl;
//! [comma]
// do the same with initializer_list
#ifdef CV_CXX11
//! [list]
C = (Mat_<double>({0, -1, 0, -1, 5, -1, 0, -1, 0})).reshape(3);//使用初始化列表的方式创建
cout << "C = " << endl << " " << C << endl << endl;
//! [list]
#endif
//! [clone]
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;//使用clone函数方式
//! [clone]

// Fill a matrix with random values
//! [random]
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));//创建包含随机数的矩阵
//! [random]

6.格式化打印输出Mat类数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cout << "R (default) = " << endl <<        R           << endl << endl;//默认格式
//! [out-default]
//! [out-python]
cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;//python风格
//! [out-python]
//! [out-numpy]
cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY ) << endl << endl;//numpy风格
//! [out-numpy]
//! [out-csv]
cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV ) << endl << endl;//csv风格、即逗号分隔值风格
//! [out-csv]
//! [out-c]
cout << "R (c) = " << endl << format(R, Formatter::FMT_C ) << endl << endl;//c语言风格
//! [out-c]

输出的格式布置程序中的五种,查看文档可以看到Formatter有一个枚举变量,定义如下

1
2
3
4
5
6
7
8
enum  	{ 
FMT_DEFAULT = 0,
FMT_MATLAB = 1,
FMT_CSV = 2,
FMT_PYTHON = 3,
FMT_NUMPY = 4,
FMT_C = 5
}

7. 2D、3D和vector的使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//! [out-point2]
Point2f P(5, 1);//浮点型2维点
cout << "Point (2D) = " << P << endl << endl;
//! [out-point2]

//! [out-point3]
Point3f P3f(2, 6, 7);//浮点型3维点
cout << "Point (3D) = " << P3f << endl << endl;
//! [out-point3]

//! [out-vector]
vector<float> v;
v.push_back( (float)CV_PI); v.push_back(2); v.push_back(3.01f);
cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;//向量转为mat类
//! [out-vector]

//! [out-vector-points]
vector<Point2f> vPoints(20);//浮点型2维点集合
for (size_t i = 0; i < vPoints.size(); ++i)
vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "A vector of 2D Points = " << vPoints << endl << endl;
//! [out-vector-points]

8.运行截图

运行截图1

运行截图2

运行截图3

运行截图4

回顾总结

这个例程的知识点包含了mat类的实例化方法,包含构造函数、create函数、和克隆拷贝、初始化列表等,接着时特殊矩阵的创建,格式化输出mat类数据,最后时2D、3D和vector的使用方法。

-------------本文结束感谢您的阅读-------------