OpenCV Mat类详解和用法(官网原文)
参考文章:OpenCV Mat类详解和用法
我马克一下,日后更
官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_image_container.html
opencv3.2.0全套教程
文章目录
- 20211124 上面那篇文章也太长了吧,看完得几个小时呢!这里就做些简单笔记吧!
- 全文 OpenCV Mat类详解和用法
- 目标
- Mat(包含矩阵大小、存储方法、矩阵存储地址的矩阵头和一个指向包含像素值的矩阵的指针)
- 重点
- 存储方法
- 显式创建 Mat 对象
- cv::Mat::Mat构造函数
- 使用 C/C++ 数组并通过构造函数初始化
- cv::Mat::create函数:
- MATLAB 样式初始值设定项:cv::Mat::zeros、cv::Mat::ones、cv::Mat::eye。指定要使用的大小和数据类型:
- 对于小矩阵,您可以使用逗号分隔的初始值设定项:
- 为现有的Mat对象和cv::Mat::clone或cv::Mat::copyTo创建一个新头部(header)
- cv::randu()函数用随机值填充矩阵
- 输出格式
- 默认
- Python(python风格会把一个像素点的不同通道像素值组合成组显示,比默认显示风格更加清晰)
- 逗号分隔值(Comma separated values) (CSV)(额,,这种风格连括号都懒得给你打印了)
- Numpy(Numpy风格挺详细,连数据类型都给你打印出来了)
- C
- 其他常用项目的输出
- 二维点
- 3D点
- std::vector via cv::Mat
- std::vector of points
20211124 上面那篇文章也太长了吧,看完得几个小时呢!这里就做些简单笔记吧!
Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等) 的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。
不行还是全文拷贝过来吧,因为重点内容太多了!
全文 OpenCV Mat类详解和用法
目标
我们有多种方法可以获得从现实世界的数字图像:数码相机、扫描仪、计算机体层摄影或磁共振成像就是其中的几种。在每种情况下我们(人类)看到了什么是图像。但是,转换图像到我们的数字设备时我们的记录是图像的每个点的数值。
例如在上图中你可以看到车的镜子只是一个包含所有强度值的像素点矩阵。现在,我们如何获取和存储像素值可能根据最适合我们的需要而变化,最终可能减少计算机世界内的所有图像数值矩阵和一些其他的信息的描述基质本身。OpenCV 是一个计算机视觉库,其主要的工作是处理和操作,进一步了解这些信息。因此,你需要学习和开始熟悉它的第一件事是理解OpenCV 是如何存储和处理图像。
Mat(包含矩阵大小、存储方法、矩阵存储地址的矩阵头和一个指向包含像素值的矩阵的指针)
OpenCV 自 2001 年出现以来。在那些日子里库是围绕C接口构建的。在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像。这是您将在大多数较旧的教程和教材中看到的那个。使用这个结构的问题是将 C 语言的所有负面效果都摆到了桌面上。最大的问题是手动管理。它是建立在用户来负责处理内存分配和解除分配的假设之上的。当程序规模较小时,这是没有问题的,一旦代码基开始变得越来越大它将会越来越挣扎着处理所有这一切而不是着眼于实际解决自己的开发目标。
幸运的是 c + + 出现了,并引入了类的概念,使得为用户开辟另一条路成为可能:
自动内存管理 (或多或少)。好消息是,c + +,如果完全兼容 C 所以进行更改时没有兼容性问题产生。因此, OpenCV其2.0 版本引入一个新的c + + 接口,通过利用这些优点将为你的工作提供新的方法。某种程度上,在其中您不需要拨弄内存管理让你的代码简洁 (写得更少,实现的更多)。C + + 接口的唯一主要缺点在于,目前许多嵌入式的开发系统支持仅 C.因此,除非您的目标是这一平台,否则就没有理由再使用旧的方法(除非你是个受虐狂程序员和喜欢自讨苦吃)。
你需要知道的关于Mat的第一件事是你不再需要手动分配其大小并且当你不需要它的时候你不再需要手动释放它。虽然这样做仍然是可能的,大多数 OpenCV 函数将手动分配其输出数据。还有一个额外的好处是如果传递一个已存在Mat对象,它已经为矩阵分配所需的空间,这段空间将被重用。也就是说我们在任何时候只使用与我们执行任务时所必须多的内存一样多的内存。
Mat本质上是由两个数据部分组成的类: (包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等)
的矩阵头和一个指针,指向包含了像素值的矩阵(可根据选择用于存储的方法采用任何维度存储数据)。矩阵头部的大小是恒定的。然而,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。因此,当你在您的程序中传递图像并在有些时候创建图像副本您需要花费很大的代价生成图像矩阵本身,而不是图像的头部。OpenCV
是图像处理库,它包含大量的图像处理函数。若要解决的计算挑战,最终大部分时间你会使用库中的多个函数。由于这一原因图像传给库中的函数是一种常见的做法。我们不应忘记我们正在谈论往往是计算量相当大的图像处理算法。我们想要做的最后一件事是通过制作不必要的可能很大的图像的拷贝进一步降低您的程序的速度。
为了解决这一问题 OpenCV 使用引用计数系统
。其思想是Mat的每个对象具有其自己的头,但可能他们通过让他们矩阵指针指向同一地址的两个实例之间共享该矩阵。此外,拷贝运算符将只能复制矩阵头部,也还将复制指针到大型矩阵,但不是矩阵本身。
Mat A, C; //仅创建了头部
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //在此我们知道使用的方法(分配矩阵)
Mat B(A); //使用拷贝构造函数
C = A; //赋值运算符
上文中的所有对象,以相同的单个数据矩阵的结束点。他们头不同,但是使用的其中任何一个对矩阵进行任何修改,也将影响所有其他的。在实践中的不同对象只是提供相同的底层数据不同的访问方法,然而,它们的头部是不同的。真正有趣的部分是您可以创建仅指向完整数据的一小部分的头。例如,要在图像中创建兴趣区域 ( ROI)
您只需创建一个新头设置新边界:
Mat D (A, Rect(10, 10, 100, 100) ); // 用矩形界定 (x1, y1)(x2, y2)?Mat E = A(Range:all(), Range(1,3)); // 用行和列来界定(这个用不了不知怎么回事?)
现在,你可能会问是否矩阵的本身可以属于多个Mat对象在不再需要时负责清理数据。简短的回答是:最后一个使用它的对象。这对于使用引用计数的机制,每当有人复制Mat对象的头,矩阵的计数器被增加。每当一个头被清除,此计数器被下调。当该计数器变为零,矩阵也就被释放了。因为有时会仍然也要复制矩阵的本身,存在着 clone() 或 copyTo() 函数。
Mat F = A.clone();
Mat G;
A.copyTo(G);
现在修改F或G不会影响Mat头指向的矩阵。你需要记住的是:
重点
• 输出图像分配 OpenCV 功能是自动 (除非另行指定,否则)。• 用c + + OpenCV的接口就无需考虑内存释放。• 赋值运算符和复制构造函数 (构造函数)只复制头。• 使用clone () 或copyTo () 函数将复制的图像的基础矩阵。
存储方法
这是关于您如何存储像素值。您可以选择颜色空间
和使用的数据类型
。颜色空间是指我们如何组合颜色分量以对给定颜色进行编码。最简单的一种是灰度,我们可以使用的颜色是黑色和白色。这些的组合使我们能够创建许多灰色阴影。
对于丰富多彩的方式,我们有更多的方法可供选择。他们每个人都将其分解为三个或四个基本组件,我们可以使用这些组件的组合来创建其他组件。最受欢迎的是RGB,主要是因为这也是我们的眼睛构建颜色的方式。它的基色是红色、绿色和蓝色。为了编码颜色的透明度,有时会添加第四个元素:alpha (A)。
然而,还有许多其他颜色系统,每一个都有自己的优势:
- RGB 是最常见的,因为我们的眼睛使用类似的东西,但请记住,
OpenCV 标准显示系统使用 BGR 色彩空间(红色和蓝色通道的切换)组合颜色
。 - HSV 和 HLS 将颜色分解为它们的色调、饱和度和值/亮度分量,这是我们描述颜色的更自然的方式。例如,您可能会忽略最后一个组件,使您的算法对输入图像的光照条件不太敏感。
- 流行的 JPEG 图像格式使用 YCrCb(
YUV
)。 - CIE Lab* 是感知上均匀的颜色空间,如果您需要测量给定颜色到另一种颜色的距离,它会派上用场。
每个建筑组件都有自己的有效域。这导致使用的数据类型。我们如何存储组件定义了我们对其域的控制。可能的最小数据类型是char,这意味着 1 个字节或 8 位。这可能是无符号的(因此可以存储从 0 到 255 的值)或有符号的(从 -127 到 +127 的值)。虽然在三个组件的情况下,这已经提供了 1600 万种可能的颜色来表示(如在 RGB 的情况下)我们可以通过使用浮点数(4 字节 = 32 位)或双精度浮点型(8 字节 = 64 位)数据获得更精细的控制每个组件的类型。尽管如此,请记住,增加组件的大小也会增加内存中整个图片的大小。
显式创建 Mat 对象
在加载、修改和保存图像教程中,您已经学习了如何使用cv::imwrite()函数将矩阵写入图像文件。但是,出于调试目的,查看实际值要方便得多。您可以使用Mat的 <<
运算符执行此操作。请注意,这仅适用于二维矩阵。
尽管Mat作为图像容器非常有效,但它也是一个通用的矩阵类。因此,可以创建和操作多维矩阵。您可以通过多种方式创建 Mat 对象:
cv::Mat::Mat构造函数
Mat M(2,2, CV_8UC3, Scalar(0,0,255));cout << "M = " << endl << " " << M << endl << endl;
我640×360的图片打印了好久才打印完。。。
对于二维和多通道图像,我们首先定义它们的大小:行和列计数。
然后我们需要指定用于存储元素的数据类型和每个矩阵点的通道数。为此,我们根据以下约定构造了多个定义:
CV_[每项的位数][有符号或无符号][类型前缀]C[通道编号]
例如,CV_8UC3意味着我们使用 8 位长的 unsigned char 类型,并且每个像素具有其中的三个以形成三个通道。这是为最多四个通道编号预定义的。该cv::Scalar是四个元件短矢量。指定此项,您可以使用自定义值初始化所有矩阵点。如果您需要更多,您可以使用上面的宏创建类型,在括号中设置通道号,如下所示。
使用 C/C++ 数组并通过构造函数初始化
int sz[3] = {2,2,2};Mat L(3,sz, CV_8UC(1), Scalar::all(0));
上面的例子展示了如何创建一个多于二维的矩阵。指定其维度,然后传递一个包含每个维度大小的指针,其余保持不变。
(这L存的是什么数据,我用std::cout打印不出来怎么回事,还报错)
cv::Mat::create函数:
M.create(4,4, CV_8UC(2));cout << "M = "<< endl << " " << M << endl << endl;
您无法使用此构造初始化矩阵值。如果新大小不适合旧大小,它只会重新分配其矩阵数据内存。
MATLAB 样式初始值设定项:cv::Mat::zeros、cv::Mat::ones、cv::Mat::eye。指定要使用的大小和数据类型:
Mat E = Mat::eye(4, 4, CV_64F);cout << "E = " << endl << " " << E << endl << endl;Mat O = Mat::ones(2, 2, CV_32F);cout << "O = " << endl << " " << O << endl << endl;Mat Z = Mat::zeros(3,3, CV_8UC1);cout << "Z = " << endl << " " << Z << endl << endl;
E =[1, 0, 0, 0;0, 1, 0, 0;0, 0, 1, 0;0, 0, 0, 1]O =[1, 1;1, 1]Z =[ 0, 0, 0;0, 0, 0;0, 0, 0]
对于小矩阵,您可以使用逗号分隔的初始值设定项:
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);cout << "C = " << endl << " " << C << endl << endl;
为现有的Mat对象和cv::Mat::clone或cv::Mat::copyTo创建一个新头部(header)
Mat RowClone = C.row(1).clone();cout << "RowClone = " << endl << " " << RowClone << endl << endl;
cv::randu()函数用随机值填充矩阵
笔记
您可以使用cv::randu()函数用随机值填充矩阵。您需要为随机值提供下限值和上限值:
Mat R = Mat(3, 2, CV_8UC3);randu(R, Scalar::all(0), Scalar::all(255));cout << "R = " << endl << " " << R << endl << endl;
输出结果:
R =[ 91, 2, 79, 179, 52, 205;236, 8, 181, 239, 26, 248;207, 218, 45, 183, 158, 101]
输出格式
在上面的示例中,您可以看到默认格式选项。但是,OpenCV 允许您格式化矩阵输出:
默认
cout << "R (default) = " << endl << R << endl << endl;
结果同上
Python(python风格会把一个像素点的不同通道像素值组合成组显示,比默认显示风格更加清晰)
cout << "R (python) = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;
R (python) =
[[[ 91, 2, 79], [179, 52, 205]],[[236, 8, 181], [239, 26, 248]],[[207, 218, 45], [183, 158, 101]]]
逗号分隔值(Comma separated values) (CSV)(额,,这种风格连括号都懒得给你打印了)
cout << "R (csv) = " << endl << format(R, Formatter::FMT_CSV) << endl << endl;
R (csv) =91, 2, 79, 179, 52, 205
236, 8, 181, 239, 26, 248
207, 218, 45, 183, 158, 101
Numpy(Numpy风格挺详细,连数据类型都给你打印出来了)
cout << "R (numpy) = " << endl << format(R, Formatter::FMT_NUMPY ) << endl << endl;
R (numpy) =
array([[[ 91, 2, 79], [179, 52, 205]],[[236, 8, 181], [239, 26, 248]],[[207, 218, 45], [183, 158, 101]]], dtype='uint8')
C
cout << "R (c) = " << endl << format(R, Formatter::FMT_C ) << endl << endl;
R (c) =
{ 91, 2, 79, 179, 52, 205,236, 8, 181, 239, 26, 248,207, 218, 45, 183, 158, 101}
其他常用项目的输出
OpenCV 也通过 << 运算符提供对其他常见 OpenCV 数据结构的输出的支持:
二维点
Point2f P(5, 1);cout << "Point (2D) = " << P << endl << endl;
Point (2D) = [5, 1]
3D点
Point3f P3f(2, 6, 7);cout << "Point (3D) = " << P3f << endl << endl;
Point (3D) = [2, 6, 7]
std::vector via cv::Mat
vector<float> v;
v.push_back((float)CV_PI);
v.push_back(2);
v.push_back(3.01f);
cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;
std::vector of points
vector<Point2f> vPoints(20);
for (size_t i = 0; i < vPoints.size(); ++i)vPoints[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "A vector of 2D Points = " << vPoints << endl << endl;
A vector of 2D Points = [0, 0;5, 1;10, 2;15, 3;20, 4;25, 5;30, 6;35, 0;40, 1;45, 2;50, 3;55, 4;60, 5;65, 6;70, 0;75, 1;80, 2;85, 3;90, 4;95, 5]
这里的大多数示例都包含在一个小型控制台应用程序中。您可以从这里或在 cpp 示例的核心部分下载它。
您还可以在YouTube 上找到有关此的快速视频演示。
OpenCV Mat类详解和用法(官网原文)相关推荐
- OpenCV Mat类详解和用法
OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...
- 微软符号服务器opencv的符号,Opencv Mat类详解和用法1
Mat OpenCV 自 2001 年出现以来.在那些日子里库是围绕C接口构建的.在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像.这是您将在大多数较旧的教程和教材中看到的那个. ...
- OpenCV Mat类详解
光心:每个透镜主轴上都有一个特殊点,凡是通过该点的光,其传播方向不变,这个点叫光心. 光线经过透镜后不会发生折射,仍然沿原方向射出. 基础矩阵(Fundamental matrix)是一个3×3的矩阵 ...
- OpenCV参考手册之Mat类详解
OpenCV参考手册之Mat类详解(一) OpenCV参考手册之Mat类详解(二) OpenCV参考手册之Mat类详解(三)
- OpenCV参考手册之Mat类详解1
Mat类 OpenCV c + + n 维稠密数组类 class CV_EXPORTS Mat { public: / / - -很多的方法... ... /*!包括几位字段: -神奇的签名 -连续性 ...
- OpenCV参考手册之Mat类详解(一)
Mat类 OpenCV c + + n 维稠密数组类 class CV_EXPORTS Mat { public: / / - -很多的方法... ... /*!包括几位字段: -连续性标志 -深度( ...
- ubuntu 16.04 官网版安装 caffe 步骤详解[CPU][紧跟官网,永不踩坑]
Reference: CPU: https://www.youtube.com/watch?v=DnIs4DRjNL4 GPU: Part1: https://www.youtube.com/watc ...
- 图文详解如何从官网下载Hadoop安装包
在把Hadoop的坑都踩了之后 的第二天,终于在MacBook Pro上安装了Hadoop伪分布式系统.我将用详细的步骤把安装Hadoop的过程分享出来,Mac系统上亲测成功,使用windows的小伙 ...
- OpenCV参考手册之Mat类详解(三)
Mat::eye 返回一个恒等指定大小和类型矩阵. C++: static MatExpr Mat::eye(int rows, int cols, inttype) C++: static MatE ...
最新文章
- GDCM:gdcm::Preamble的测试程序
- win10下cmd ping不通虚拟机,xshell连不上虚拟机【如果实在想不出来原因,就看看吧】
- JavaScript中的全局变量介绍
- Nhibernate.hbm2ddl.auto配置详解
- 匿名管道和pipe函数
- c访问excel 密码 api_管理EXCEL的5种服务使用渠道
- 仿QQ锁屏界面消息提示
- 今天tiktok小社群更新 第5个项目行业案例
- Oracle-1:的列操作(增加列,修改列,删除列),包括操作多列
- win7 vmware ubuntu16 xshell链接
- The ‘state_publisher‘ executable is deprecated. Please use ‘robot_state_publisher‘ instead
- 肌电信号 原始信号 积分_实验室人必看!复杂的色谱峰要如何正确积分?
- 深入理解java:2.3.4. 并发编程concurrent包 之容器ConcurrentLinkedQueue(非阻塞的并发队列---循环CAS)...
- 台达伺服B2 调机杂说
- 智慧交通综合管理平台建设方案
- 苹果显示器(Apple Cinema Display)亮度调节方法
- APP运营推广:新APP建设之后该怎么做好品牌运营?
- 纯电动汽车快慢充原理介绍
- MD5加密和SHA256加密
- 绘图与滤镜全面解析--Quartz 2D 、Core Image