专栏首页深度学习和计算机视觉【从零学习OpenCV 4】Mat类介绍

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

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

其实在最早的OpenCV 1.0版本中,图像使用名为IplImage的C语言结构体进行存储的,所以在很多比较老的OpenCV版本教程中常会看到其身影。但是使用IplImage类型存在需要用户手动释放内存的缺点,如果程序结束后存在没有释放内存的IplImage变量,就会造成内存泄漏的问题。值得庆幸的是,随着OpenCV版本的更新,OpenCV引入C++接口,提供Mat类用于存储数据,利用自动内存管理技术很好的解决了内存自动释放的问题,当变量不再需要时立即释放内存。

Mat类用来保存矩阵类型的数据信息,包括向量、矩阵、灰度或彩色图像等数据。Mat类分为矩阵头和指向存储数据的矩阵指针两部分。矩阵头中包含矩阵的尺寸、存储方法、地址和引用次数等。矩阵头的大小是一个常数,不会随着矩阵尺寸大小而改变。在绝大多数情况下矩阵头大小远小于矩阵中数据量的大小,因此图像复制和传递过程中主要的开销是存放矩阵数据。为了解决这个问题,在OpenCV中复制和传递图像时,只是复制了矩阵头和指向存储数据的指针,因此在创建Mat类时可以先创建矩阵头后赋值数据,其方法如代码清单2-1所示。

代码清单2-1 创建Mat类
cv::Mat a; //创建一个名为a的矩阵头
a = cv::imread(“test.jpg”); //向a中赋值图像数据,矩阵指针指向像素数据
cv::Mat b=a; //复制矩阵头,并命名为b

上面这段代码首先创建了一个名为a的矩阵头,之后读入一张图像并将a中的矩阵指针指向该图像的像素数据,最后将a矩阵头中的内容复制到b矩阵头中。虽然a、b有各自的矩阵头,但是其矩阵指针指向的是同一个矩阵数据,通过任意一个矩阵头修改矩阵中的数据,另一个矩阵头指向的数据也会跟着发生改变。但是当删除a变量时,b变量并不会指向一个空数据,只有当两个变量都删除后,才会释放矩阵数据。因为矩阵头中引用次数标记了引用某个矩阵数据的次数,只有当矩阵数据引用次数为0的时候才会释放矩阵数据。

提示

采用引用次数来释放存储内容是C++中常见的方式,用这种方式可以避免仍有某个变量引用数据时将这个数据删除造成程序崩溃的问题,同时极大的缩减了程序运行时所占用的内存。

接下来我们来了解Mat类里可以存储的数据类型,根据官方给出的Mat类继承图,如图2-2所示,我们发现Mat类可以存储的数据类型包含double、float、uchar、unsigned char以及自定义的模板等。

图2-2 Mat类继承关系图

我们可以通过代码清单2-2的方式声明一个存放指定类型的Mat类变量:

代码清单2-2 声明一个指定类型的Mat类
cv::Mat A = Mat_<double>(3,3);//创建一个3*3的矩阵用于存放double类型数据

由于OpenCV提出Mat类主要用于存储图像,而像素值的最大值又决定了图像的质量,如果用8位无符号整数去存储16位图像,会造成严重的图像颜色失真或造成数据错误。而由于不同位数的编译器对数据长度定义不同,为了避免在不同环境下因变量位数长度不同而造成程序执行问题,OpenCV根据数值变量存储位数长度定义了数据类型,表2-1中列出了OpenCV中的数据类型与取值范围。

表2-1 OpenCV中的数据类型与取值范围

数据类型

具体类型

取值范围

CV_8U

8位无符号整数

0—255

CV_8S

8位符号整数

-128—127

CV_16U

16位无符号整数

0-65535

CV_16S

16位符号整数

-32768—32767

CV_32S

32位符号整数

-2147483648—2147483647

CV_32F

32位浮点整数

-FLT_MAX—FLT_MAX, INF, NAN

CV_64F

64位浮点整数

-DBL_MAX—DBL_MAX, INF, NAN

仅有数据类型是不够的,还需要定义图像数据的通道(Channel)数,例如灰度图像数据是单通道数据,彩色图像数据是3通道或者4通道数据。因此针对这个情况,OpenCV还定义了通道数标识,C1、C2、C3、C4分别表示单通道、双通道、3通道和4通道。每一种数据类型都存在多个通道的情况,所以将数据类型与通道数表示结合便得到了OpenCV中对图像数据类型的完整定义,例如CV_8UC1表示的就是8位单通道数据,用于表示8位灰度图,而CV_8UC3表示的是8位3通道数据,用于表示8位彩色图。我们可以通过代码清单2-3的方式创建一个声明通道数和数据类型的Mat类:

代码清单2-3 通过OpenCV数据类型创建Mat类
cv::Mat a(640,480,CV_8UC3) //创建一个640*480的3通道矩阵用于存放彩色图像
cv::Mat a(3,3,CV_8UC1) //创建一个3*3的8位无符号整数的单通道矩阵
cv::Mat a(3,3,CV_8U) //创建单通道矩阵C1标识可以省略

注意

虽然在64位编辑器里,uchar和CV_8U都表示8位无符号整数,但是两者有严格的定义,CV_8U只能用在Mat类内部的方法。例如用Mat_<CV_8U>(3,3)和Mat a(3,3,uchar)会提示创建错误。

本文分享自微信公众号 - 小白学视觉(NoobCV)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-23

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • leetcode467. Unique Substrings in Wraparound String

    假设存在一个从a-z26个字母无限循环的字符串s,现在输入一个字符串p,问该字符串有多少个子字符串在s中循环出现?

    眯眯眼的猫头鹰
  • 推荐收藏 | 又有10道XGBoost面试题送给你

    对于不平衡的数据集,例如用户的购买行为,肯定是极其不平衡的,这对XGBoost的训练有很大的影响,XGBoost有两种自带的方法来解决:

    Sam Gor
  • 竞赛经验 | 一文梳理2019年腾讯广告算法大赛冠军方案

    作为从本次比赛共157队伍中脱颖而出的冠军方案,评分达到87.9683,从数据清洗、模型构建、目标优化等有非常多值得学习的地方。比赛团队也挺有意思,分别来自哈工...

    Sam Gor
  • 集合三大类无模型强化学习算法,BAIR开源RL代码库rlpyt

    2013 年有研究者提出使用深度强化学习玩游戏,之后不久深度强化学习又被应用于模拟机器人控制,自此以后大量新算法层出不穷。其中大部分属于无模型算法,共分为三类:...

    机器之心
  • leetcode481. Magical String

    这题是描述了一个魔法字符串,该字符串完全由数字1和2构成。这个字符串的魔法点在于,如果将该该字符串连续的数字数量进行统计并且构成一个新的字符串,会发现新的字符串...

    眯眯眼的猫头鹰
  • 深入探寻JAVA8 part1:函数式编程与Lambda表达式

    在很久之前粗略的看了一遍《Java8 实战》。客观的来,说这是一本写的非常好的书,它由浅入深的讲解了JAVA8的新特性以及这些新特性所解决的问题。最近重新拾起这...

    眯眯眼的猫头鹰
  • 520 页机器学习笔记!放假期间继续充电!

    前段时间,来自SAP(全球第一大商业软件公司)的梁劲(Jim Liang)公开了自己所写的一份 520 页的学习教程(英文版),详细、明了地介绍了机器学习中的相...

    Sam Gor
  • 比Tiny YOLOv3小8倍,性能提升11个点,4MB的网络也能做目标检测

    目标检测在计算机视觉领域是一个活跃的研究分支,而深度学习已经成为这一领域最前沿也是最成功的解决方案。但是,在边缘和移动设备中广泛部署神经网络模型需要大量的计算算...

    机器之心
  • 企业应用架构模式中的层次模型简介

    企业对外提供服务,通常借助于软件应用。比如交易零售系统,用来提供购买商品的服务,这里就涉及到交易数据,这些数据会被用户“反复”的产生、查看,而且随着服务时间增长...

    爬蜥
  • leetcode435. Non-overlapping Intervals

    使用二维数组表示区间组,每一个子数组的第一个值表示区间的开始坐标,第二个值表示区间的结束坐标。计算最少进行多少次删除操作,可以确保剩下的区间不会产生任何重叠。

    眯眯眼的猫头鹰

扫码关注云+社区

领取腾讯云代金券