翻译:陈之炎
校对:吴振东、林夕本文约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对象
在调用、修改和保存图像教程中&#xff0c;你已经学会了如何利用cv::imwrite()函数 将矩阵写入图像文件之中。然而&#xff0c;出于调试的目的&#xff0c;为了更加方便地看到矩阵的实际值&#xff0c;可以直接使用<<运算符。注意&#xff0c;这仅适用于二维矩阵。
Mat作为一个图像容器非常不错&#xff0c;但是它也是一个通用矩阵类。所以&#xff0c;可以是一个通用矩阵类。为此&#xff0c;它还可以创建和操作多维矩阵。你可以用多种方式来创建Mat对象&#xff1a;
cv::Mat::Mat 构造器
对于二维和多通道图像&#xff0c;首先定义出大小&#xff1a;按行和列计数。
然后指定用于存储元素的数据类型和每个矩阵点的通道数。按照以下约定&#xff0c;构造出多个定义&#xff1a;
例如&#xff0c;CV_8UC3是指&#xff1a;使用的是8位长的unsigned char数据类型&#xff0c;每个像素具有三个通道&#xff0c;可以预定义多达四个通道。cv::Scalar是一个包含四个元素的短矢量。可以通过指定cv::Scalar&#xff0c;将所有的矩阵点初始化为自定义的值。如果需要创建更多的图像矩阵&#xff0c;还可以利用宏来创建&#xff0c;按照下述方式&#xff0c;设置括号中的通道数目&#xff1a;
构造C / C &#43;&#43;数组&#xff0c;并对其进行初始化
上述例子说明了如何创建一个维数大于2维的矩阵。首先指定其维数大小&#xff0c;然后传递一个包含每个维度大小的指针&#xff0c;其余部分保持不变。
不能用这种结构初始化矩阵值&#xff0c;如果新的矩阵大小与先前的矩阵大小不一致&#xff0c;会对矩阵数据的存储重新进行分配。
MATLAB风格初始化&#xff1a;cv::Mat::zeros , cv::Mat::ones , cv::Mat::eye 。指定矩阵大小和数据类型&#xff1a;
对于比较小的矩阵&#xff0c;可以使用逗号分隔初始化值或初始化值列表&#xff08;支持C&#43;&#43; 11&#xff09;&#xff1a;
为现有的Mat对象创建一个新的Mat对象头&#xff1a;cv::Mat::clone or cv::Mat::copyTo。
注
可以利用CV :: RANDU&#xff08;&#xff09;函数&#xff0c;为矩阵写入随机值&#xff0c;此时需要给定随机值的下限和上限&#xff1a;
输出格式化
在上面的例子中&#xff0c;可以看到默认的格式设置选项。OpenCV允许对矩阵输出进行格式化&#xff1a;
默认
Python
逗号分隔值 (CSV)
NumPy
C
其他常见的输出
OpenCV中提供了通过<<操作输出常见的OpenCV数据结构&#xff1a;
二维Point
三维Point
cv::Mat的std::vector
std::vector Point
小型控制台应用程序中均包含了这里的大多数示例。可以从这里下载或在CPP示例程序中找到它们。你还可以到YouTube网站看相应的视频演示。
YouTube网站
https:/www.youtube.com/watch%3fv&#61;1tibU7vGWpk%22
编辑&#xff1a;王菁
校对&#xff1a;林亦霖
下一小节: 1.2 如何扫描图像、查找表和用OpenCV进行时间测量
译者简介
陈之炎&#xff0c;北京交通大学通信与控制工程专业毕业&#xff0c;获得工学硕士学位&#xff0c;历任长城计算机软件与系统公司工程师&#xff0c;大唐微电子公司工程师&#xff0c;现任北京吾译超群科技有限公司技术支持。目前从事智能化翻译教学系统的运营和维护&#xff0c;在人工智能深度学习和自然语言处理&#xff08;NLP&#xff09;方面积累有一定的经验。业余时间喜爱翻译创作&#xff0c;翻译作品主要有&#xff1a;IEC-ISO 7816、伊拉克石油工程项目、新财税主义宣言等等&#xff0c;其中中译英作品“新财税主义宣言”在GLOBAL TIMES正式发表。能够利用业余时间加入到THU 数据派平台的翻译志愿者小组&#xff0c;希望能和大家一起交流分享&#xff0c;共同进步
翻译组招募信息
工作内容&#xff1a;需要一颗细致的心&#xff0c;将选取好的外文文章翻译成流畅的中文。如果你是数据科学/统计学/计算机类的留学生&#xff0c;或在海外从事相关工作&#xff0c;或对自己外语水平有信心的朋友欢迎加入翻译小组。
你能得到&#xff1a;定期的翻译培训提高志愿者的翻译水平&#xff0c;提高对于数据科学前沿的认知&#xff0c;海外的朋友可以和国内技术应用发展保持联系&#xff0c;THU数据派产学研的背景为志愿者带来好的发展机遇。
其他福利&#xff1a;来自于名企的数据科学工作者&#xff0c;北大清华以及海外等名校学生他们都将成为你在翻译小组的伙伴。
点击文末“阅读原文”加入数据派团队~
转载须知
如需转载&#xff0c;请在开篇显著位置注明作者和出处&#xff08;转自&#xff1a;数据派ID&#xff1a;DatapiTHU&#xff09;&#xff0c;并在文章结尾放置数据派醒目二维码。有原创标识文章&#xff0c;请发送【文章名称-待授权公众号名称及ID】至联系邮箱&#xff0c;申请白名单授权并按要求编辑。
发布后请将链接反馈至联系邮箱&#xff08;见下方&#xff09;。未经许可的转载以及改编者&#xff0c;我们将依法追究其法律责任。
点击“阅读原文”拥抱组织