您的位置:首页 > 运维架构

图像识别与处理之Opencv——Mat类

2017-10-15 00:51 337 查看

Mat 类

早期的 OpenCV 中,使用 IplImage 和 CvMat 数据结构来表示图像。 IplImage和 CvMat 都是 C 语言的结构。 使用这两个结构的问题是内存需要手动管理,开发者必须清楚的知道何时需要申请内存,何时需要释放内存。这个开发者带来了一定的负担,开发者应该将更多精力用于算法设计,因此在新版本的 OpenCV 中引入了 Mat 类。新加入的 Mat 类能够自动管理内存。使用 Mat 类,你不再需要花费大量精力在内存管理上。而且你的代码会变得很简洁,代码行数会变少。但 C++接口唯一的不足是当前一些嵌入式开发系统可能只支持 C 语言,如果你的开发平台支持C++,完全没有必要再用 IplImage 和 CvMat。在新版本的 OpenCV 中,开发者依然可以使用 IplImage 和 CvMat,但是一些新增加的函数只提供了 Mat 接口。

一、Mat 类的定义

如下所示,关键的属性如下方代码所示:

自己也可以在opencv的程序里打开看个究竟。

class CV_EXPORTS Mat
{
public:
//一系列函数
...
/* flag 参数中包含许多关于矩阵的信息,如:
-Mat 的标识
-数据是否连续
-深度
-通道数目
*/
int flags;
//矩阵的维数,取值应该大于或等于 2
int dims;
//矩阵的行数和列数,如果矩阵超过 2 维,这两个变量的值都为-1
int rows, cols;
//指向数据的指针
uchar* data;
//指向引用计数的指针
//如果数据是由用户分配的,则为 NULL
int* refcount;24
//其他成员变量和成员函数
...
};


二.创建 Mat 对象

Mat 是一个非常优秀的图像类,它同时也是一个通用的矩阵类,可以用来创建和操作多维矩阵。 有多种方法创建一个 Mat 对象。

1 构造函数方法

Mat 类提供了一系列构造函数,可以方便的根据需要创建 Mat 对象。 下面是一个使用构造函数创建对象的例子。

Mat M(3,2, CV_8UC3, Scalar(0,0,255));
cout << "M = " << endl << " " << M << endl;


第一行代码创建一个行数(高度)为 3,列数(宽度)为 2 的图像,图像元素是 8 位无符号整数类型,且有三个通道。图像的所有像素值被初始化为(0, 0,255)。由于 OpenCV 中默认的颜色顺序为 BGR,因此这是一个全红色的图像。

关于常见颜色的RGB组合及解释,见下图:



第二行代码是输出 Mat 类的实例 M 的所有像素值。Mat 重定义了<<操作符,使用这个操作符,可以方便地输出所有像素值,而不需要使用 for 循环逐个像素输出。

该段代码的输出如下图所示:



常用的构造函数有:

Mat::Mat()

无参数构造方法;

Mat::Mat(int rows, int cols, int type)

创建行数为 rows,列数为 col,类型为 type 的图像;

Mat::Mat(Size size, int type)

创建大小为 size,类型为 type 的图像;

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

创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s;

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

创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s;

Mat::Mat(const Mat& m)

将 m 赋值给新创建的对象,此处不会对图像数据进行复制, m 和新对象

共用图像数据;

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

创建行数为 rows,列数为 col,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step

指定。

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

创建大小为 size,类型为 type 的图像,此构造函数不创建图像数据所需内存,而是直接使用 data 所指内存,图像的行步长由 step 指定。

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

创建的新图像为 m 的一部分,具体的范围由 rowRange 和colRange 指定,此构造函数也不进行图像数据的复制操作,新图像与 m 共用图像数据;

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

创建的新图像为 m 的一部分,具体的范围 roi 指定,此构造函数也不进行图像数据的复制操作,新图像与 m 共用图像数据。

这些构造函数中,很多都涉及到类型 type

type可以是 CV_8UC1,CV_16SC1,…,CV_64FC4 等。里面的

8U 表示 8 位无符号整数, 即unsigned

16S 表示 16 位有符号整数, 即signed

64F表示 64 位浮点数(即 float 类型)

C 后面的数表示通道数,

例如 C1 表示一个通道的图像, C4 表示 4 个通道的图像,以此类推。如果你需要更多的通道数,需要用宏 CV_8UC(n),例如:

Mat M(3,2, CV_8UC(5));//创建行数为 3,列数为 2,通道数为 5 的图像。

2、 create()函数创建对象

除了在构造函数中可以创建图像,也可以使用 Mat 类的 create()函数创建图像。如果 create()函数指定的参数与图像之前的参数相同,则不进行实质的内存申请操作;如果参数不同,则减少原始数据内存的索引,并重新申请内存。

使用方法如下面例程所示:

Mat M(2,2, CV_8UC3);//构造函数创建图像
M.create(3,2, CV_8UC2);//释放内存重新创建图像26


需要注意的时,使用 create()函数无法设置图像像素的初始值。

3.Matlab 风格的创建对象方法

OpenCV 2 中提供了 Matlab 风格的函数,如 zeros(), ones()和 eyes()。这种方法使得代码非常简洁,使用起来也非常方便。使用这些函数需要指定图像的大小和类型。

使用方法如下:

Mat Z = Mat::zeros(2,3, CV_8UC1);//2行3列的8位无符号整型,一通道的0矩阵
cout << "Z = " << endl << " " << Z << endl;
Mat O = Mat::ones(2, 3, CV_32F);
cout << "O = " << endl << " " << O << endl;
Mat E = Mat::eye(2, 3, CV_64F);
cout << "E = " << endl << " " << E << endl;


该代码中,有些 type 参数如 CV_32F 未注明通道数目,这种情况下默认表示单通道。

上面代码的输出结果如下图所示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: