OpenCV大型阵列类型Mat类

匿名 (未验证) 提交于 2019-12-03 00:34:01

一、Mat类

Mat类是C++实现的OpenCV库的核心,表示一个N维度单通或多通道阵列,可以用来存储实数或复数值向量和数组,灰度或彩色图像,向量场,张量及直方图(当然高纬度的直方图存储在稀疏Mat类更合适),OpenCV是一个图像处理库。它包含大量的图像处理功能。为了解决计算上的挑战,大多数时候你最终会使用库的多个功能。因此,将图像传递给函数是一种常见的做法。我们不应该忘记,我们正在讨论图像处理算法,这些算法往往计算量很大。我们想要做的最后一件事是通过制作不必要的大型图像副本来进一步降低程序的速度。

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

1.1创建一个Mat对象

从上可以看出Mat基本上是一个包含两个数据部分的类:矩阵头(包含矩阵大小,用于存储的方法,存储矩阵的地址等信息)以及包含像素值(取决于选择用于存储的方法的任何维度)。矩阵头部大小是恒定的,但是矩阵本身的大小可能随着图像而变化,并且通常比数量级大。

创建一个Mat类型对象可以没有大小和数据类型,然后通过成员函数create()来分配指定,例如创建一个二维数组,可以使用create(int rows, int cols, types)备注:仅限于二维数组,第三个参数类型既指定了元素的类型又说明了通道数,这些类型都定义在矩阵头中,格式为:CV_{8U,16S,16U,32S,32F,64F}C{1,2,3},然后通过setTo()函数设定每个通道上的具体数值;

通常定义创建一个Mat类型的对象可以通过构造函数在创建矩阵时即分配内存,其中一个构造函数的参数与create()函数参数相同;

 1 //演示示例:创建一个Mat对象数组  2 #include <opencv2/highgui.hpp>  3 #include <opencv2/core.hpp>  4 #include <iostream>  5   6 using namespace std;  7 using namespace cv;  8   9 int main() 10 { 11     Mat array_test; 12     array_test.create( 3, 2, CV_32FC3 );       //create array header 13     array_test.setTo(Scalar(1.0f,2.0f,3.0f));   //set array data 14  15     cout << "array_test = " << endl << array_test << endl; 16     //如下使用构造函数等同上面分布创建 17     Mat array_test_con( 3, 2, CV_32FC3, Scalar(1.0f,2.0f,3.0f) ); 18     cout << "array_test_con = " << endl << array_test_con << endl; 19     return 0; 20 }

1.2 Mat类对象的数据和Mat类矩阵头

如上叙述,为了解决图像处理繁杂计算问题,OpenCV使用了一个引用计数系统。这个想法是,针对图像的数据,每个Mat对象都有自己的头部相对应,通过让它们的矩阵指针指向相同的地址而在它们的两个实例对象之间共享。而且,复制操作符只会复制标题和指向大矩阵的指针,而不是数据本身。

 1 //演示示例:矩阵头Array Header和矩阵数据Array data关系  2 #include <opencv2/highgui.hpp>  3 #include <opencv2/core.hpp>  4 #include <iostream>  5 using namespace std;  6 using namespace cv;  7    8 int main()  9 { 10     Mat A( 2, 2, CV_8UC3, Scalar(10, 20, 30)); 11   12     cout << "A = " << endl << A << endl; 13   14     cout << endl; 15   16     Mat B(A); 17     cout << "B = " << endl << B << endl; 18   19     cout << endl; 20   21     Mat C = A; 22     cout << "C = " << endl << C << endl; 23   24     cout << endl << "After Mat algebra..." << endl; 25   26     Mat A1( 2, 2, CV_8UC3, Scalar(1, 2, 3)); 27   28     A = A +A1; 29   30     cout << "A = " << endl << A << endl; 31     cout << "B = " << endl << B << endl; 32     cout << "C = " << endl << C << endl; 33   34     return 0; 35 }

上述所有对象最后指向相同的单一数据矩阵。然而,它们的标头是不同的,并且使用它们中的任何一个进行修改也会影响所有其他标签。实际上,不同的对象只是为相同的底层数据提供不同的访问方法。不过,它们的矩阵头部分是真正相互独立的。这样,可以创建一个仅包含矩阵数据的一部分的矩阵对象。例如,要在图像中创建感兴趣的区域(ROI),您只需创建一个带有新边界的新矩阵头:

 1 #include <opencv2/highgui.hpp>  2 #include <opencv2/core.hpp>  3 #include <iostream>  4   5 using namespace std;  6 using namespace cv;  7   8 int main()  9 { 10     Mat A( 4, 4, CV_8UC3, Scalar(10, 20, 30)); 11     cout << "A = " << endl << A << endl; 12  13     cout << endl; 14  15     Mat B(A); 16     cout << "B = " << endl << B << endl; 17  18     cout << endl; 19  20     Mat C = A; 21  22     cout << "C = " << endl << C << endl; 23  24     cout << endl << "After Mat algebra..." << endl; 25  26     Mat A1( 4, 4, CV_8UC3, Scalar(1, 2, 3)); 27  28     A = A +A1; 29  30     cout << "A = " << endl << A << endl; 31     cout << "B = " << endl << B << endl; 32     cout << "C = " << endl << C << endl; 33     //在图像中创建感兴趣的区域(ROI) 34     Mat D(A, Rect(0,0,2,2)); 35     cout << "D = " << endl << D << endl; 36  37     D.setTo(Scalar(1, 2, 3)); 38     cout << "A = " << endl << A << endl; 39  40     //创建一个带有新边界的新矩阵头 41     Mat E = A(Range::all(), Range(2,3)); 42     cout << "E = " << endl << E << endl; 43  44     E.setTo(Scalar(7, 8, 9)); 45     cout << "A = " << endl << A << endl; 46  47     return 0; 48 }

当想复制矩阵本身,所以OpenCV提供了cv :: Mat :: clone()和cv :: Mat :: copyTo()函数。

 1 #include <opencv2/highgui.hpp>  2 #include <opencv2/core.hpp>  3 #include <iostream>  4   5 using namespace std;  6 using namespace cv;  7   8 int main()  9 { 10     Mat A( 4, 4, CV_8UC3, Scalar(10, 20, 30)); 11     cout << "A = " << endl << A << endl; 12  13     cout << endl; 14  15     Mat B(A); 16     cout << "B = " << endl << B << endl; 17  18     cout << endl; 19   20     Mat C = A; 21     cout << "C = " << endl << C << endl; 22  23     cout << endl << "After Mat algebra..." << endl; 24  25     Mat A1( 4, 4, CV_8UC3, Scalar(1, 2, 3)); 26  27     A = A +A1; 28  29     cout << "A = " << endl << A << endl; 30     cout << "B = " << endl << B << endl; 31     cout << "C = " << endl << C << endl; 32   33     Mat D(A, Rect(0,0,2,2));      //拷贝构造函数中Rect仅适用于二维矩阵 34     cout << "D = " << endl << D << endl; 35  36     D.setTo(Scalar(1, 2, 3)); 37     cout << "A = " << endl << A << endl; 38  39     Mat E = A(Range::all(), Range(2,3)); //拷贝构造函数中Range 仅适用于二维矩阵 40     cout << "E = " << endl << E << endl; 41     E.setTo(Scalar(7, 8, 9)); 42     cout << "A = " << endl << A << endl; 43  44     Mat F = A.clone(); 45     cout << "F = " << endl << F << endl; 46  47     Mat G; 48     A.copyTo(G); 49     cout << "G = " << endl << G << endl; 50  51     A.setTo(Scalar(10, 20, 30)); 52     cout << "A = " << endl << A << endl; 53     cout << "F = " << endl << F << endl; 54     cout << "G = " << endl << G << endl; 55     return 0; 56 }

二、SpareMat类

针对稀疏矩阵,OpenCV定义了独立的数据结构SpareMat类。稀疏矩阵仅存储非零元素,避免了资源上的浪费,即将节省很多空间尤其针对元素存在许多零元素的数据, 使用稀疏矩阵的常用案例是直方图,对于直方图,大多数数据是零,存储这些零元素又是没有必要的。

三、数组常用操作

3.1两数组元素加权相加运算 AddWeighted()

1 void addWeighted( 2 InputArray src1,   //第一个输入矩阵 3 double alpha,      //第一个输入矩阵的权重 4 InputArray src2,   //第二个输入的矩阵 5 double beta,       //第二个输入矩阵的权重 6 double gamma,      //权重相加的偏移量 7 OutputArray dst,   //输出的结果 8 int dtype = -1)    //输出结果的类型

即加权的表达式如下:

Dst = α・src1 + β・src2 + γ

该函数可以用来实现alhpa融合(线性融合),即将公式中的γ设置为0,则alpha融合的公式演变为:

Dst = α・src1 + β・src2 = α・src1 + (1-α)・src2

函数中需要两个源图像src1和src2,这两个源图像可以是任意类型的像素(灰度,彩色),但只要他们属于同一类型一致即可,所输出的图像也是与源图像的像素类型一致;

注意:源图像可以是不同尺寸,但融合的操作区域(即感兴趣区域ROI)必须尺寸统一,否则OpenCV会产生错误;

 1 //alpha融合演示示例  2 #include <opencv2/highgui.hpp>  3 #include <iostream>  4   5 using namespace std;  6 using namespace cv;  7   8 int main()  9 { 10      //读取图像imread()显示图像imshow()函数待后续 11      Mat src1 = imread("D:\\workspace-qt\\OpenCV\\LinuxLogo.jpg"); 12      if(src1.empty()) {cout << "Can‘t Load the image..." << endl; return -1;} 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!