目录

1.  Mat说明

2.  通道宏定义说明

3.  创建 Mat对象的方式


1.  Mat说明

在opencv中,图像用一个矩阵数组表示,类名为Mat(Matrices的前三个字母的缩写)。类Mat表示一个n维密度数值的单通道或多通道数组(注:所谓密度,是否每一个元素都会存储,哪怕该值为零,而稀疏矩阵不存储零值)。它可用于存储实数或复数向量、以及矩阵、灰度图像或彩色图像、立体像素(voxel)体积、向量域(fields)、点云(point clouds,一系列在三维空间中描述物体几何形状的点)、张量(tensors)、直方图(不过,非常高维的直方图可能存储在 SparseMat 中更好)。数组M的数据布局由数组M.step[]所定义,因此,元素 ( i_{0} ,..., i_{M.dims-1})  的地址(其中, 0 \leq i_k < M.size[k] )计算为

\rm{addr}(M_{i_{0} ,...,i_{M.dims-1} )} = M.data + M.step[0]* i_{0} + M.step[1]* i_{1} + ...+ \\ \\M.step[M.dims-1]* i_{M.dims-1}

在二维数组的情况下,上述公式缩减为

\rm{addr}(M_{i,j}) = M.data + M.step[0]* i + M.step[1]* j  

注意,M.step[i] >= M.step[i +1]  ( 事实上,M.step[i] >= M.step[i +1]* M.step[i +1] )

这意味着,二维矩阵是逐行存储的三维矩阵逐平面存储的,如此,等等。 M.step[M.dims-1] 是最小的,并且总是等于元素数目 M.elemSize()。因此,Mat 中的数据布局与标准工具包和 SDK 中的大多数密度数组类型兼容,例如 Numpy (ndarray)、Win32(独立设备位图)等,即使用逐步(steps)(或大步(strides))的任何数组来计算像素的位置。由于这种兼容性,可以为用户分配的数据创建 Mat 头文件并使用 OpenCV 函数就地处理它。

2.  通道宏定义说明

#define CV_8U   0    //8位无符号整数

#define CV_8S   1    //8位有符号整数

#define CV_16U  2    // 16位无符号整数

#define CV_16S  3    // 16位有符号整数

#define CV_32S  4    // 32位有符号整数

#define CV_32F  5    // 32位浮点数

#define CV_64F  6    // 64位浮点数

#define CV_16F  7     //16位浮点数

#define CV_8UC1 CV_MAKETYPE(CV_8U,1)

#define CV_8UC2 CV_MAKETYPE(CV_8U,2)

#define CV_8UC3 CV_MAKETYPE(CV_8U,3)

#define CV_8UC4 CV_MAKETYPE(CV_8U,4)

#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))

// CV_8UC1 表示8位无符号1通道,

// 最后的数字表示通道数,数字前的CChannel道字母(下同)

#define CV_8SC1 CV_MAKETYPE(CV_8S,1)

#define CV_8SC2 CV_MAKETYPE(CV_8S,2)

#define CV_8SC3 CV_MAKETYPE(CV_8S,3)

#define CV_8SC4 CV_MAKETYPE(CV_8S,4)

#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))

#define CV_16UC1 CV_MAKETYPE(CV_16U,1)

#define CV_16UC2 CV_MAKETYPE(CV_16U,2)

#define CV_16UC3 CV_MAKETYPE(CV_16U,3)

#define CV_16UC4 CV_MAKETYPE(CV_16U,4)

#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))

#define CV_16SC1 CV_MAKETYPE(CV_16S,1)

#define CV_16SC2 CV_MAKETYPE(CV_16S,2)

#define CV_16SC3 CV_MAKETYPE(CV_16S,3)

#define CV_16SC4 CV_MAKETYPE(CV_16S,4)

#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))

#define CV_32SC1 CV_MAKETYPE(CV_32S,1)

#define CV_32SC2 CV_MAKETYPE(CV_32S,2)

#define CV_32SC3 CV_MAKETYPE(CV_32S,3)

#define CV_32SC4 CV_MAKETYPE(CV_32S,4)

#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))

#define CV_32FC1 CV_MAKETYPE(CV_32F,1)

#define CV_32FC2 CV_MAKETYPE(CV_32F,2)

#define CV_32FC3 CV_MAKETYPE(CV_32F,3)

#define CV_32FC4 CV_MAKETYPE(CV_32F,4)

#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))

#define CV_64FC1 CV_MAKETYPE(CV_64F,1)

#define CV_64FC2 CV_MAKETYPE(CV_64F,2)

#define CV_64FC3 CV_MAKETYPE(CV_64F,3)

#define CV_64FC4 CV_MAKETYPE(CV_64F,4)

#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))

#define CV_16FC1 CV_MAKETYPE(CV_16F,1)

#define CV_16FC2 CV_MAKETYPE(CV_16F,2)

#define CV_16FC3 CV_MAKETYPE(CV_16F,3)

#define CV_16FC4 CV_MAKETYPE(CV_16F,4)

#define CV_16FC(n) CV_MAKETYPE(CV_16F,(n))

3.  创建 Mat对象的方式

    有多种方式可以创建 Mat对象,下面是常用方式:

(1)  使用 create(nrows, ncols, type) 方法或类似的 Mat(nrows, ncols, type[, fillValue]) 构造函数。这将分配一个指定大小和类型的新数组。type 的含义与 cvCreateMat 方法中的相同。例如,CV_8UC1 表示一个 8 位无符号单通道数组,CV_32FC2 表示一个双通道(复数)浮点数组,依此类推。

// 创建一个 7x7 复矩阵,其内容用 1+3j 填充

Mat M(7, 7, CV_32FC2, Scalar(1, 3));

// 现在将 M 转换为一个 100x60 15通道 8位矩阵.

// 旧内容将被移除。

M.create(100, 60, CV_8UC(15));

create() 仅在当前数组的形状或类型与指定的形状或类型不同时才分配一个新数组。

(2)  创建一个多维数组

// 创建一个 100x100x100 8位数组

int sz[] = { 100, 100, 100 };

Mat bigCube(3, sz, CV_8U, Scalar::all(0));

(3)  使用复制构造函数或赋值运算符,其中右侧可以是数组或表达式。数组赋值是 O(1) 操作,因为它只复制数组头并增加引用计数器。如果需要,可以使用 Mat::clone() 方法获取数组的完整(深度)副本。

    为另一个数组的一部分构造数组头。它可以是单行、单列、多行、多列、数组中的矩形区域(在代数中称为“次区域”)或对角线。此类操作也是 O(1) 操作,因为新数组头引用的是相同的数据。您可以使用此功能实际修改数组的一部分,例如:

// 填加第5行并乘以3,再加到第3行

M.row(3) = M.row(3) + M.row(5) * 3;

// 第7列复制到第1列

Mat M1 = M.col(1);

M.col(7).copyTo(M1);

// 创建一个 320x240 图像

Mat img(Size(320, 240), CV_8UC3);

//先择一个 ROI

Mat roi(img, Rect(10, 10, 100, 100));

// 用 (0,255,0) 填充 ROI (在 RGB 颜色空间中是绿色);

// 原 320x240 图像将被修改

roi = Scalar(0, 255, 0);

(4)  由于增加了 datastart 和 dataend 成员,可以使用 locateROI() 计算子数组在主 容器 数组中的相对位置:

Mat A = Mat::eye(10, 10, CV_32S);

// 提取 A 列,第 1 列(含)至第 3 列(不含)。

Mat B = A(Range::all(), Range(1, 3));

//提取 B 行,第 5 行(含)至第 9 行(不含)。

// 即, C \~ A(Range(5, 9), Range(1, 3))

Mat C = B(Range(5, 9), Range::all());

Size size; Point ofs;

C.locateROI(size, ofs);

(5)  快速初始化小型矩阵,和/或实现超高速的元素访问。

double m[3][3] = { {'a', 'b', 'c'}, {'d', 'e', 'f'}, {'g', 'h', 'i'}};

Mat M = Mat(3, 3, CV_64F, m).inv();

(6)  用 MATLAB 风格数组初始化器,zeros(), ones(), eye() 。

// 创建一个 double 精度恒等矩阵并将其加入 M

M += Mat::eye(M.rows, M.cols, CV_64F);

(7)  使用逗号分隔的初始化列表。

// 创建一个 3x3 double 精度恒等矩阵

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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐