本文首发于“小白学视觉”微信公众号,欢迎关注公众号

本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究!


经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

前一小节已经介绍了三种构造Mat类变量的方法,但是后两种没有给变量初始化赋值,本小节将重点介绍如何灵活的构造并赋值Mat类变量。根据OpenCV的源码定义,关于Mat类的构造方式共有二十余种,然而在平时一些简单的应用程序中很多复杂的构造方式并没有太多的用武之地,因此本书重点讲解笔者在学习和做项目中常用的构造与赋值方式。

Mat类的构造

(1)利用默认构造函数

代码清单2-4 默认构造函数使用方式
cv::Mat::Mat();

通过代码清单2-4,利用默认构造函数构造了一个Mat类,这种构造方式不需要输入任何的参数,在后续给变量赋值的时候会自动判断矩阵的类型与大小,实现灵活的存储,常用于存储读取的图像数据和某个函数运算输出结果。

(2)根据输入矩阵尺寸和类型构造

代码清单2-5 利用矩阵尺寸和类型参数构造Mat类
cv::Mat::Mat( int  rows,int  cols,int  type)

rows:构造矩阵的行数

cols:矩阵的列数

type:矩阵中存储的数据类型。此处除了CV_8UC1、CV_64FC4等从1到4通道以外,还提供了更多通道的参数,通过CV_8UC(n)中的n来构建多通道矩阵,其中n最大可以取到512.

这种构造方法我们前文也见过,通过输入矩阵的行、列以及存储数据类型实现构造。这种定义方式清晰、直观、易于阅读,常用在明确需要存储数据尺寸和数据类型的情况下,例如相机的内参矩阵、物体的旋转矩阵等。利用输入矩阵尺寸和数据类型构造Mat类的方法存在一种变形,通过将行和列组成一个Size()结构进行赋值,代码清单2-6中给出了这种构造方法的原型。

代码清单2-6 用Size()结构构造Mat类
cv::Mat::Mat(Size size(),int  type)

size:2D数组变量尺寸,通过Size(cols, rows)进行赋值。

type:与代码清单2-5中的参数一致

利用这种方式构造Mat类时要格外注意,在Size()结构里矩阵的行和列的顺序与代码清单2-5中的方法相反,使用Size()时,列在前、行在后。如果不注意同样会构造成功Mat类,但是当我们需要查看某个元素时,我们并不知道行与列颠倒,就会出现数组越界的错误。使用该种方法构造函数如下:

代码清单2-7 用Size()结构构造Mat示例
cv::Mat a(Size(480, 640), CV_8UC1); //构造一个行为640,列为480的单通道矩阵
cv::Mat b(Size(480, 640), CV_32FC3); //构造一个行为640,列为480的3通道矩

(3)利用已有矩阵构造

代码清单2-8 利用已有矩阵构造Mat类
cv::Mat::Mat( const Mat & m);
m:已经构建完成的Mat类矩阵数据。

这种构造方式非常简单,可以构造出与已有的Mat类变量存储内容一样的变量。注意这种构造方式只是复制了Mat类的矩阵头,矩阵指针指向的是同一个地址,因此如果通过某一个Mat类变量修改了矩阵中的数据,另一个变量中的数据也会发生改变。

提示

如果想复制两个一模一样的Mat类而彼此之间不会受影响,可以使用m=a.clone()实现。

如果需要构造的矩阵尺寸比已有矩阵小,并且存储的是已有矩阵的子内容,那么可以用代码清单2-9中的方法进行构建:

代码清单2-9 构造已有Mat类的子类
cv::Mat::Mat(const Mat & m,const Range & rowRange,const Range & colRange = Range::all())

m:已经构建完成的Mat类矩阵数据。

rowRange:在已有矩阵中需要截取的行数范围,是一个Range变量,例如从第2行到第5行可以表示为Range(2,5)。

colRange:在已有矩阵中需要截取的列数范围,是一个Range变量,例如从第2列到第5列可以表示为Range(2,5),当不输入任何值时表示所有列都会被截取。

这种方式主要用于在原图中截图使用,不过需要注意的是,通过这种方式构造的Mat类与已有Mat类享有共同的数据,即如果两个Mat类中有一个数据发生更改,另一个也会随之更改。使用该种方法构造Mat类如代码清单2-10中所示。

代码清单2-9 构造已有Mat类的子类
cv::Mat::Mat(const Mat & m,const Range & rowRange,const Range & colRange = Range::all())

Mat类的赋值

构建完成Mat类后,变量里并没有数据,需要将数据赋值给它。针对不同情况,OpenCV 4.1提供了多种赋值方式,接下来将介绍如何给Mat类变量进行赋值。

(1)构造时赋值

代码清单2-11 在构造时赋值的方法
cv::Mat::Mat(int  rows,int  cols,int  type,const Scalar & s)

rows:矩阵的行数

cols:矩阵的列数

type:存储数据的类型

s:给矩阵中每个像素赋值的参数变量,例如Scalar(0, 0, 255)。

该种方式是在构造的同时进行赋值,将每个元素想要赋予的值放入Scalar结构中即可,这里需要注意的是,用此方法会将图像中的每个元素赋值相同的数值,例如Scalar(0, 0, 255)会将每个像素的三个通道值分别赋值0,0,255。我们可以使用如下的形式构造一个已赋值的Mat类

代码清单2-12 在构造时赋值示例
cv::Mat a(2, 2, CV_8UC3, cv::Scalar(0,0,255));//创建一个3通道矩阵,每个像素都是0,0,255
cv::Mat b(2, 2, CV_8UC2, cv::Scalar(0,255));//创建一个2通道矩阵,每个像素都是0,255
cv::Mat c(2, 2, CV_8UC1, cv::Scalar(255)); //创建一个单通道矩阵,每个像素都是255

我们在程序return语句之前加上断点进行调试,用Image Watch查看每一个Mat类变量里的数据,结果如图2-3所示,证明我们已成功构造矩阵并赋值。

图2-3 使用Scalar结构给Mat类赋值结果  

提示

Scalar结构中变量的个数一定要与定义中的通道数相对应,如果Scalar结构中变量个数大于通道数,则位置大于通道数之后的数值将不会被读取,例如执行a(2, 2, CV_8UC2, Scalar(0,0,255))后,每个像素值都将是(0,0),而255不会被读取。如果Scalar结构中变量数小于通道数,则会以0补充。

(2)枚举赋值法

这种赋值方式是将矩阵中所有的元素都一一枚举出,并用数据流的形式赋值给Mat类。具体赋值形式如代码清单2-13所示。

代码清单2-13 利用枚举法赋值示例
cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat b = (cv::Mat_<double>(2, 3) << 1.0, 2.1, 3.2, 4.0, 5.1, 6.2);

上面第一行代码创建了一个3×3的矩阵,矩阵中存放的是从1-9的九个整数,先将矩阵中的第一行存满,之后再存入第二行、第三行,即1、2、3存放在矩阵a的第一行,4、5、6存放在矩阵a的第二行,7,8,9存放在矩阵a的第三行。第二行代码创建了一个2×3的矩阵,其存放方式与矩阵a相同。

提示

采用枚举法时,输入的数据个数一定要与矩阵元素个数相同,例如代码清单2-13中第一行代码只输入从1到8八个数,赋值过程会出现报错,因此本方法常用在矩阵数据比较少的情况。

(3)循环赋值

与通过枚举法赋值方法相类似,循环法赋值也是对矩阵中的每一位元素进行赋值,但是可以不在声明变量的时候进行赋值,而且可以对矩阵中的任意部分进行赋值。具体赋值形式如代码清单2-14所示。

代码清单2-14 利用枚举法赋值示例
cv::Mat c = cv::Mat_<int>(3, 3); //定义一个3*3的矩阵
for (int i = 0; i < c.rows; i++) //矩阵行数循环
{for (int j = 0; j < c.cols; j++) //矩阵列数循环{c.at<int>(i, j) = i+j;}
}

上面代码同样创建了一个3×3的矩阵,通过for循环的方式,对矩阵中的每一位元素进行赋值。需要注意的是,在给矩阵每个元素进行赋值的时候,赋值函数中声明的变量类型要与矩阵定义时的变量类型相同,即上面代码中第1行和第6行中变量类型要相同,如果第6行代码改成c.at<double>(i, j) ,程序就会报错,无法赋值。

(4)类方法赋值

在Mat类里提供了可以快速赋值的方法,可以初始化指定的矩阵。例如生成单位矩阵、对角矩阵、所有元素都为0或者1的矩阵等。具体使用方法如代码清单2-15所示。

代码清单2-15 利用类方法赋值示例
cv::Mat a = cv::Mat::eye(3, 3, CV_8UC1);
cv::Mat b = (cv::Mat_<int>(1, 3) << 1, 2, 3);
cv::Mat c = cv::Mat::diag(b);
cv::Mat d = cv::Mat::ones(3, 3, CV_8UC1);
cv::Mat e = cv::Mat::zeros(4, 2, CV_8UC3);

上面代码中,每个函数作用及参数含义分别如下:

eye():构建一个单位矩阵,前两个参数为矩阵的行数和列数,第三个参数为矩阵存放的数据类型与通道数。如果行和列不相等,则在矩阵的 (1,1),(2,2),(3,3)等主对角位置处为1。

diag():构建对角矩阵,其参数必须是Mat类型的1维变量,用来存放对角元素的数值。

ones():构建一个全为1的矩阵,参数含义与eye()相同。

zeros():构建一个全为0的矩阵,参数含义与eye()相同。

(5)利用数组进行赋值

这种方法与枚举法相类似,但是该方法可以根据需求改变Mat类矩阵的通道数,可以看作枚举法的拓展,在代码清单2-16中给出了这种方法的赋值形式。

代码清单2-16 利用数组赋值示例
float a[8] = { 5,6,7,8,1,2,3,4 };
cv::Mat b = cv::Mat(2, 2, CV_32FC2, a);
cv::Mat c = cv::Mat(2, 4, CV_32FC1, a);

这种赋值方式首先将需要存入到Mat类中的变量存入到一个数组中,之后通过设置Mat类矩阵的尺寸和通道数将数组变量拆分成矩阵,这种拆分方式可以自由定义矩阵的通道数,当矩阵中的元素数目大于数组中的数据时,将用-1.0737418e+08填充赋值给矩阵,如果矩阵中元素的数目小于数组中的数据时,将矩阵赋值完成后,数组中剩余数据将不再赋值。由数组赋值给矩阵的过程是首先将矩阵中第一个元素的所有通道依次赋值,之后再赋值下一个元素,为了更好的体会这个过程,我们将定义的b和c矩阵在图2-4中给出。

图2-4 矩阵b和c中存储的数据  

《OpenCV 4开放详解》往期推荐

【从零学习OpenCV 4】Windows系统中安装OpenCV 4

【从零学习OpenCV 4】Ubuntu系统中安装OpenCV 4

【从零学习OpenCV 4】opencv_contrib扩展模块的安装

【从零学习OpenCV 4】Image Watch插件的使用

经过几个月的努力,市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》将于今年12月左右由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持!

关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。

【从零学习OpenCV 4】Mat类构造与赋值相关推荐

  1. opencv4 c++ 提取图片中的白色区域_修正!【从零学习OpenCV 4】分割图像——分水岭法...

    点击上方"小白学视觉",选择"星标"公众号重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开 ...

  2. cv2.error: opencv(4.4.0)_【从零学习OpenCV 4】图像金字塔

    点击上方"小白学视觉",选择"星标"公众号 重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习Open ...

  3. 【从零学习OpenCV 4】4种读取Mat类元素的的方法

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  4. 【从零学习OpenCV 4】Mat类介绍

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  5. OpenCV 之 Mat 类

    数字图像可看作一个数值矩阵, 其中的每个元素代表一个像素点,如下图所示: OpenCV 中,用 Mat 来表示该数值矩阵,它是很关键的一种数据结构,因为 OpenCV 中的大部分函数都和 Mat 有关 ...

  6. 快速系统从零学习OpenCV 4路线图

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 转眼间,小白学视觉就要成立三周年了,小白一直是很感谢小伙伴们的支持 ...

  7. 【从零学习OpenCV 4】Image Watch插件的使用

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...

  8. 【从零学习openCV】IOS7下的人脸检測

    前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...

  9. opencv利用矩形框选中某一区域_【从零学习OpenCV】4Ubuntu系统中安装OpenCV 4

    经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<从零学习OpenCV 4>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分 ...

最新文章

  1. SQL SERVER中的三种获得自增长ID的方法
  2. LeetCode题组:第121题-买卖股票的最佳时机
  3. 计算机基础综合实验项目报告模板,计算机基础实验报告模板.doc
  4. 【Python基础】Python安装第三方库太慢?配置好这个速度飞起
  5. 推荐系统里,你是怎么Embedding的?
  6. 这不是特效也不是魔术!
  7. android canvas 网络图,【巨坑:toDataURL】canvas合成网络图片
  8. 爬虫-urlparse与urlsplit
  9. c语言电子地图程序,C语言 电子地图信息
  10. Opengl编程指南第二章:状态管理、几何绘图
  11. mysql 非英文_非英文网站如何使用MySQL的字符集
  12. VS code不用集成终端如何修改并推送分支?
  13. 蚂蚁金服研究员何征宇:系统软件和开源都是手段,不是目的
  14. Unity3D占用内存太大的解决方法
  15. 测试方法之JUnit单元测试
  16. 船务公司简称与缩写一览表
  17. 微信公众号选择什么服务器好,微信开发选择订阅号还是服务号好?
  18. 雅虎邮箱客户端服务器设置
  19. 解决U8库龄分析报表数量与实际结存数量不一致问题
  20. 游戏建模控件Aspose.3D for Java最新版支持在Wavefront OBJ中添加点云支持

热门文章

  1. 一键fxxk,代码修复神器拯救你
  2. 普元王葱权:数字化时代需要新一代的大数据应用平台架构
  3. 算法 | 动画+解析,轻松理解「Trie树」
  4. Uber无人车撞人视频公布,究竟哪儿出问题了?
  5. 是的,网络身份证来了!一堆技术和安全上的麻烦事也来了
  6. HashMap源码实现分析
  7. Java并发编程:JMM和volatile关键字
  8. 数据分析师在岗3年小结!
  9. 数据分析利器Jupyter Notebook!
  10. Datawahle文化衫来了!