您的位置:首页 > 大数据 > 人工智能

2.0-OpenCV核心--图片容器 (Mat - The Basic Image Container)

2017-03-30 09:22 295 查看
本文摘自 OpenCV官方英文文档

您将学习如何在内存和存储图像如何打印内容输出到控制台。

Mat: 图片容器

 

目标



我们有多种方法从现实世界中获取数字图像:数码相机、扫描器、计算机断层扫描和磁共振成像等等。在每种case里,人们都可以看见这些图片。然而,我们数码设备记录图片的数值都是点。

例如在上面的图片你可以看到汽车的镜子,只不过是一个包含所有的像素点的强度值矩阵.我们如何根据我们的不同的需要去

获取和存储像素值,但是在最后计算机在电脑世界里可能被简化为了数值矩阵和其它信息描述这个矩阵本身。

OpenCV 是一个计算机视觉库,主要的重点就是处理和操作这些信息   。因此,你需要熟悉的第一件事就是OpenCV商店和如何处理图像。

Mat

自2001年以来OpenCV已经存在。在这些日子里,这个库是被建立在C接口上的并且用内存来存储图片,它们使用C的结构体被叫做IplImage。你会看到IplImage在大多数老的教程和教材里。这里的问题是,它带来的是C语言的缺点。最大的问题是手动内存管理。它建立在用户负责关注内存分配和重分配。虽然这不是一个问题规模在比较小型的项目里,但是一旦你的代码量很多,它将很难处理而不能去关注开发目标了。

幸运的是c++来了,介绍了类的概念,使用户更容易为通过自动内存管理(或多或少)。好消息是,c++是完全兼容C,所以没有兼容性问题产生变化。因此OpenCV2.0引入了C++的接口提供一个新的方法去搞事。那就意味着你不需要去搞内存管理了,让你的代码更简洁,写的更少,实现的内容更多。C++接口的负面是许多嵌入式的开发系统,目前只支持C。因此,除非你是针对嵌入式平台,那样你就得用老的方法。(除非你是一个受虐狂的程序员,你自找麻烦,脑残偏偏要用C)

第一件事,你需要了解Mat是你不需要手动去申请和释放内存。尽管这样做仍然是一种可能,大部分OpenCV的功能会自动分配输出数据的。作为一个奖励你需要传递一个存在的Mat对象,这个Mat是已分配所需的空间存储矩阵,这将会重复利用。换句话说我们只使用在任何时候尽可能多的有内存,来执行我们的工作。

Mat有两个主要的数据部分,矩阵头(包含信息如矩阵的大小,用于存储的方法,存储矩阵的地址,等等)。

一个指向包含像素值的矩阵(采取任何维度取决于选择存储的方法)。矩阵头的大小是恒定的

然而矩阵本身的大小可能会有所不同,从图像到图像,并且通常是更大的数量级。

OpenCV是一个图像处理库。它包含了许多采集和处理图片的功能。解决一个计算的挑战,大部分的时间你会最终使用的多个函数库。因为如此,传递图片的功能是一个常用的练习。我们不应该忘记,我们谈论的是图像处理算法,这往往是相当计算重量级的计算。这样就是我们想要做的最后一件事是,进一步降低程序的速度,制造不必要的潜在的大图像的副本。

OpenCV使用引用计数系统来解决这个问题。我们的想法是,每个Mat对象有自己的头,然而矩阵可能是他们通过矩阵的两个实例之间共享指针指向同一个地址。而且复制操作符只会复制标题和大型矩阵的指针,不会是数据本身。

Mat A, C; // createsjust the header parts 创建仅仅是头部分

// here we'll know themethod used (allocate matrix) 这里我们知道方法的使用,分配矩阵

A = imread(argv[1],IMREAD_COLOR);

Mat B(A); // Use thecopy constructor  使用拷贝构造

C = A; // Assignmentoperator 分配运算符

 

所有的对象,在最后指向同一个单独的数据矩阵。他们的头是不同的,然而使用其中任何一个做出修改,都会影响到所有其他的。

在实践中不同的对象,提供不同的访问方法对于相同的基本数据。然而,他们的头部分是不同的。

所有的对象,在最后指向同一个单独的数据矩阵。他们的头是不同的,然而使用其中任何一个做出修改,都会影响到所有其他的。

在实践中不同的对象,提供不同的访问方法对于相同的基本数据。然而,他们的头部分是不同的。真正有趣的部分是,您可以创建头指向只有一个小部分的完整数据。例如,在一个图片上创建一个感兴趣的区域(ROI)
。你仅仅创建一个新的头与新的边界就行。

Mat D (A, Rect(10,10, 100, 100) ); // using a rectangle           创建一个矩形

Mat E = A(Range::all(), Range(1,3)); // using row and column boundaries 
使用行和列的边界

现在你可能会问,如果矩阵本身可能属于多个Mat 对象,谁负责啊清理它当它不在被需要?。最简单的答案是最后一个用它的对象。这是由使用引用计数机制来处理的。无论什么时候什么人拷贝一个Mat对象的头,一个引用计数会对于矩阵进行增加。当计数达到零,它就释放了。有时候你将想拷贝矩阵本身,所以OpenCV提供了两个方法 cv::Mat::clone()andcv::Mat::copyTo()

 

Mat G;

A.copyTo(G);

现在修改F或是G,不会影响矩阵头。你需要记住这些

输出图像分配对于OpenCV功能是自动的(除非特定说明)
你不需要想内存管理,因为OpenCV是C++的接口
赋值运算符和拷贝构造函数只复制的是头。
图像根本的矩阵可能被拷贝用这两个函数cv::Mat::clone() and cv::Mat::copyTo()

存储方法

       

这是如何存储像素值。你可以选择颜色空间和使用数据类型。颜色空间指的是,我们如何结合颜色组件来把颜色变成代码。最简单的一个是灰度,我们的处理是黑色和白色。这些组合使我们能够创造许多深浅不同的灰色

对于丰富多彩的方式,我们有更多的方法选择。他们每个都会分解为三或四个基本组成部分,我们可以使用这些组合创建其它的。最流行的是RGB,主要是因为这也是我们的眼睛建立的颜色。它的底色是红,绿,蓝。要编码颜色的透明度,有时会添加四分之一个元素:alpha(a)

然而,还有许多其他颜色系统都有自己的有点:

•RGB是最常见的,因为我们的眼睛使用类似的东西,但请记住,OpenCV标准显示系统使用BGR颜色空间(红色和蓝色通道的开关)组成颜色。

•HSV和HLS将颜色分解为色调,饱和度和值/亮度分量,这是我们描述颜色的更自然的方式。例如,您可能会忽略最后一个组件,使您的算法对输入图像的光线条件不太敏感。

•YCrCb被流行的JPEG图像格式使用。

•CIE L * a * b *是感知统一的色彩空间,如果您需要测量给定颜色与其他颜色的距离,则可方便使用。
每个组成构件都有自己的有效域。 这导致使用了数据类型。 我们如何存储组件定义,我们在其域中的控件。可能的最小数据类型是char,这意味着一个字节或8位。 这可能是无符号的(因此可以存储从0到255的值)或带符号(从-127到+127的值)。尽管在三个组件的情况下,这已经提供了1600万个可能的颜色来表示(像在RGB情况下),我们可以通过使用浮点数(4字节= 32位)或双(8字节= 64位)数据来获得更精细的控制 每个组件的类型。 然而,请记住,增加组件的大小也会增加内存中整个画面的大小


明确创建Mat对象在加载,修改和保存图像教程中,您已经学习了如何使用cv :: imwrite()函数,将矩阵写入图像文件。 但是,为了调试目的,查看实际值更为方便。 您可以使用Mat的操作符<<来执行此操作。 请注意,这仅适用于二维矩阵。虽然Mat作为一个图像容器非常好,但它也是一个通用的矩阵类。 因此,可以创建和操纵多维矩阵。 您可以通过多种方式创建Mat对象:

cv::Mat::Mat Constructor

Mat M(2,2, CV_8UC3, Scalar(0,0,255));

cout << "M = " << endl << " " << M << endl <<endl;




对于二维和多通道图像,我们首先定义它们的大小:行和列数明智。

然后,我们需要指定用于存储元素的数据类型和每个矩阵点的通道数。为此,我们根据以下约定构造了多个定义:

CV_[The number of bits per item][Signed orUnsigned][Type Prefix]C[The channel number]


CV_ [每个项目的位数] [有无符号 [类型前缀] C [通道号]

例如,CV_8UC3意味着我们使用8位长的无符号字符类型,每个像素有三个形成三个通道。这是最多四个通道号预定义的。 cv :: Scalar是四元素 短向量。 指定这一点,您可以使用自定义值初始化所有矩阵点。如果您需要更多功能,您可以使用上部宏来创建类型,在括号中设置通道号,如下所示。
 

•使用C / C ++数组并通过构造函数进行初始化int sz[3] ={2,2,2};

Mat L(3,sz, CV_8UC(1),Scalar::all(0));


上面的例子显示了如何创建一个具有两维以上的矩阵。 指定其维度,然后传递一个包含每个维的大小的指针,其余的保持不变。·       

cv::Mat::createfunction:

M.create(4,4, CV_8UC(2));

cout << "M= "<< endl << " "<< M << endl << endl;




您无法使用此结构初始化矩阵值。 如果新的大小不适合旧的,它将仅重新分配其矩阵数据存储器。

·        MATLAB 样式初始化: cv::Mat::zeros, cv::Mat::ones, cv::Mat::eye. 指定要使用的大小和数据类型:MatE = 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;




•对于小矩阵,您可以使用逗号分隔的初始化器:

Mat C = (Mat_<double>(3,3) <<0, -1, 0, -1, 5, -1, 0, -1, 0);

cout << "C= " << endl << " "<< C << endl << endl;




·为现有的Matobject使用cv :: Mat :: clone cv :: Mat :: copyTo创建一个新头。

Mat RowClone = C.row(1).clone();

cout << "RowClone= " << endl << " "<< RowClone << endl << endl;




Note

您可以使用cv :: randu()函数填入随机值的矩阵。
您需要给出随机值的较小值和最高值:

Mat R = Mat(3,2, CV_8UC3);

randu(R,Scalar::all(0), Scalar::all(255));


输出格式

在上面的例子中,您可以看到默认格式化选项。
然而,OpenCV允许您格式化矩阵输出:

Default

cout << "R(default) = " << endl << R << endl << endl;




Python

cout << "R(python) = " << endl << format(R,Formatter::FMT_PYTHON) << endl << endl;




Comma separated values (CSV)

cout << "R(csv) = " << endl << format(R,Formatter::FMT_CSV ) << endl << endl;




Numpy

cout << "R(numpy) = " << endl << format(R,Formatter::FMT_NUMPY ) << endl << endl;




C

cout << "R(c) = " << endl << format(R,Formatter::FMT_C ) << endl << endl;




其他常用项目的输出

OpenCV还通过<< operator来支持其他常用OpenCV data结构的输出:

2D Point
Point2fP(5, 1);

cout << "Point(2D) = " << P << endl << endl;




3D Point
Point3fP3f(2, 6, 7);

cout << "Point(3D) = " << P3f << endl << endl;




std::vector via
cv::Mat
vector<float> v;

v.push_back( (float)CV_PI);v.push_back(2); v.push_back(3.01f);

cout << "Vectorof 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 << "Avector of 2D Points = " << vPoints << endl <<endl;




这里的大多数样品已被包含在小型的应用程序中。您可以从cpp示例的核心部分中从此处下载。here
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐