【opencv14】cv::Mat---Desne数组类
1.cv::Mat类简介
cv::Mat类用于表示任意维度的dense数组。大多数图像数据都是存储在dense数组中,当然与之对应的就是sparse数组。
- dense数组:对于数组中的每个元素,内存中都存储了一个与当前元素对应的数据值,即使该元素值为零。
- sparse数组:存储的是非零项。如果许多元素值实际上为零,那么这会节省大量存储空间。(Opencv中永cv::SpareseMat类表述sparse数组。)
Note:若你对opencv2.1之前的版本较熟悉,你可能记得IplImage{IplImage}IplImage,CvMat{CvMat}CvMat。但在之后的版本中,这些类都没了,都被cv::Mat{cv::Mat}cv::Mat取代。
2.cv::Mat类中数据存储规则
cv::Mat类数据可以被用来表示各种维度的数组。数据存储在数组中,可以看作是一个n维的“光栅扫描顺序(raster scan order)”。
raster scan order解释:
在一维数组中,元素是顺序排列的。
在二维数组中,元素是被组织成行,每一行依次排列
在三维数组中,每一个平面可以认为二维数组,且每一个平面(二维数组)按行排列,且平面是一个接着一个。
每个数组都有一个标志元素,用来指示数组的内容。
- dim:指定数组维度
- rows/cols:指定数组的行数和列数(当dim>2时,这两个参数无效)
- 指针:指向数组数据存储位置的数据指针
- refcount:引用计数器,类似于利用cv::Ptr<>的引用计数器。该类成员的存在使得cv::Mat类能像数据智能指针一样被数据包含。
数据中的内存布局由数组step[]描述。cv::Mat类中,当下标为(i0,i1,’’’,iNd-1,iNd)时,数组的存储地址为:
对于二维数组而言:
cv::Mat中的每个数据元素本身可以是单个数字,也可以是多个数字。在多个数字的情况下,这个库称为多通道数组。事实上,n维数组和(n-1)维多通道数组实际上是非常相似的对象,但是由于在许多情况下,将数组看作向量值数组是有用的,比如图像而言通道为3表示彩色图像,通道为1表示灰度图像,所以库中对这种结构有特殊的规定。
在使用opencv2.1之前的版本中的IplImage{IplImage}IplImage时,有一个表征通道的成员变量:IplImage : :nChannels{IplImage\::\::nChannels}IplImage::nChannels。但在之后的版本中用cv::Mat类后,没有这个成员变量了,要查看通道数则需要调用cv::channels()。
要设置这种通道的区别的主要原因是内存访问。根据定义,数组的元素可以是向量值的部分。例如,一个数组可以被称为32位浮点数的二维三通道数组;在这种情况下,数组的元素是三个大小为12字节的32位浮点数。
当然在实际情况下,数据元素在内存中布局时,数组的行不是绝对按照顺序连续存放的;可能在行与行之间会有小的间隔。
这种填充的目的是提高内存访问速度。
n维单通道阵列与(n-1)维多通道阵列的区别在于,这种填充总是发生在完整行的末尾(也就是说,同一个通道中的元素总是顺序连续的)。
3.创建数组
cv::Mat m;
// Create data area for 3 rows and 10 columns of 3-channel 32-bit floats
m.create( 3, 10, CV_32FC3 );
// Set the values in the 1st channel to 1.0, the 2nd to 0.0, and the 3rd to 1.0
m.setTo( cv::Scalar( 1.0f, 0.0f, 1.0f ) );
可以利用cv::Mat类实例化一个变量来创建数组。当然利用这种方式创建的数组没有大小,也没有数据类型。在用这种方式创建数组后,之后可使用诸如create()这样的成员函数来分配数组大小,数据类型等参数。数组类型这一个参数决定了它具有哪种元素。
- 第一个位置参数:传入的是数组的行数,此例中表示数组3行
- 第二个位置参数:传入的是数组的列数,此例中表示数组10列
- 第三个位置参数:传入的是数组元素的类型,此例中32bit浮点数,3通道
第三个位置参数,即指定元素的基本类型,也指定通道数。所有可能的类型都在头文件中定义了,一共有6*3=18种可选方式(从如下组合中选取):CV_{8U,16S,16U,32S,32F,64F}{1,2,3}CV\_{\{8U,16S,16U,32S,32F,64F\}\{1,2,3\}}CV_{8U,16S,16U,32S,32F,64F}{1,2,3}
所以按照上述的例子CV_32FC3表示32bit的浮点数,3通道。
cv::Mat m( 3, 10, CV_32FC3, cv::Scalar( 1.0f, 0.0f, 1.0f ) );
如上述代码所示,前一段介绍的代码可以整合构造过程中,这是另一种构造函数(带参数的)。
理解数组中的数据没有严格地附加到数组对象上是至关重要的。Mat对象实际上是一个数据区域的标头,原则上是一个完全独立的东西。例如,可以将一个矩阵n赋值给另一个矩阵m(即m = n)。在这种情况下,m内部的数据指针将被改变为指向与n相同的数据,之前m的数据指针(如果有的话)所指向的数据将被释放。同时,它们现在共享的数据区域的引用计数器将增加。最后,将更新m的成员(例如行,列和标志),以准确描述m中数据现在指向的数据。 这一切使得这些行为变得很方便,其中数组可以彼此分配,并且在幕后自动执行此操作以提供正确的结果。
4.cv::Mat对象的构造函数
下表是cv::Mat类可用的构造函数的完整列表。当然大部分情况下,我们只会用到下表中的某几个。
操作 | 例子 |
---|---|
默认构造函数 | cv::Mat; |
按类型的2维矩阵构造函数 | cv::Mat( int rows, int cols, int type ); |
带初始化值的按类型的2维矩阵构造函数 | cv::Mat(int rows, int cols, int type,const Scalar& s); |
具有预先存在的数据的2维矩阵构造函数 | cv::Mat(int rows, int cols, int type,void* data, size_t step=AUTO_STEP); |
按类型的2维数组构造函数(大小以sz为单位) | cv::Mat( cv::Size sz, int type ); |
带初始化值的按类型的2维矩阵构造函数(大小以sz为单位) | cv::Mat(cv::Size sz,int type, const Scalar& s); |
具有预先存在的数据的2维矩阵构造函数(大小以sz为单位) | cv::Mat( cv::Size sz, int type,void* data, size_t step=AUTO_STEP) |
按类型的多维矩阵构造函数 | cv::Mat(int ndims, const int* sizes,int type); |
带初始化值的按类型的多维矩阵构造函数 | cv::Mat(int ndims, const int* sizes,int type, const Scalar& s); |
具有预先存在的数据的多维矩阵构造函数 | cv::Mat(int ndims, const int* sizes,int type, void* data,size_t step=AUTO_STEP); |
操作 | 例子 |
---|---|
拷贝构造函数 | cv::Mat( const Mat& mat ); |
仅拷贝指定行列的构造函数 | cv::Mat(const Mat& mat,const cv::Range&rows,const cv::Range&cols); |
仅拷贝指定区域的构造函数 | cv::Mat(const Mat& mat,const cv::Rect& roi); |
广义感兴趣区域复制构造函数,它使用范围数组从n维数组中进行选择 | cv::Mat(const Mat& mat,const cv::Range*ranges); |
复制构造函数,用其他矩阵的代数表达式的结果初始化m | cv::Mat( const cv::MatExpr&expr ); |
5.与旧版本之间的兼容问题
如果您正在维护包含C样式数据结构的opencv2.1版本之前的代码,您可能希望从现有的CvMat或IplImage结构创建新的C ++样式的cv :: Mat结构。 在这种情况下,我们有两个选择:
- 在现有的数据上构建一个标记头m(通过将copyData设置为false)
- 重新分配内存,并将老数据复制到m中(通过将copyData设置为true)
cv::Mat(
const CvMat* old,
bool copyData=false
);
cv::Mat(
const IplImage*
old,
bool copyData=false
);
6.模板构造函数
模板构造函数之所以被称之为模板构造函数,不是因为它们从cv::Mat构造出了一个模板类,而是因为它们从本身就是模板的东西(cv::Vec<>或cv::Matx<>),来创建cv::Mat类实例。所以模板构造函数能够用任意cv::Vec<>,cv::Matx<>类的实例来创建cv::Mat数组。或者将任意类型的STL库中的vector<>实例来构建相同类型的cv::Mat数组。
操作 | 例子 |
---|---|
从相同类型的cv :: Vec构造类型为T和大小为n的一维数组 | cv::Mat(const cv::Vec<T,n>&vec,bool copyData=true); |
从相同类型的cv :: Matx构造类型为T且大小为m×n的二维数组 | cv::Mat(const cv::Matx<T,m,n>&vec,bool copyData=true); |
从包含相同类型元素的STL向量构造类型为T的一维数组 | cv::Mat(const std::vector&vec,bool copyData=true); |
7.Mat类的静态成员函数
cv::Mat类提供一些能够创建常用类的静态成员函数。
//创建一个大小为rows×cols的cv :: Mat,其中所有的值为类型为type(CV_32F等)的零
cv::Mat::zeros( rows, cols, type );//创建一个大小为rows×cols的cv :: Mat,其中所有的值为类型为type(CV_32F等)的一
cv::Mat::ones( rows, cols, type);//单位矩阵
cv::Mat::eye( rows, cols, type);
【opencv14】cv::Mat---Desne数组类相关推荐
- cv::Mat 与 CvMat的区别
cv::Mat和CvMat都可以表示图像数据,只是却不明白他们之间到底什么区别,用CV::MAT 每次都有56byte的内存泄露.后来查看了源码才知道原来cv::Mat是一个类(Class),而CvM ...
- 【OpenCV3】cv::Mat类成员函数详解
cv::Mat为OpenCV2和OpenCV3中最重要的类,可以毫不夸张得说,掌握了cv::Mat的操作,就掌握了OpenCV大半,这里将详细的介绍下cv::Mat类的成员函数及其使用. 1.clon ...
- cv mat 灰度值和_OpenCV2:总结篇 cv::Mat 类
一.简介 在OpenCV中,可以用C++语法的Mat类来表示一张图像 也可以用C语法的lpllmage或CvMat结构体来表示一张图像 1.单通道像素值 2.多通道像素值 OpenCV默认颜色顺序为B ...
- OpenCV【零】—————cv::Mat——Mat对象创建方法
OpenCV (一)--Mat对象创建方法 目录 OpenCV (一)--Mat对象创建方法 1. cv::Mat优点及原理(本质类) 2. Mat类拷贝及对象的创建方法 3. Mat 对象元素的高效 ...
- opencv mat用数组初始化_10、OpenCV中图像和Mat类型(一)
Mat类型可以被认为是OpenCV库的核心. OpenCV库中绝大多数的函数都是Mat类的成员,以Mat作为参数,或者Mat作为返回值. Mat类用于表示任意维数的密集数组.即使对于数组中的该条目为零 ...
- 【OpenCV3】cv::Mat的定义与初始化
cv::Mat是OpenCV2和OpenCV3中基本的数据类型,在cv::Mat类中,关于cv::Mat的定义和初始化有多种不同的形式,这里,将对其进行详尽的总结和介绍. 一.无数据拷贝的cv::Ma ...
- OpenCv学习笔记(二)—cv Mat学习
由于在写上一篇图像的数据结构时,发现自己只知道CvMat,竟然还有Mat数据结构,真是无知了,看了这么多程序,貌似没有看到这个结构.有可能那些程序都是些老版本的例子,这是在2.0以后加上的,所以我也得 ...
- OpenCv中的cv::Mat::create()函数,cvRound(),cvFloor(),cvCeil()函数的详解l
文件说明: cv::create()函数的详解 函数原型: inline void Mat::create(int _rows, int _cols, int _type) inline void M ...
- cv::Mat初识和它的六种创建方法
cv::Mat 初识 Opencv种的Mat类,使得Opencv的编程更加的简单,程序员不用过多的去关注内存管理,并且发现Opencv的编程有点像不需要太多编程技术的Matlab一样,甚至有些函数 ...
- opencv 报错:Error: Assertion failed (data) in cv::Mat::at, file ... mat.inl.hpp, line 897(访问了不存在矩阵的像素)
文章目录 opencv4报错 原因 解决方法 opencv4报错 这是源代码: #include <opencv2/opencv.hpp> #include <iostream> ...
最新文章
- 由于授权协议中的一个错误,远程计算机中断了会话
- 为什么用 抽象类,接口
- IntelliJ IDEA版本和junit版本不适配
- 今日直播 | 全国高校人工智能人才与科技莫干山论坛直播来袭!
- boost::reverse_lock相关的测试程序
- java离线语音识别_你家的油烟机,可以语音控制了吗?
- Celo计划推出一种与欧元挂钩的新稳定币
- 罗翔 ---- 理想主义的花
- Struts2学习笔记(八) 拦截器(Interceptor)(上)
- 会场安排问题NYOJ14
- UML学习(一)类图和对象图
- c3p0连接池配置模板,SSM中使用c3p0连接池配置属性
- USACO 4.2 The Perfect Stall 完美的牛栏(最大匹配)
- 哥尼斯堡的“七桥问题”(欧拉回路)
- ylbtech-DBD-WeShop(微店)
- 你以为 CSS 只是个简单的布局?
- 《咸鱼分享》DNS轮询
- 德鲁克:优秀的管理者,都做到了这3点
- 自动换行 word-break:break-all和word-wrap:break-word
- 对图片进行等比例压缩