前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >独家|OpenCV 1.1 Mat - 基本图像容器(附链接)

独家|OpenCV 1.1 Mat - 基本图像容器(附链接)

作者头像
数据派THU
发布2023-03-29 13:16:06
6660
发布2023-03-29 13:16:06
举报
文章被收录于专栏:数据派THU数据派THU

代码语言:javascript
复制
翻译:陈之炎
校对:吴振东、林夕
本文约3600字,建议阅读10分钟本文为大家系统地介绍了OpenCV官方教程。

写在前边

让读者朋友们较为系统地了解和学习OpenCV官方教程,数据派THU翻译组联合研究部共同推出OpenCV官方教程翻译系列。由于所列章节较多,教程将被分为多篇文章持续更新发布。

原文链接:https://docs.opencv.org/4.5.2/de/d7a/tutorial_table_of_content_core.html

目标

我们可以通过多种方式从现实世界中获取数字图像,比如:数码相机、扫描仪、计算机扫描和磁共振成像等等。在这些情况中,虽然我们肉眼看到的是图像,但是当需要将图像在数字设备中变换传输时,图像的每个像素则对应一个数值。

例如,上述图像你可以看到一个汽车的后视镜,它可以用包含像素点强度值的矩阵来表示。虽然获取并存储像素点强度值的方法各不相同,但是图像在计算机中最终是以数值矩阵的形式来存储和处理的。OpenCV是一个计算机视觉库,主要用于处理和操作图像像素矩阵信息。因此,你首先需要熟悉OpenCV是如何存储和处理图像的。

Mat

OpenCV诞生于2001年。当时的库均是C语言接口创建,图像以C 语言的数据结构IplImage形式存储。在以往的教程和培训材料中均可以看到这一点,而这同时也反映出了C语言的优缺点。最大的挑战来自于手动的内存管理,它假设由用户来负责内存的分配和释放。对于代码量比较小的程序,手动分配内存没有问题。但是当代码量剧增时,处理起来的难度会急速增大。

幸运的是,C ++引入了类的概念,使得用户更容易实现自动内存管理。同时,C ++与C完全兼容,所以不存在兼容性问题,这也使代码迁移更加容易。OpenCV 2.0引入了一种新的C++接口,无需考虑内存管理问题,使得代码更加简洁,即利用更少的代码量,能够实现更多的功能。C ++接口的主要缺点是:目前许多嵌入式开发系统只支持C。因此,除非是针对嵌入式平台,否则没有必要使用的以往的老方法(除非你是受虐狂程序员,在自找麻烦)。

在使用Mat 时,需要知道的第一件事情是:无需手动分配内存。对于不再使用的内存,无需进行释放。大多数OpenCV函数会自动分配其输出数据。更为便捷的是,如果需要传递Mat 对象,则已经给它分配好了内存空间,可以被重用。换句话说,在任何时候都只用到执行任务所需要的内存,而无需进行额外的操作。

Mat基础类包含两部分数据:矩阵头(包括矩阵大小,存储方法,矩阵存储地址等信息)和指向一个矩阵的指针,这个矩阵包含了像素值信息(根据所选定的不同存储方法而有不同的维度)。矩阵头大小是一个常量,不同大小的图像的矩阵大小各不相同,通常矩阵大小要比图像大小大几个数量级。

OpenCV是一个图像处理库,其中包含大量图像处理函数。为了解决计算难题,多数情况下选用库中的多个函数来实现计算功能,常见的做法是将图像传递给函数。而图像处理算法的计算量往往非常大,所以要通过避免不必要的图像复制来进一步提升程序的运行速度。

为了解决上述问题, OpenCV采用了一种引用计数系统。具体做法是,每个Mat 对象有其各自的头,两个Mat 对象可以通过将矩阵指针指向同一地址来共享一个矩阵,复制操作只复制Mat 头和指向矩阵的指针,而不是复制数据本身。

上述所有的对象均指向同一个数据矩阵,对矩阵的任何变动均会影响所有的对象。在实际示例中,不同的对象只是对同一数据的不同的访问方式,尽管如此,不同MAT 对象的头各不相同。真正有趣的是,可以创建仅指向部分数据分段的MAT 对象头。例如,为了创建一个图像的感兴趣区域(ROI),你只需要创建一个具有行列边界的新MAT 对象头:

那么问题来了 - 如果像素矩阵可以属于多个MAT 对象, 那么当它不需要再次被使用时,由谁来负责清空?答案是:通过引用计数机制(reference counting mechanism)来实现,由最后一个使用它的对象来清空。每次拷贝MAT 对象头时,计数器便会加一;当对MAT 对象头进行清空时,此计数器会减一。当计数器的值为零时,矩阵会被释放。当需要对矩阵自身进行复制时, OpenCV提供cv::Mat::clone() 和cv::Mat::copyTo() 函数。

修改F或者G不会影响A所指向的矩阵,需要记住以下几点:

  • Opencv函数,输出图像分配时是自动的(除非另行规定);
  • 无需考虑OpenCV中C ++接口的内存管理;
  • 赋值操作符和拷贝构造函数仅复制MAT 对象头;
  • 图像的基本矩阵可以利用cv::Mat::clone() 和cv::Mat::copyTo()两个函数进行复制。

存储方法

本小节的内容是关于如何存储像素值的。你可以选择色彩空间和使用的数据类型。色彩空间是指为给定的颜色编码的色彩分量组合,最简单的色彩空间是灰度,它的颜色空间只有黑色和白色,这两种颜色可以组合出多种灰度。

为了使图像色彩更加丰富,色彩空间可以有更多的选择。每个色彩空间均可将其分解为三到四个基本颜色,利用这三到四个基本颜色的组合来生成其它颜色。主流的色彩空间是RGB,人类的眼睛正是利用RGB构建出多种色彩。其基本的颜色是红色、绿色和蓝色,为了对透明度进行编码,添加了第四个元素:α(A)。

除了RGB外,还有多种其它的色彩空间,它们各有优势:

  • RGB是与人眼类似的最为常见的色彩空间,但需要切记的是:OpenCV标准显示系统使用的色彩空间是BGR(互换了红色和蓝色通道);
  • HSV和HLS将色彩分解为色调、饱和度和亮度分量,利用这些分量,可以更加自然地对色彩进行描述。例如,去除最后一个分量之后,算法便对输入图像的光照条件不太敏感了;
  • JPEG图像格式使用的是YCrCb色彩空间;
  •  CIE L * A * B *是一个感知均匀的色彩空间,可以用它来测量给定的颜色到另一种颜色之间的距离。

在OpenCV中,每个组件都有其各自的有效域,即采用何种数据类型。组件的存储方式定义了对其有效域的控制方式。最小的数据类型是char,即一个字节或8比特位,char可以是无符号的(值从0到255)或带符号的(值从-127到+127)。在三元组色彩空间(如RGB 色彩空间),可以表示出1600万种颜色。此外,还可以通过使用float数据类型(4字节= 32比特位)或double数据类型(8字节= 64比特位),对色彩实现更为精细的控制和表达。但是,增加组件数据类型长度的同时也会增加整个图片占用的内存大小。

创建Mat对象

在调用、修改和保存图像教程中,你已经学会了如何利用cv::imwrite()函数 将矩阵写入图像文件之中。然而,出于调试的目的,为了更加方便地看到矩阵的实际值,可以直接使用<<运算符。注意,这仅适用于二维矩阵。

Mat作为一个图像容器非常不错,但是它也是一个通用矩阵类。所以,可以是一个通用矩阵类。为此,它还可以创建和操作多维矩阵。你可以用多种方式来创建Mat对象:

cv::Mat::Mat 构造器

对于二维和多通道图像,首先定义出大小:按行和列计数。

然后指定用于存储元素的数据类型和每个矩阵点的通道数。按照以下约定,构造出多个定义:

例如,CV_8UC3是指:使用的是8位长的unsigned char数据类型,每个像素具有三个通道,可以预定义多达四个通道。cv::Scalar是一个包含四个元素的短矢量。可以通过指定cv::Scalar,将所有的矩阵点初始化为自定义的值。如果需要创建更多的图像矩阵,还可以利用宏来创建,按照下述方式,设置括号中的通道数目:

构造C / C ++数组,并对其进行初始化

上述例子说明了如何创建一个维数大于2维的矩阵。首先指定其维数大小,然后传递一个包含每个维度大小的指针,其余部分保持不变。

不能用这种结构初始化矩阵值,如果新的矩阵大小与先前的矩阵大小不一致,会对矩阵数据的存储重新进行分配。

MATLAB风格初始化:cv::Mat::zeros , cv::Mat::ones , cv::Mat::eye 。指定矩阵大小和数据类型:

对于比较小的矩阵,可以使用逗号分隔初始化值或初始化值列表(支持C++ 11):

为现有的Mat对象创建一个新的Mat对象头:cv::Mat::clone or cv::Mat::copyTo。

可以利用CV :: RANDU()函数,为矩阵写入随机值,此时需要给定随机值的下限和上限:

输出格式化

在上面的例子中,可以看到默认的格式设置选项。OpenCV允许对矩阵输出进行格式化:

默认

Python 

逗号分隔值 (CSV)

NumPy

C

其他常见的输出

OpenCV中提供了通过<<操作输出常见的OpenCV数据结构:

二维Point

三维Point

 cv::Mat的std::vector

std::vector Point

小型控制台应用程序中均包含了这里的大多数示例。可以从这里下载或在CPP示例程序中找到它们。你还可以到YouTube网站看相应的视频演示。

YouTube网站

https:/www.youtube.com/watch%3fv=1tibU7vGWpk%22

编辑:王菁

校对:林亦霖

下一小节: 1.2 如何扫描图像、查找表和用OpenCV进行时间测量

译者简介

陈之炎,北京交通大学通信与控制工程专业毕业,获得工学硕士学位,历任长城计算机软件与系统公司工程师,大唐微电子公司工程师,现任北京吾译超群科技有限公司技术支持。目前从事智能化翻译教学系统的运营和维护,在人工智能深度学习和自然语言处理(NLP)方面积累有一定的经验。业余时间喜爱翻译创作,翻译作品主要有:IEC-ISO 7816、伊拉克石油工程项目、新财税主义宣言等等,其中中译英作品“新财税主义宣言”在GLOBAL TIMES正式发表。能够利用业余时间加入到THU 数据派平台的翻译志愿者小组,希望能和大家一起交流分享,共同进步

翻译组招募信息

工作内容:需要一颗细致的心,将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生,或在海外从事相关工作,或对自己外语水平有信心的朋友欢迎加入翻译小组。

你能得到:定期的翻译培训提高志愿者的翻译水平,提高对于数据科学前沿的认知,海外的朋友可以和国内技术应用发展保持联系,THU数据派产学研的背景为志愿者带来好的发展机遇。

其他福利:来自于名企的数据科学工作者,北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。

点击文末“阅读原文”加入数据派团队~

转载须知

如需转载,请在开篇显著位置注明作者和出处(转自:数据派ID:DatapiTHU),并在文章结尾放置数据派醒目二维码。有原创标识文章,请发送【文章名称-待授权公众号名称及ID】至联系邮箱,申请白名单授权并按要求编辑。

发布后请将链接反馈至联系邮箱(见下方)。未经许可的转载以及改编者,我们将依法追究其法律责任。

点击“阅读原文”拥抱组织

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据派THU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目标
  • Mat
  • 存储方法
  • 创建Mat对象
  • 输出格式化
  • 其他常见的输出
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档