1.Mat-基本图像容器
我们有多种方式从现实世界中获取数字图像:数码相机,扫描仪,计算机断层扫描和磁共振成像等等。在任何情况下,我们(人类)看到的都是图像。然而,当将其转换为数字设备时,我们记录的是图像中每个点的数值。
Mat A, C; // creates just the header parts
A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix)
Mat B(A); // Use the copy constructor
C = A; // Assignment operator
1.2.存储方法
这是关于如何存储像素值。您可以选择使用的颜色空间和数据类型。颜色空间是指我们如何组合颜色分量以编码给定的颜色。最简单的一个是灰色,我们可以使用的颜色是黑色和白色。这些组合使我们能够创建许多灰色阴影。
对于丰富多彩的方式,我们有更多的选择方法。他们每个人都将它们分解成三到四个基本组件,我们可以使用这些组合来创建其他组件。最流行的是RGB,主要是因为这也是我们的眼睛如何建立颜色。其基色为红,绿,蓝。为了编码颜色的透明度有时是第四个元素:添加了α(A)。
然而,还有许多其他颜色系统都有自己的优势:
- RGB是最常见的,因为我们的眼睛使用类似的东西,但请记住,OpenCV标准显示系统使用BGR颜色空间(红色和蓝色通道的开关)组成颜色。
- HSV和HLS将颜色分解为色调,饱和度和值/亮度分量,这是我们描述颜色的更自然的方式。例如,您可能会忽略最后一个组件,使您的算法对输入图像的光线条件不太敏感。
- YCrCb被流行的JPEG图像格式使用。
- CIE L * a * b *是感知统一的颜色空间,如果您需要测量给定颜色与其他颜色的距离,则可方便使用。
每个建筑组件都有自己的有效域。这导致使用的数据类型。我们如何存储组件定义了我们在其域中的控件。可能的最小数据类型是char,这意味着一个字节或8位。这可能是无符号的(因此可以存储从0到255的值)或带符号(从-127到+127的值)。尽管在三个组件的情况下,这已经提供了1600万个可能的颜色来表示(像在RGB情况下),我们可以通过使用浮点数(4字节= 32位)或双(8字节= 64位)数据来获得更精细的控制每个组件的类型。然而,请记住,增加组件的大小也会增加内存中整个画面的大小。
1.3.明确创建一个Mat对象
在加载,修改和保存图像教程中,您已经学习了如何使用cv :: imwrite()函数将矩阵写入图像文件。但是,为了调试目的,查看实际值更为方便。您可以使用Mat的“操作符”来执行此操作。请注意,这仅适用于二维矩阵。
虽然Mat作为一个图像容器非常好,但它也是一个通用的矩阵类。因此,可以创建和操纵多维矩阵。您可以通过多种方式创建Mat对象:#
1. (cv :: Mat :: Mat)构造函数
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
//构造函数构建
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
cout << " M = " << endl << "" << M << endl << endl;
return 0;
}
执行结果:
M =
[ 0, 0, 255, 0, 0, 255;
0, 0, 255, 0, 0, 255]
对于二维和多通道图像,我们首先定义它们的大小:行和列数明智。
然后,我们需要指定用于存储元素的数据类型和每个矩阵点的通道数。为此,我们根据以下约定构造了多个定义:
CV_[The number of bits per item][Signed or Unsigned][Type Prefix]C[The channel number]
例如,CV_8UC3意味着我们使用8位长的无符号字符类型,每个像素有三个形成三个通道。这是最多四个通道号预定义的。该CV ::标量是四个元件短矢量。指定这一点,您可以使用自定义值初始化所有矩阵点。如果您需要更多功能,您可以使用上部宏来创建类型,在括号中设置通道号,如下所示。
- 使用C / C ++数组并通过构造函数进行初始化
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));
上面的例子显示了如何创建一个具有两维以上的矩阵。指定其维度,然后传递一个包含每个维的大小的指针,其余的保持不变。
2. (cv :: Mat :: create)函数构建
- cv :: Mat :: create function:
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
//Create函数构建
Mat M;
M.create(4, 4, CV_8UC(2));
cout << " M = " << endl << "" << M << endl << endl;
return 0;
}
执行结果:
M =
[116, 0, 46, 0, 79, 0, 102, 0;
102, 0, 105, 0, 99, 0, 101, 0;
46, 0, 68, 0, 101, 0, 115, 0;
107, 0, 116, 0, 111, 0, 112, 0]
您无法使用此结构初始化矩阵值。如果新的大小不适合旧的,它将仅重新分配其矩阵数据存储器。
- MATLAB样式初始化器:cv :: Mat :: zeros,cv :: Mat :: ones,cv :: Mat :: eye。指定要使用的大小和数据类型:
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
//用matlab创建 1或0矩阵
Mat E = Mat::eye(4, 4, CV_64F);
cout << "E = " << endl << "" << E << endl << endl;
Mat O = Mat::ones(2, 2, CV_32F);
cout << "O = " << endl << "" << O << endl << endl;
Mat Z = Mat::zeros(3, 3, CV_8UC1);
cout << "Z = " << endl << "" << Z << endl << endl;
return 0;
}
执行结果:
E =
[1, 0, 0, 0;
0, 1, 0, 0;
0, 0, 1, 0;
0, 0, 0, 1]
O =
[1, 1;
1, 1]
Z =
[ 0, 0, 0;
0, 0, 0;
0, 0, 0]
3.对于小矩阵,您可以使用逗号分隔的初始化器或初始化器列表(在最后一种情况下需要C ++ 11支持):
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
//创建一个3x3双精度单位矩阵
Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << "" << C << endl << endl;
return 0;
}
C =(Mat_ <double>({0,-1,0,-1,5,-1,0,-1,0}))。reshape(3);
cout << “C =” << endl << “”“ << C << endl << endl;
执行结果:
C =
[0, -1, 0;
-1, 5, -1;
0, -1, 0]
4. 为现有的Mat对象和(cv :: Mat :: clone)或(cv :: Mat :: copyTo)创建一个新标题。
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
#ifdef CV_CXX11
//! [list]
Mat C;
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]
return 0;
}
执行结果:
C =
[0, -1, 0;
-1, 5, -1;
0, -1, 0]
RowClone =
[-1, 5, -1]
1.4.输出格式
使用cv :: randu()函数填入随机值的矩阵。您需要给出随机值的较低和较高值:
您可以看到默认的格式化选项。然而,OpenCV允许您格式化矩阵输出:
1. Default
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
//用随机值填充一个矩阵
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));
//演示输出格式化选项
cout << "R (default) = " << endl << R << endl << endl;
return 0;
}
执行结果:
R (default) =
[ 91, 2, 79, 179, 52, 205;
236, 8, 181, 239, 26, 248;
207, 218, 45, 183, 158, 101]
2. Python
cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;
执行结果:
R (python) =
[[[ 91, 2, 79], [179, 52, 205]],
[[236, 8, 181], [239, 26, 248]],
[[207, 218, 45], [183, 158, 101]]]
3. Comma separated values (CSV)
cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV) << endl << endl;
执行结果:
R (csv) =
91, 2, 79, 179, 52, 205
236, 8, 181, 239, 26, 248
207, 218, 45, 183, 158, 101
4. NumPy
cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY) << endl << endl;
执行结果:
R (numpy) =
array([[[ 91, 2, 79], [179, 52, 205]],
[[236, 8, 181], [239, 26, 248]],
[[207, 218, 45], [183, 158, 101]]], dtype='uint8')
5. C
cout << "R (c) = " << endl << format(R, Formatter::FMT_C) << endl << endl;
执行结果:
R (c) =
{ 91, 2, 79, 179, 52, 205,
236, 8, 181, 239, 26, 248,
207, 218, 45, 183, 158, 101}
1.5. 其他常用项目的输出
OpenCV还通过<<运算符来支持其他常见OpenCV数据结构的输出:
1. 2D Point
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
Point2f P(5, 1);
cout << "Point (2D) = " << P << endl << endl;
return 0;
}
执行结果:
Point (2D) = [5, 1]
2. 3D Point
Point3f P3f(2, 6, 7);
cout << "Point (3D) = " << P3f << endl << endl;
执行结果:
Point (3D) = [2, 6, 7]
3. std :: vector via cv :: Mat
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;
执行结果:
Vector of floats via Mat = [3.1415927;
2;
3.01]
4. std::vector of points
vector<Point2f> vPoints(20);
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;
执行结果:
A vector of 2D Points = [0, 0;
5, 1;
10, 2;
15, 3;
20, 4;
25, 5;
30, 6;
35, 0;
40, 1;
45, 2;
50, 3;
55, 4;
60, 5;
65, 6;
70, 0;
75, 1;
80, 2;
85, 3;
90, 4;
95, 5]
完整的源代码:
#include "opencv2/core.hpp"
#include <iostream>
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 image(int, char**)
{
help();
//构造函数构建
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
cout << "M = " << endl << " " << M << endl << endl;
//Create函数构建
M.create(4, 4, CV_8UC(2));
cout << "M = " << endl << " " << M << endl << endl;
//创建多维矩阵
int sz[3] = { 2,2,2 };
Mat L(3, sz, CV_8UC(1), Scalar::all(0));
//用matlab创建 1或0矩阵
Mat E = Mat::eye(4, 4, CV_64F);
cout << "E = " << endl << " " << E << endl << endl;
Mat O = Mat::ones(2, 2, CV_32F);
cout << "O = " << endl << " " << O << endl << endl;
Mat Z = Mat::zeros(3, 3, CV_8UC1);
cout << "Z = " << endl << " " << Z << endl << endl;
//创建一个3x3双精度单位矩阵
Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;
//对初始化列表做同样的事吗
#ifdef CV_CXX11
C = (Mat_<double>({ 0, -1, 0, -1, 5, -1, 0, -1, 0 })).reshape(3);
cout << "C = " << endl << " " << C << endl << endl;
#endif
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;
//用随机值填充一个矩阵
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));
//演示输出格式化选项
cout << "R (default) = " << endl << R << endl << endl;
cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;
cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY) << endl << endl;
cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV) << endl << endl;
cout << "R (c) = " << endl << format(R, Formatter::FMT_C) << endl << endl;
// 其他常用项目的输出
Point2f P(5, 1);
cout << "Point (2D) = " << P << endl << endl;
Point3f P3f(2, 6, 7);
cout << "Point (3D) = " << P3f << endl << endl;
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;
vector<Point2f> vPoints(20);
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;
return 0;
}
2. Mat类简单用法
2.1.Mat::Mat(int rows, int cols, int type)
- rows:矩阵行数
- cols:矩阵列数
- type:CV_8UC1(8位 uchar型 (channel)1通道) 类似可以定义些CV_32FC3.说明:CV_(位数)+(数据类型)+(通道 数)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char argv)
{
Mat A(3, 2, CV_8UC1);//一通道
Mat B(3, 2, CV_32FC3);//三通道
cout << “A=” << endl << “” << A << endl;
cout << “B=” << endl << “” << B << endl;
}
执行结果:
A=
[144, 148;
151, 34;
249, 127]
B=
[0.00094728079, 8.1135181e-43, 0.00094956905, 8.1135181e-43, 0.00094929244, 8.1135181e-43;
0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43;
0.00094709825, 8.1135181e-43, 0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43]
2.2.Mat::Mat(Size size, int type)
- Size:矩阵大小 //可以用别的图像的大小也可以自定Size(width,heighth)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char argv)
{
Mat A(3, 2, CV_8UC1);//一通道
Mat B(A.size(), CV_32FC3); //以A的大小定义
cout << “B=” << endl << “” << B << endl;
}
执行结果:
B=
[8.4436516e-24, 8.8141673e-43, 8.4758624e-24, 8.8141673e-43, 8.4709146e-24, 8.8141673e-43;
8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43;
8.4411777e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43]
2.3.:Mat sampleMat = (Mat_< float>(1, 2) << num1, num2);
- 这是定义类一个一行两列的内容为float类型的矩阵,并且将num1,num2这两个数赋给矩阵
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
float num1 = 2;
float num2 = 4;
Mat sampleMat = (Mat_<float>(1, 2) << num1, num2);
cout << "sampleMat=" << endl << "" << sampleMat << endl;
}
执行结果:
sampleMat=
[2, 4]
2.4.Mat DataMat(1, 2, CV_32FC1, &a[i][0]);
- 此处假设a[i][2]。则定义了个一行两列的矩阵,类型为32位浮点型单通道,然后将a[i][0],a[i][1]的值赋给了矩阵。
2.5.零矩阵:cv::Mat::zeros(rows,cols,type)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat A = Mat::zeros(5, 5, CV_8UC1);
cout << "A=" << endl << "" << A << endl;
}
执行结果:
A=
[ 0, 0, 0, 0, 0;
0, 0, 0, 0, 0;
0, 0, 0, 0, 0;
0, 0, 0, 0, 0;
0, 0, 0, 0, 0]
2.6.one矩阵:cv::Mat::ones(rows,cols,type)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat B = Mat::ones(5, 5, CV_8UC1);
cout << "B=" << endl << "" << B << endl;
}
执行结果:
B=
[ 1, 1, 1, 1, 1;
1, 1, 1, 1, 1;
1, 1, 1, 1, 1;
1, 1, 1, 1, 1;
1, 1, 1, 1, 1]
2.7.单位矩阵:cv::Mat::eye(rows,cols,type)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat C = Mat::eye(5, 5, CV_8UC1);
cout << "C=" << endl << "" << C << endl;
}
执行结果:
C=
[ 1, 0, 0, 0, 0;
0, 1, 0, 0, 0;
0, 0, 1, 0, 0;
0, 0, 0, 1, 0;
0, 0, 0, 0, 1]
2.8.取一行:Mat B:B.row(i)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat B = Mat::ones(5, 5, CV_8UC1);
Mat A = Mat::eye(5, 5, CV_8UC1);
cout << "B的第一行" << endl << "" << B.row(1) << endl;
cout << "A的第一列" << endl << "" << A.col(1) << endl;
}
执行结果:
B的第一行
[ 1, 1, 1, 1, 1]
A的第一列
[ 0;
1;
0;
0;
0]