OpenCV基本数据结构

本文介绍了OpenCV中的核心数据结构Mat,包括其组成、内存管理和创建方法。此外,还提到了其他常用的数据结构如Point、Scalar、Size、Rect,以及颜色空间转换函数cvtColor()。Mat对象的创建和内存管理机制是解决大图像处理中内存占用问题的关键,而其他数据结构则在表示图像特征和处理中扮演重要角色。

参考学习书籍:《OpenCV3编程入门》

环境:OpenCV4.1.1 + VS2019

一.基础图像容器Mat

Mat是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等),一个指向存储所有像素值的矩阵(根据所选存储方式不同,矩阵可以是不同维数的)。矩阵头所占内存小,通常是一个常数,而矩阵本身的尺寸很大,∵它存储了所有的像素值。而且图像处理本身就是一个计算量很大的过程,除非万不得已,都不应该进行大图像的复制。

为了解决占用空间大这一问题,OpenCV引入了计数机制:让每个Mat对象都有自己的矩阵头,但可以共同指向一个矩阵(即让矩阵指针指向同一个地址)。

在OpenCV1.0中,还不存在Mat类,在那时,OpenCV是基于C接口实现的。而其中的图像存储格式IplImage*,在退出前没有relase的话,就会造成内存泄漏,使用非常不方便。在C++出现后,有了类的概念,就不用担心这一问题。如Mat类,是有自动的存储管理。在创建对象时,是不会分配内存空间的。

Mat src;                 //创建Mat类对象  不分配内存空间
src = imread("1.jpg");   //为src开辟内存空间

上面是一种创建Mat类对象以及赋值的方法,第一行仅是创建对象,即创建矩阵头信息;第二行才是为其分配内存。同样也可以使用下面这种方法创建一个对象并初始化。这就是C++类的好处,同样,跟C++一样的面向对象的语言Java也是这样的。

Mat src = imread("1.jpg");

下面是两种方法的结构都是一样的,都是让dst对象指向src对象的矩阵,只是矩阵头(对象名)不一样。

Mat dst(src);    //使用拷贝构造函数

Mat dst;
dst = src;       //赋值运算符

显示创建Mat对象的七种方法

对于显示创建Mat对象的七种方法,很多博客与书上都有讲解,这里就不再赘述。可以参考这位博主的博客:https://blog.csdn.net/qq_34106574/article/details/93471025

不过我个人认为最常用的方法还是用Mat()构造函数创建。

OpenCV的格式化输出

r为创建的对象,用randu函数来生成一个随机矩阵,并给定一个上限下限值。

#include <iostream>
#include <opencv2\opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main()
{
	Mat r = Mat(10, 3, CV_8UC3);
	randu(r, Scalar::all(0), Scalar::all(255));
	cout << "r(opencv默认风格)=" << r << ";" << endl << endl;
	cout << "r(python风格)=" <<format(r, Formatter::FMT_PYTHON)<< ";" << endl << endl;
	cout << "r(逗号分割风格)=" << format(r, Formatter::FMT_CSV) << ";" << endl << endl;
	cout << "r(numpy风格)=" << format(r, Formatter::FMT_NUMPY) << ":" << endl << endl;
	cout << "r(c语言风格)=" << format(r, Formatter::FMT_C) << ":" << endl << endl;

}

OpenCV默认风格:

python风格:

逗号分隔风格:

numpy风格:

C语言风格:

以上,对于矩阵值的大小是由randu函数随机生成的,而矩阵的大小是由Mat r = Mat(10, 3, CV_8UC3);所决定的。

在VS中,右击Mat,选择速览定义,就会出现下面的代码。

456行的函数就是Mat的构造函数,这个函数定义在mat.inl.hpp这一头文件中,当然你还可以看到除了456行这一函数之外的其他构造函数,它们都有同样的函数名,但形参不同。在使用构造函数创建对象时,会根据填入的实参来自动选择所使用的构造函数。如这里就是使用的456行的函数,三个参数分别为矩阵的行数,列数,和存储的数据类型。

对于数据类型,有许多种,它定义了每个元素(图片中的像素)的通道数和每个通道上表示像素值的比特数(位数)。

如:8UC3 ——> 8 unsigned  3 channel   即  3通道 8位无符号整型

依次类推有:

8S   (单通道8位有符号整数) 
16U (单通道16位无符号整数) 
16S  (单通道16位有符号整数) 
32S  (单通道32位有符号整数) 
32F  (单通道32位浮点数) 
64F  (单通道64位浮点数)

8UC1 (单通道8位无符号整数) 
8UC2 (2通道8位无符号整数) 
8UC3 (3通道8位无符号整数) 
8UC4 (4通道8位无符号整数) 
8UC(n) (n通道8位无符号整数 (n 可以从 1 到 512) ) 

更详细的讲解可以参考这位博主的博客,可以帮助我们从视觉上理解:https://blog.csdn.net/CV_YOU/article/details/53177173

所以,上面的示例代码所生成的矩阵的含义是输出一个3*10的矩阵,每个元素有3个通道值。以python风格为例:

二.其他常用数据结构和函数

1.点 Point类

point类

Point point;
point.x = 1;
point.y = 2;

//或

Point point = Point(1,2);

定义输出二维点

Point2f p(6,2);
count<<"二维点 p="<<p<<";\n"<<endl;

定义输出三维点

Point3f p3f = (1,2,3);
count<<"三维点 p3f="<<p3f<<";\n"<<endl;

定义输出基于Mat的std::vector

vector<float> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
count<<"vector="<<Mat(v)<<";\n"<<endl;

定义输出std::vector点

vector<Point2f> points(20);
for(size_t i = 0; i<points.size(); ++i)
{
   points[i] = Point2f((float)(i*5),(float)(i%7));
}
count<<"二维点向量 points="<<points<<";\n"<<endl;

2.颜色 Scalar类

Scalar(a,b,c);

Scalar()表示有4个元素的数组,即RGB颜色值和透明颜色alpha。若只填了3个参数,则默认我们想表示3个参数。值得注意的是:RGB的颜色定义顺序不再是R(红),G(绿),B(蓝),而是BGR。

3.尺寸 Size类

Size(5,5);

4.矩形 Rect类

Rect rec = Rect(1,2,3,4);

Rect()的成员变量有x,y,width,height。上面的例子表示一个左上角坐标为(1,2)长为3,高为4的矩形。

5.颜色空间转换 cvtColor()函数

#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;

void main()
{
	Mat src = imread("1.jpg");
	Mat dst;
	cvtColor(src,dst,COLOR_BGR2BGRA);
	imshow("效果图",dst);
	waitKey();
}

COLOR_BGR2BGRA为一个标识符,表示将RGB转化成BGR。除此之外还有其他许多标识符,可以在使用时在网上查询。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值