cv:Mat是OpenCV中最重要的数据存储类,几乎可以存储所有的矩阵数据(包括2维图片数据)。
cv::Mat
The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store (Mat类用于表示一个多维度的密集的单通道或多通道的数值数组,能用于存储):
- real or complex-valued vectors or matrices (实数值或复合值向量、矩阵)
- grayscale or color images (灰度图或者彩色图)
- voxel volumes (立体元素)
- vector fields (矢量场)
- point clouds (点云)
- tensors (张量)
- histograms (though, very high-dimensional histograms may be better stored in a SparseMat ) (直方图,高纬度的最好存放在SparseMat中)
矩阵 (M) 中数据元素的地址计算公式:
addr(Mi0,i1,…im-1) = M.data + M.step[0] * i0 + M.step[1] * i1 + … + M.step[m-1] * im-1 (其中 m = M.dims,即M的维度)
重要的类成员:
- data:数据存储的起始地址 (uchar*类型);
- dims:矩阵维度。如 3 * 4 的矩阵为 2 维, 3 * 4 * 5 的为3维;
- channels():通道数量,矩阵中表示一个元素所需要的值的个数。例:3 * 4矩阵中共有12个元素,如果每个元素需要3个值表示,那么此矩阵的通道数为3。常见的是一张彩色图片有B蓝、G绿、R红3个通道;
- depth():深度,即表示单通道中元素值的位数(bits)。Mat.depth()返回的是一个 0~6 的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 可见 0和1都代表8位, 2和3都代表16位,4和5代表32位,6代表64位;
- elemSize() : 单个元素在所有通道中大小之和,elemSize() = sizeof(数据类型) * channels()。如果Mat中的数据的数据类型是 CV_8U 那么 elemSize() = 1;CV_8UC3 那么 elemSize() = 3,CV_16UC2 那么 elemSize() = 4;
- elemSize1() : 单个元素在1个通道中的大小。elemSize1() = sizeof(数据类型) = elemSize() / channels()。
- step[]:可以看作是一个有dims个元素的动态数组,定义了矩阵的在各维度之间跳变时的最大步长(单位:字节。如2维Mat时,step[0]表示行长度,step[1]表示元素长度)。
- step1(n):与step[n]对应范围的总通道数, step1(n) = step[n] / elemSize1();
实例分析1:2维情况(stored row by row)按行存储
上面是一个 3 * 4 的2维矩阵(线 * 点),有:
- M.dims = 2;
- M.rows = 3;
- M.cols = 4;
假设其数据类型为 CV_8U,是单通道的 uchar 类型,那么:
- M.depth() = 0;
- M.channels() = 1;
- M.elemSize1() = sizeof(uchar) = 1;
- M.elemSize() = M.elemSize1() * M.channels() = 1 * 1 = 1;
- M.step[]数组有两个元素。M.step[0]表示每行数据的大小,M.step[1] 表示每个数据元素的大小;
- M.step[0] = M.elemSize() * M.cols = 1 * 4 = 4 ;
- M.step[1] = M.elemSize() = 1;
- M.step1(0) = M.step[0] / M.elemSize1() = 4;
- M.step1(1) = M.step[1] / M.elemSize1() = 1。
假设上面的矩阵数据类型是 CV_8UC3,是3通道的 uchar 类型,那么:
- M.depth() = 0;
- M.channels() = 3;
- M.elemSize1() = sizeof(uchar) = 1;
- M.elemSize() = M.elemSize1() * M.channels() = 1 * 3 = 3;
- M.step[]数组有两个元素。M.step[0]表示每行数据的大小,M.step[1] 表示每个数据元素的大小;
- M.step[0] = M.elemSize() * M.cols = 3 * 4 = 12 ;
- M.step[1] = M.elemSize() = 3;
- M.step1(0) = M.step[0] / M.elemSize1() = 12 / 1 = 12;
- M.step1(1) = M.step[1] / M.elemSize1() = 3 / 1 = 3。
实例分析2:3维情况(stored plane by plane)按面存储
上面是一个 3 * 4 * 6 的3维矩阵(面 * 线 * 点),有:
- M.dims = 3;
- M.rows = 4;
- M.cols = 6;
假设其数据类型为 CV_16SC4,是4通道的 short 类型,那么:
- M.depth() = 3;
- M.channels() = 4 ;
- M.elemSize1() = sizeof(short) = 2 ;
- M.elemSize() = M.elemSize1() * M.channels() = M.step[M.dims-1] = M.step[2] = 2 * 4 = 8;
- M.step[0] = M.rows * M.cols * M.elemSize() = 4 * 6 * 8 = 192;
- M.step[1] = M.cols * M.elemSize() = 6 * 8 = 48;
- M.step[2] = M.elemSize() = 8;
- M.step1(0) = M.step[0] / M.elemSize1() = 192 / 2 = 96 (第1维度(面)的总通道数);
- M.step1(1) = M.step[1] / M.elemSize1() = 48 / 2 = 24(第2维度(线)的总通道数);
- M.step1(2) = M.step[2] / M.elemSize1() = M.channels() = 4(第3维度(点)的总通道数);