OpenCV(2)Mat-基本图像容器 C++

18 篇文章 9 订阅

1.Mat-基本图像容器

我们有多种方式从现实世界中获取数字图像:数码相机,扫描仪,计算机断层扫描和磁共振成像等等。在任何情况下,我们(人类)看到的都是图像。然而,当将其转换为数字设备时,我们记录的是图像中每个点的数值。

在这里插入图片描述

Mat A, C;                          // creates just the header parts
A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix)
Mat B(A);                          // Use the copy constructor
C = A;                             // Assignment operator

1.2.存储方法

这是关于如何存储像素值。您可以选择使用的颜色空间和数据类型。颜色空间是指我们如何组合颜色分量以编码给定的颜色。最简单的一个是灰色,我们可以使用的颜色是黑色和白色。这些组合使我们能够创建许多灰色阴影。

对于丰富多彩的方式,我们有更多的选择方法。他们每个人都将它们分解成三到四个基本组件,我们可以使用这些组合来创建其他组件。最流行的是RGB,主要是因为这也是我们的眼睛如何建立颜色。其基色为红,绿,蓝。为了编码颜色的透明度有时是第四个元素:添加了α(A)。
然而,还有许多其他颜色系统都有自己的优势:

  • RGB是最常见的,因为我们的眼睛使用类似的东西,但请记住,OpenCV标准显示系统使用BGR颜色空间(红色和蓝色通道的开关)组成颜色。
  • HSV和HLS将颜色分解为色调,饱和度和值/亮度分量,这是我们描述颜色的更自然的方式。例如,您可能会忽略最后一个组件,使您的算法对输入图像的光线条件不太敏感。
  • YCrCb被流行的JPEG图像格式使用。
  • CIE L * a * b *是感知统一的颜色空间,如果您需要测量给定颜色与其他颜色的距离,则可方便使用。

每个建筑组件都有自己的有效域。这导致使用的数据类型。我们如何存储组件定义了我们在其域中的控件。可能的最小数据类型是char,这意味着一个字节或8位。这可能是无符号的(因此可以存储从0到255的值)或带符号(从-127到+127的值)。尽管在三个组件的情况下,这已经提供了1600万个可能的颜色来表示(像在RGB情况下),我们可以通过使用浮点数(4字节= 32位)或双(8字节= 64位)数据来获得更精细的控制每个组件的类型。然而,请记住,增加组件的大小也会增加内存中整个画面的大小。

1.3.明确创建一个Mat对象

在加载,修改和保存图像教程中,您已经学习了如何使用cv :: imwrite()函数将矩阵写入图像文件。但是,为了调试目的,查看实际值更为方便。您可以使用Mat的“操作符”来执行此操作。请注意,这仅适用于二维矩阵。

虽然Mat作为一个图像容器非常好,但它也是一个通用的矩阵类。因此,可以创建和操纵多维矩阵。您可以通过多种方式创建Mat对象:#

1. (cv :: Mat :: Mat)构造函数
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    //构造函数构建
    Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));    
    cout << " M = " << endl << "" << M << endl << endl;
    return 0;
}

执行结果:

M =
 [  0,   0, 255,   0,   0, 255;
    0,   0, 255,   0,   0, 255]

对于二维和多通道图像,我们首先定义它们的大小:行和列数明智。
然后,我们需要指定用于存储元素的数据类型和每个矩阵点的通道数。为此,我们根据以下约定构造了多个定义:

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

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

  • 使用C / C ++数组并通过构造函数进行初始化
  int sz[3] = {2,2,2};
    Mat L(3,sz, CV_8UC(1), Scalar::all(0));

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

2. (cv :: Mat :: create)函数构建
  • cv :: Mat :: create function:
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    //Create函数构建
    Mat M;
    M.create(4, 4, CV_8UC(2));
    cout << " M = " << endl << "" << M << endl << endl;
    return 0;
}

执行结果:

 M =
[116,   0,  46,   0,  79,   0, 102,   0;
 102,   0, 105,   0,  99,   0, 101,   0;
  46,   0,  68,   0, 101,   0, 115,   0;
 107,   0, 116,   0, 111,   0, 112,   0]

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

  • MATLAB样式初始化器:cv :: Mat :: zeros,cv :: Mat :: ones,cv :: Mat :: eye。指定要使用的大小和数据类型:
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    //用matlab创建 1或0矩阵
    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;
    return 0;
}

执行结果:

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]

3.对于小矩阵,您可以使用逗号分隔的初始化器或初始化器列表(在最后一种情况下需要C ++ 11支持):
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    //创建一个3x3双精度单位矩阵
    Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << "" << C << endl << endl;
    return 0;
}
  C =(Mat_ <double>{0-1,0-1,5-1,0-1,0}))。reshape(3;
    cout << “C =<< endl << “”“ << C << endl << endl;

执行结果:

C =
[0, -1, 0;
 -1, 5, -1;
 0, -1, 0]
4. 为现有的Mat对象和(cv :: Mat :: clone)或(cv :: Mat :: copyTo)创建一个新标题。
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    #ifdef CV_CXX11
        //! [list]
        Mat C;
        C = (Mat_<double>({ 0, -1, 0, -1, 5, -1, 0, -1, 0 })).reshape(3);
        cout << "C = " << endl << "" << C << endl << endl;
        //! [list]
    #endif
        //! [clone]
        Mat RowClone = C.row(1).clone();
        cout << "RowClone = " << endl << " " << RowClone << endl << endl;
        //! [clone]
        return 0;
}

执行结果:

C =
[0, -1, 0;
 -1, 5, -1;
 0, -1, 0]

RowClone =
[-1, 5, -1]

1.4.输出格式

使用cv :: randu()函数填入随机值的矩阵。您需要给出随机值的较低和较高值:
您可以看到默认的格式化选项。然而,OpenCV允许您格式化矩阵输出:

1. Default
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    //用随机值填充一个矩阵
    Mat R = Mat(3, 2, CV_8UC3);
    randu(R, Scalar::all(0), Scalar::all(255));
    //演示输出格式化选项
    cout << "R (default) = " << endl << R << endl << endl;
        return 0;
}

执行结果:

R (default) =
[ 91,   2,  79, 179,  52, 205;
 236,   8, 181, 239,  26, 248;
 207, 218,  45, 183, 158, 101]
2. 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]]]
3. 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
4. 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')
5. 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}

1.5. 其他常用项​​目的输出

OpenCV还通过<<运算符来支持其他常见OpenCV数据结构的输出:

1. 2D Point
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int, char**)
{
    Point2f P(5, 1);
    cout << "Point (2D) = " << P << endl << endl;
    return 0;
}

执行结果:

Point (2D) = [5, 1]
2. 3D Point
Point3f P3f(2, 6, 7);
    cout << "Point (3D) = " << P3f << endl << endl;

执行结果:

Point (3D) = [2, 6, 7]
3. 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;

执行结果:

Vector of floats via Mat = [3.1415927;
 2;
 3.01]
4. 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]

完整的源代码:

#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help()
{
    cout
        << "\n---------------------------------------------------------------------------" << endl
        << "This program shows how to create matrices(cv::Mat) in OpenCV and its serial"
        << " out capabilities" << endl
        << "That is, cv::Mat M(...); M.create and cout << M. " << endl
        << "Shows how output can be formatted to OpenCV, python, numpy, csv and C styles." << endl
        << "Usage:" << endl
        << "./mat_the_basic_image_container" << endl
        << "-----------------------------------------------------------------------------" << endl
        << endl;
}
int image(int, char**)
{
    help();
    //构造函数构建
    Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));
    cout << "M = " << endl << " " << M << endl << endl;
    //Create函数构建
    M.create(4, 4, CV_8UC(2));
    cout << "M = " << endl << " " << M << endl << endl;
    //创建多维矩阵
    int sz[3] = { 2,2,2 };
    Mat L(3, sz, CV_8UC(1), Scalar::all(0));
    //用matlab创建 1或0矩阵
    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;
    //创建一个3x3双精度单位矩阵
    Mat C = (Mat_<double>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    cout << "C = " << endl << " " << C << endl << endl;
    //对初始化列表做同样的事吗
#ifdef CV_CXX11
    C = (Mat_<double>({ 0, -1, 0, -1, 5, -1, 0, -1, 0 })).reshape(3);
    cout << "C = " << endl << " " << C << endl << endl;
#endif
    Mat RowClone = C.row(1).clone();
    cout << "RowClone = " << endl << " " << RowClone << endl << endl;
    //用随机值填充一个矩阵
    Mat R = Mat(3, 2, CV_8UC3);
    randu(R, Scalar::all(0), Scalar::all(255));
    //演示输出格式化选项
    cout << "R (default) = " << endl << R << endl << endl;    
    cout << "R (python)  = " << endl << format(R, Formatter::FMT_PYTHON) << endl << endl;    
    cout << "R (numpy)   = " << endl << format(R, Formatter::FMT_NUMPY) << endl << endl;    
    cout << "R (csv)     = " << endl << format(R, Formatter::FMT_CSV) << endl << endl;    
    cout << "R (c)       = " << endl << format(R, Formatter::FMT_C) << endl << endl;    
    // 其他常用项​​目的输出
    Point2f P(5, 1);
    cout << "Point (2D) = " << P << endl << endl;
    Point3f P3f(2, 6, 7);
    cout << "Point (3D) = " << P3f << endl << endl;
    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;
    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;
    return 0;
}

2. Mat类简单用法

2.1.Mat::Mat(int rows, int cols, int type)

  • rows:矩阵行数
  • cols:矩阵列数
  • type:CV_8UC1(8位 uchar型 (channel)1通道) 类似可以定义些CV_32FC3.说明:CV_(位数)+(数据类型)+(通道 数)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;

int main(int argc, char argv)
{
Mat A(3, 2, CV_8UC1);//一通道
Mat B(3, 2, CV_32FC3);//三通道
cout << “A=” << endl << “” << A << endl;
cout << “B=” << endl << “” << B << endl;
}

执行结果:

A=
[144, 148;
 151,  34;
 249, 127]
B=
[0.00094728079, 8.1135181e-43, 0.00094956905, 8.1135181e-43, 0.00094929244, 8.1135181e-43;
 0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43;
 0.00094709825, 8.1135181e-43, 0.00094728079, 8.1135181e-43, 0.00094728079, 8.1135181e-43]

2.2.Mat::Mat(Size size, int type)

  • Size:矩阵大小 //可以用别的图像的大小也可以自定Size(width,heighth)
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;

int main(int argc, char argv)
{
Mat A(3, 2, CV_8UC1);//一通道
Mat B(A.size(), CV_32FC3); //以A的大小定义
cout << “B=” << endl << “” << B << endl;
}

执行结果:

B=
[8.4436516e-24, 8.8141673e-43, 8.4758624e-24, 8.8141673e-43, 8.4709146e-24, 8.8141673e-43;
 8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43;
 8.4411777e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43, 8.4436516e-24, 8.8141673e-43]

2.3.:Mat sampleMat = (Mat_< float>(1, 2) << num1, num2);

  • 这是定义类一个一行两列的内容为float类型的矩阵,并且将num1,num2这两个数赋给矩阵
#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    float num1 = 2;
    float num2 = 4;
    Mat sampleMat = (Mat_<float>(1, 2) << num1, num2); 
    cout << "sampleMat=" << endl << "" << sampleMat << endl;
}

执行结果:

sampleMat=
[2, 4]

2.4.Mat DataMat(1, 2, CV_32FC1, &a[i][0]);

  • 此处假设a[i][2]。则定义了个一行两列的矩阵,类型为32位浮点型单通道,然后将a[i][0],a[i][1]的值赋给了矩阵。

2.5.零矩阵:cv::Mat::zeros(rows,cols,type)

#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    Mat A = Mat::zeros(5, 5, CV_8UC1);
    cout << "A=" << endl << "" << A << endl;
}

执行结果:

A=
[  0,   0,   0,   0,   0;
   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0]

2.6.one矩阵:cv::Mat::ones(rows,cols,type)

#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    Mat B = Mat::ones(5, 5, CV_8UC1);
    cout << "B=" << endl << "" << B << endl;
}

执行结果:

B=
[  1,   1,   1,   1,   1;
   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1;
   1,   1,   1,   1,   1]

2.7.单位矩阵:cv::Mat::eye(rows,cols,type)

#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    Mat C = Mat::eye(5, 5, CV_8UC1); 
    cout << "C=" << endl << "" << C << endl;
}

执行结果:

C=
[  1,   0,   0,   0,   0;
   0,   1,   0,   0,   0;
   0,   0,   1,   0,   0;
   0,   0,   0,   1,   0;
   0,   0,   0,   0,   1]

2.8.取一行:Mat B:B.row(i)

#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
    Mat B = Mat::ones(5, 5, CV_8UC1);
    Mat A = Mat::eye(5, 5, CV_8UC1);
    cout << "B的第一行" << endl << "" << B.row(1) << endl;
    cout << "A的第一列" << endl << "" << A.col(1) << endl;
}

执行结果:

B的第一行
[  1,   1,   1,   1,   1]
A的第一列
[  0;
   1;
   0;
   0;
   0]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~晓广~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值