OpenCV2:Mat属性type,depth,step
在OpenCV2中Mat类无疑使占据着核心地位的,前段时间初学OpenCV2时对Mat类有了个初步的了解,见OpenCV2:Mat初学。这几天试着用OpenCV2实现了图像缩小的两种算法:基于等间隔采样和基于局部均值的图像缩小,发现对Mat中的数据布局和一些属性的认知还是懵懵懂懂,本文对Mat的一些重要属性和数据布局做一个总结。
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保存比较好)。简而言之,Mat就是用来保存多维的矩阵的。
Mat的常见属性
- data uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。
- dims 矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3.
- rows 矩阵的行数
- cols 矩阵的列数
- size 矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1)
- channels 矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三部分组成,则channels = 3
下面的几个属性是和Mat中元素的数据类型相关的。
- type
表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4 CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4 CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4 这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数。
例如:CV_16UC2,表示的是元素类型是一个16位的无符号整数,通道为2.
C1,C2,C3,C4则表示通道是1,2,3,4
type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则无需使用type,使用下面的depth - depth
矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值,
将type的预定义值去掉通道信息就是depth值:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F - elemSize
矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes - elemSize1
矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels
下面是一个示例程序,具体说明Mat的各个属性:
Mat img(, , CV_16UC4, Scalar_<uchar>(, , , ));
cout << img << endl;
cout << "dims:" << img.dims << endl;
cout << "rows:" << img.rows << endl;
cout << "cols:" << img.cols << endl;
cout << "channels:" << img.channels() << endl;
cout << "type:" << img.type() << endl;
cout << "depth:" << img.depth() << endl;
cout << "elemSize:" << img.elemSize() << endl;
cout << "elemSize1:" << img.elemSize1() << endl;
首先创建了一个3*4的具有4个通道的矩阵,其元素类型是CV_16U。Scalar_是一个模板向量,用来初始化矩阵的每个像素,因为矩阵具有4个通道,Scalar_有四个值。其运行结果:
运行结果首先打印了Mat中的矩阵,接着是Mat的各个属性。注意其type = 26,而depth = 2。这是由于上面所说的各种预定义类型
例如,CV_16UC4,CV_8U是一些预定义的常量。
step
Mat中的step是一个MStep的一个实例。其声明如下:
struct CV_EXPORTS MStep
{
MStep();
MStep(size_t s);
const size_t& operator[](int i) const;
size_t& operator[](int i);
operator size_t() const;
MStep& operator = (size_t s); size_t* p;
size_t buf[];
protected:
MStep& operator = (const MStep&);
};
从其声明中可以看出,MStep和size_t有比较深的关系。用size_t作为参数的构造函数和重载的赋值运算符
MStep(size_t s);
MStep& operator = (size_t s);
向size_t的类型转换以及重载的[ ]运算符返回size_t
const size_t& operator[](int i) const; size_t& operator[](int i);
size_t的数组以及指针
size_t* p; size_t buf[];
那么size_t又是什么呢,看代码
typedef unsigned int size_t;
size_t就是无符号整数。
再看一下MStep的构造函数,就可以知道其究竟保存的是什么了。
inline Mat::MStep::MStep(size_t s) { p = buf; p[] = s; p[] = ; }
从MStep的定义可以知道,buff是一个size_t[2],而p是size_t *,也就是可以把MStep看做一个size_t[2]。那么step中保存的这个size_t[2]和Mat中的数据有何种关系呢。
step[0]是矩阵中一行元素的字节数。
step[1]是矩阵中一个元素的自己数,也就是和上面所说的elemSize相等。
上面说到,Mat中一个uchar* data指向矩阵数据的首地址,而现在又知道了每一行和每一个元素的数据大小,就可以快速的访问Mat中的任意元素了。下面公式:

step1
规整化的step,值为step / elemSize1。 定义如下:
inline size_t Mat::step1(int i) const { return step.p[i]/elemSize1(); }
仍以上例代码中定义的img为例,来看下step,step1具体的值:
img(3*4)的type是CV_16UC4,step[0]是其一行所占的数据字节数4 *4 * 16 / 8 = 32.
step[1] 是一个元素所占的字节数,img的一个元素具有4个通道,故:4 * 16 / 8 = 2
step1 = step / elemSize1,elemSize1是元素的每个通道所占的字节数。
N维的step(N > 2)
上面分析step是一个size_t[2],实际不是很正确,正确的来说step应该是size_t[dims],dims是Mat的维度,所以对于上面的二维的Mat来说,step是size_t[2]也是正确的。
下面就对三维的Mat数据布局以及step(维度大于3的就算了吧)。

上图引用自http://ggicci.blog.163.com/blog/static/210364096201261052543349/ 搜集资料时发现了这幅图,一切就变的简单了
感谢作者 Ggicci
三维的数据在Mat中是按面来存储的,上图描述的很清晰,这里不再多说。
上面言道,step是一个size_t[dims],dims是维度。so,三维的step就是size_t[3]。其余的不多说了,看图就有了。下面来创建一个三维的Mat,实际看看
int dims[] = { , , };
Mat src(, dims, CV_16SC2, Scalar_<short>(,));
cout << "step[0]:" << src.step[] << endl;
cout << "step[1]:" << src.step[] << endl;
cout << "step[2]:" << src.step[] << endl;
首先创建一个3*3*3,depth为CV_16S的两通道的Mat
step[0]是一个数据面的大小 3 * 3 * (16 / 8 ) * 2 = 36
step[1]是一行数据的大小 3 * (16 / 8 ) * 2 = 12
step[2]是一个元素的大小 2 * (16 / 8) = 4

PS: 三维的Mat 不能使用 <<运算符进行输出的。
over
OpenCV2:Mat属性type,depth,step的更多相关文章
- 【VS开发】OpenCV2:Mat属性type,depth,step
OpenCV2:Mat属性type,depth,step 在OpenCV2中Mat类无疑使占据着核心地位的,前段时间初学OpenCV2时对Mat类有了个初步的了解,见OpenCV2:Mat初学.这几天 ...
- html <input>标签类型属性type(file、text、radio、hidden等)详细介绍
html <input>标签类型属性type(file.text.radio.hidden等)详细介绍 转载请注明:文章转载自:[169IT-最新最全的IT资讯] html <inp ...
- OpenCV中Mat属性step,size,step1,elemSize,elemSize1
Mat的step,size,step1,elemSize,elemSize1这几个属性非常容易混淆. OpenCV的官方参考手册也没有解释清楚这几个概念. 前一段时间研究了一下每个属性的含义,如果有什 ...
- opencv::Mat属性
OpenCV支持JPG.PNG.TIFF等常见格式图像文件加载 加载图像 Mat imread( const String& filename, int flags = IMREAD_COLO ...
- OpenCV2:Mat
1.Mat基础 在计算机内存中,数字图像是已矩阵的形式保存的.OpenCV2中,数据结构Mat是保存图像像素信息的矩阵,它主要包含两部分:矩阵头和一个指向像素数据的矩阵指针. 矩阵头主要包含,矩阵尺寸 ...
- input属性type为file打开文件资源管理器时,如何限制多次选取或只能一次选取的行为
1.input标签没有设置multiple属性,文件资源管理器默认一次选取 <!doctype html> <html lang="en"> <hea ...
- 学习OpenCV2——Mat之通道的理解
本文详细介绍了opencv中涉及通道的知识,包括图像类型转换,通道合成分解,图像的显示. 来源:http://blog.csdn.net/GDFSG/article/details/50927257 ...
- vs2016 vsto excel addin deploy error: vsto 无法解析属性type的值
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ea33e391-21d7-4f54-92cb-c7af72f19c61/outlook- ...
- VS2015开发的Office Addin部署,安装时报错:无法解析属性“type”的值。
用VS2012开发的Outlook插件,在多数情况下安装正常,但是在某些机器上,安装时出现以下错误: 打开VSTOInstaller.exe.config文件查看,其中内容是: <?xml ve ...
随机推荐
- BigDecimal用法详解
一.简介Java在java.math包中提供的API类BigDecimal,用来对超过16位有效 位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更 ...
- 基于 Asp.Net的 Comet 技术解析
Comet技术原理 来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 简单的说是一种基于现 ...
- [翻译]理解Swift中的Optional
原文出处:Understanding Optionals in Swift 苹果新的Swift编程语言带来了一些新的技巧,能使软件开发比以往更方便.更安全.然而,一个很有力的特性Optional,在你 ...
- C#设计模式之组合
IronMan之组合 在上个篇幅中讲到怎么把“武器”装饰到“部件”上,这个篇幅呢,还是要讲到“武器”,不过呢是关于“武器”使用的. 本篇介绍"武器"的合理使用方式,不说废话,直接来 ...
- JS获取剪贴板图片之后的格式选择与压缩问题
前言 某年某月的某一天,突然发现博客服务器上上传的图片都比较大,一些很小的截图都有几百kb,本来服务器带宽就慢,不优化一下说不过去. 问题细述 特别说明:本文代码因为只是用于我自己后台写markdow ...
- 京东招聘Java开发人员
软件开发工程师(JAVA) 岗位职责: 1. 负责京东核心业务系统的需求分析.设计.开发工作 2. 负责相关技术文档编写工作 3. 解决系统中的关键问题和技术难题 任职要求: 1. 踏实诚恳.责任心强 ...
- Java 线程 — ThreadPoolExecutor
线程池 线程池处理流程 核心线程池:创建新线程执行任务,需要获取全局锁 队列:将新来的任务加入队列 线程池:大于corePoolSize,并且队列已满,小于maxPoolSize,创建新的worker ...
- webpack进阶构建项目(一)
webpack进阶构建项目(一) 阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解ba ...
- ExecuteReader在执行有输出参数的存储过程时拿不到输出参数
异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 后期会在博客首发更新:http://dnt.dkill.net/Article/D ...
- invalidate()和postInvalidate() 的区别及使用
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中 ...