opencv笔记 -- 核心功能模块(Mat)

笔者之前零零碎碎地用过一些opencv,但是一直没有足够详尽的了解,正巧刷到了opencv的tutorial,仅以此记录。
网址:link

Mat - 基本的图像容器

在这里插入图片描述
一张普通的图片,如果想让计算机也能读得懂的话,我们需要把他转换成矩阵格式,也就是上图中的数字部分。使用Opencv的主要重点就是操作和处理这些数据。那么第一步就是如何存储和处理图片。

在opencv中使用mat来存储图像,且不需要手动分配其内存或在不需要时释放它。大多数OpenCV函数将自动分配其输出数据。如果您传递一个已经存在的Mat对象,它已经为矩阵分配了所需的空间,那么它将被重用。换句话说,我们在任何时候都只使用执行任务所需的内存。

为了避免对较大图像的不必要复制,opencv使用了一个引用计数系统,让每个mat对象都有自己的头,但是一个矩阵可以在两个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

上面的所有的对象都指向了同一个单一的数据矩阵,并且其中任意一个发生了改变都会影响其他的。实际上不同的对象仅会对同一个根本数据提供不同的入口。然而,它们的标题部分是不同的。真正有趣的部分是,您可以创建仅引用完整数据的一部分的头。例如,要在图像中创建感兴趣的区域(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对象,最后一个使用该矩阵的对象负责清理该矩阵。如果有复制图片的需求,那么可以使用cv::Mat::clone() 和cv::Mat::copyTo()功能。

Mat F = A.clone();
Mat G;
A.copyTo(G);

对F和G的修改不会对A造成任何影响。以下是一些总结的tips

  • 输出的图片分瓶是自动完成的。
  • 无需担心内存管理。
  • 赋值操作和复制构造只复制了头部。
  • 一个图片的根本矩阵可以使用clone和copyto功能进行复制。

存储方法

我们可以使用颜色空间和数据类型来存储像素的值。颜色空间指的是我们如何组合颜色组件来编码给定的颜色。最简单的一种是灰度,我们可以使用的颜色是黑色和白色。这些组合使我们能够创造出许多灰色阴影。

彩色方案可以被分成三到四个基础颜色组合(三原色)。最流行的组合是RGB,主要是因为我们的眼睛就是以此为基础来组成颜色的。此外,透明度alpha(A)也会被添加进来。(0代表完全透明,255代表完全不透明)。

但是不同的颜色系统的优势各不相同:

  • RGB是最常见的,因为我们的眼睛使用类似的东西,但请记住,OpenCV标准显示系统使用BGR色彩空间(红色和蓝色通道交换位置)来组合颜色。
  • HSV和HLS将颜色分解成它们的色调、饱和度和值/亮度组件,这是我们描述颜色的一种更自然的方式。例如,您可以忽略最后一个组件,使您的算法对输入图像的光照条件不那么敏感。
  • 流行的JPEG图像格式使用YCrCb。
  • CIE Lab*是一个感知上一致的色彩空间,如果你需要测量一种给定颜色到另一种颜色的距离,它会派上用场。

创造一个Mat对象

以下是创建一个Mat对象的方法:

  • 默认构造
 Mat M(2,2, CV_8UC3, Scalar(0,0,255));
 cout << "M = " << endl << " " << M << endl << endl;

在这里插入图片描述

对于二维多通道图像,我们首先需要定义他们的大小,行数和列数。然后需要明确用来存储这些元素的数据类型和每个矩阵点的通道数。

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

举个例子,CV_8UC3代表我们使用unsigned char类型,8bit长且每个像素都有三个char类型来组成三个通道。通道最多只有四个。标量是一个四元素短向量。指定它,您可以用自定义值初始化所有矩阵点。如果需要更多类型,可以使用上面的宏创建类型,在括号中设置通道号,如下所示。

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

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

  • cv::Mat::create功能
 M.create(4,4, CV_8UC(2));
 cout << "M = "<< endl << " " << M << endl << endl;

在这里插入图片描述
你无法通过这个构造器来初始化这个矩阵,尽在新的大小不符合原来的大小时,才会重新分配数据内存。

  • MATLAB style 初始化: 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;

在这里插入图片描述

  • 对于小的矩阵,你可以使用逗号来区分初始化器
 Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
 cout << "C = " << endl << " " << C << endl << endl;
 C = (Mat_<double>({0, -1, 0, -1, 5, -1, 0, -1, 0})).reshape(3);
 cout << "C = " << endl << " " << C << endl << endl;

在这里插入图片描述

  • 为一个已经存在的Mat对象创造一个新的头部并使用 cv::Mat::clone or 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中进行存储,以及相应的一些操作,如复制,构造等。
在笔者的实际使用过程中,需要格外注意opencv的操作耗时问题,尤其是cv::imread操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值