Opencv中数据结构Mat的相关属性

Opencv中数据结构Mat的相关属性

前言:

The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It can be used to store real or complex-valued vectors and 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 ). Mat类用于表示一个多维的单通道或者多通道的稠密数组。它能够用来存储实数或附属的向量、矩阵、灰度/彩色图像、立体元素、点云、张量,以及直方图(虽然高维的直方图用SparseMat保存比较好)。

以上摘自OpenCV 2.4.9的官方文档opencv2refman.pdf。

以前虽然能够比较熟练的使用OpenCV,但是最近感觉其实笔者自己对OpenCV的最底层数据结构Mat与IplImage都不怎么熟悉…… 由于笔者比较反感总是需要管理内存的IplImage,所以对Mat数据结构做一下学习工作还是有必要的。

官方说明文档opencv2refman.pdf中,写出了Mat的定义如下:

class CV_EXPORTS Mat
{
public:
// ... a lot of methods ...
...
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the array dimensionality, >= 2
int dims;
//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
int rows, cols;
//! pointer to the data
uchar* data;
//! pointer to the reference counter;
// when array points to user-allocated data, the pointer is NULL
int* refcount;
// other members
...
};

下面笔者将从几个方面总结Mat数据结构的主要组成。

参考网址: 《OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解 》 《OpenCV Mat的常见属性》 《OpenCV学习笔记(四十)——再谈OpenCV数据结构Mat详解》

参考文档: 《opencv2refman.pdf》

一. Mat重要数据成员简要列举

如上面的Mat定义源码,Mat类中有很多重要的数据类型成员。 下面进行简单的列举。

  • dims:两者表示矩阵M的维度,如3*4的矩阵为2维,3*4*5的矩阵为3维;
  • data:Mat对象中的指针,指向存放内存中存放矩阵数据的一块内存,即:uchar* data;
  • step:定义了矩阵布局的数组,具体见后面的图片解释;
  • rows, cols:矩阵的行数、列数;
  • depth:即图像每一个像素的位数(bits);具体在后面的地址部分解释;
  • type:表示了矩阵中元素的类型(depth)与矩阵的通道个数(channels);具体在后面解释;
  • channels:通道数量;若图像为RGB、HSV等三通道图像,则channels = 3;若图像为灰度图,则为单通道;
  • elemSize:矩阵中每一个元素的数据大小;具体在后面进行解释;

1. depth, channels, type, elemSize, elemSize1

把这四个数据成员放在一起,是因为这四个数据成员相互之间有关系。

(1) depth

数据的存储一直都是个值得关注的问题,所以数据元素存储的位数和范围就十分重要了。depth就体现了每一个像素的位数,即深度。 Mat中包含的图像深度如下所示:

  • CV_8U:8位无符号整数(0–255),对应Mat_< uchar>
  • CV_8S:8位有符号整数(-128–127),对应Mat_< char >
  • CV_16U:16位无符号整数(0–65535)
  • CV_16S:16位有符号整数(-32768–32767)
  • CV_32S:32位有符号整数(-2147483648–2147483647),对应Mat_< int >
  • CV_32F:32位浮点数(-FLT_MAX..FLT_MAX, INF, NAN),对应Mat_< float >
  • CV_64F:64位浮点数 ( -DBL_MAX..DBL_MAX, INF, NAN)

另外还需要注意:大部分OpenCV的函数支持的数据深度只有8位和32位,所以尽量使用CV_64F。

(2) channels

channels表示了矩阵拥有的通道数量,这个比较容易理解:

  • 若图像为RGB、HSV等三通道图像,则channels == 3;
  • 若图像为灰度图,则为单通道,channels == 1;

(3) type

type表示矩阵中元素的类型(depth)与矩阵的通道个数(channels),可以理解成上面的depth与channels的综合说明。type是一系列预定义的常量,命名规则如下: CV_+位数+数据类型+通道数 具体有如下值:

数据类型

1

2

3

4

CV_8U

CV_8UC1

CV_8UC2

CV_8UC3

CV_8UC4

CV_8S

CV_8SC1

CV_8SC2

CV_8SC3

CV_8SC4

CV_16U

CV_16UC1

CV_16UC2

CV_16UC3

CV_16UC4

CV_16S

CV_16SC1

CV_16SC2

CV_16SC3

CV_16SC4

CV_32S

CV_32SC1

CV_32SC2

CV_32SC3

CV_32SC4

CV_32F

CV_32FC1

CV_32FC2

CV_32FC3

CV_32FC4

CV_64F

CV_64FC1

CV_64FC2

CV_64FC3

CV_64FC4

表格中,行代表了通道数量channels,列代表了图像深度depth。 例如CV_8UC3,可以拆分为:

  • CV_:type的前缀
  • 8U:8位无符号整数(depth)
  • C3:3通道(channels)

注:type一般是在创建Mat对象时设定,若要去的Mat的元素类型,可以不使用type,使用depth。

(4) elemSize

elemSize表示了矩阵中每一个元素的数据大小,单位是字节。公式如下: elemSize = channels * depth / 8 例如type == CV_16SC3,则elemSize = 3 * 16 / 8 = 6 Bytes。

(5) elemSize1

elemSize1表示了矩阵元素的一个通道占用的数据大小,单位是字节。公式如下: elemSize = depth / 8 例如type == CV_16SC3,则elemSize1 = 16 / 8 = 2 Bytes。

二. Mat数据元素地址

使用OpenCV处理图像时,最普遍的处理方式便是遍历图像,即访问所有的图像像素点。但有的算法还需要访问目标像素的邻域,所以这时候就需要了解访问Mat数据元素地址的方式。

1. 像素地址计算公式

假设有矩阵M,则数据元素的地址计算公式如下:

如果是二维数组,则上述公式就简化成:

注:式中m = M.dims,即矩阵的维度。

2. 举例说明

(1) 二维矩阵

假设存在一个二维矩阵如下图所示:

上面是一个3 × 4的矩阵。此时我们按照数据类型为CV_8U, CV_8UC3的情况,分别对其进行讨论。

首先假设其数据类型为CV_8U,也就是单通道的uchar类型,则可以得出上面的数据成员情况分别为:

  • M.dims == 2:二维矩阵;
  • M.rows == 3:图像共三行;
  • M.cols == 4:图像共四列;
  • M.channels == 1:图像通道数为1;
  • M.elemSize() == 1:矩阵中每一个元素的数据大小为1,因为sizeof(uchar) == 1;
  • M.step = [4, 1]:由于是二维矩阵,所以step数组只有两个值;
    • step[0]代表一行数据大小,所以step[0] = 4 * 1 = 4;
    • step[1]代表一个元素的数据大小,即通道个数,所以step[1] = 1;

若假设其数据类型为CV_8UC3,也就是三通道的uchar类型,则可以得出上面的数据成员情况分别为:

  • M.dims == 2:二维矩阵;
  • M.rows == 3:图像共三行;
  • M.cols == 4:图像共四列;
  • M.channels == 3:图像通道数为3;
  • M.elemSize() == 1:矩阵中每一个元素的数据大小为1,因为sizeof(uchar) == 1;
  • M.step = [12, 3]:由于是二维矩阵,所以step数组只有两个值;
    • step[0]代表一行数据大小,所以step[0] = 4 * 3 = 12;
    • step[1]代表一个元素的数据大小,即通道个数,所以step[1] = 3;

(2) 三维矩阵

假设存在一个三维矩阵如下图所示:

上面是一个3 × 4 × 6的矩阵。假设其数据类型为CV_16SC4,此时对其进行讨论。

  • M.dims == 3:三维矩阵;
  • M.channels == 4:图像通道数为4;
  • M.elemSize() == M.elemSize1() * M.channels() == 2 * 4 = 8;
  • M.step = [192, 48, 3]:由于是三维矩阵,所以step数组有三个值;
    • M.step[2] == M.elemSize == 8;
    • M.step[1] == 6 * M.elemSize() == 48;
    • M.step[0] == 4 * 6 * M.elemSize() == 192;

3. 地址访问

关于OpenCV地址访问方法及效率的部分,请见笔者的博文《OpenCV像素点邻域遍历效率比较,以及访问像素点的几种方法 》。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏zhisheng

学习算法之路

一个搞ACM的需要掌握的算法的sheet。 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10...

4305
来自专栏生信技能树

比较不同的对单细胞转录组数据聚类的方法

背景介绍 聚类之前必须要对表达矩阵进行normalization,而且要去除一些批次效应等外部因素。通过对表达矩阵的聚类,可以把细胞群体分成不同的状态,解释为什...

65312
来自专栏小樱的经验随笔

【机器学习笔记之一】深入浅出学习K-Means算法

摘要:在数据挖掘中,K-Means算法是一种 cluster analysis 的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法。 ...

2869
来自专栏Python数据科学

机器学习“特征编码”的经验分享:鱼还是熊掌?

我们拿到的数据通常比较脏乱,可能会带有各种非数字特殊符号,比如中文。下面这个表中显示了我们最原始的数据集。而实际上机器学习模型需要的数据是数字型的,因为只有数字...

2301
来自专栏专知

【LeetCode 204】关关的刷题日记40 Number of Boomerangs

关关的刷题日记40 – Leetcode 447. Number of Boomerangs 题目 Given n points in the plane th...

3444
来自专栏封碎

当今世界最为经典的十大算法 博客分类: 经典文章转载 算法数据结构网络应用数据挖掘J#

本文转载自July CSDN博客:http://blog.csdn.net/v_JULY_v/archive/2011/03/07/6228235.aspx

1282
来自专栏瓜大三哥

基于FPGA的非线性滤波器(二)

基于FPGA的非线性滤波器(二) 之并行全比较排序 在进行FPGA映射之前,必须首先确定排序算法。由于在FPGA的图像处理领域,中值滤波的处理窗口不会太大,因此...

2099
来自专栏互联网大杂烩

Python 异常值分析

异常值分析是检验数据是否有录入错误以及含有不合常理的数据。忽视异常值的存在是十分危险的,不加剔除地把异常值包括进数据的计算分析过程中,对结果会产生不良影响;重视...

1162
来自专栏ATYUN订阅号

利用统计方法,辨别和处理数据中的异常值

在建模时,清理数据样本非常重要,这样做可以确保观察结果充分代表问题。有时,数据集可能包含超出预期范围之外的极端值。这通常被称为异常值,通过理解甚至去除这些异常值...

1223
来自专栏肖力涛的专栏

NLP 点滴 :文本相似度 (上)

在自然语言处理过程中,经常会涉及到如何度量两个文本之间的相似性,我们都知道文本是一种高维的语义空间,如何对其进行抽象分解,从而能够站在数学角度去量化其相似性。

1.7K1

扫码关注云+社区