博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【opencv学习笔记】004之Mat对象及其应用详解
阅读量:4074 次
发布时间:2019-05-25

本文共 5841 字,大约阅读时间需要 19 分钟。

目录


一、说在前面的话

在最初学习opencv 的时候,还没有写博客的习惯,后来有时间,从中间开始写。现在因为要做些实际项目,对一些概念进行深入了解,同时有很多朋友跟我说,希望我能接着完善我的博客。本来是希望以后有时间能从头到尾好好学,但是由于项目需要,对一些概念有详细的介绍,所以我的opencv相关博客将不按照顺序发布,我会根据自己项目或者实际情况,逐步完善自己的学习笔记。这里面不仅有我初次学习opencv的一些笔记资料,还有后期项目实战的一些了解和完善,希望大家多多支持。

在此,也感谢各位对我的支持。我会努力写出更好的博客。

二、其他图像类型

在Opencv1代的时候,是使用lplImage 和 CvMat 数据结构来表示图像的。他们都是C语言的结构,申请的内存需要自己手动管理,特别是采用 lplImage 会直接暴露内存,如果忘记释放内存,就会造成内存泄漏。在这里,我不对这个进行过多的描述,大家可以从百度百科或者其他的文章中去了解。在这里提一下,希望大家能对此有所了解。

三、Mat对象

从Opencv2.3往后就引入了Mat类,他可以自动管理内存,相比较C语言的两种数据结构,Mat有着自己独特的优势,接下来我Mat对象做详细介绍。

1、构成

Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。Mat在进行赋值和拷贝时,只复制矩阵头,而不复制矩阵,提高效率。如果矩阵属于多个Mat对象,则通过引用计数来判断,当最后一个使用它的对象,则负责释放矩阵。

class CV_EXPORTS Mat{public:/*..很多方法..*//*............*/ int flags;/*flags指定图像的颜色空间              flags > 0 3通道的彩色图像            flags = 0 灰度图像            flags < 0 不作改变          */int dims;  /*数据的维数*/int rows,cols; /*行和列的数量;数组超过2维时为(-1,-1)*/uchar *data;   /*指向数据*/int * refcount;   /*指针的引用计数器; 阵列指向用户分配的数据时,指针为 NULL/* 其他成员 */ ...};

2、存储方法

Mat中矩阵的每个元素可以使用不同的数据类型,最小的数据类型是char,占用一个字节或者8位,可以是有符号的(0到255)或者是无符号的(-127到127)。在RGB颜色空间中,使用三个char类型可以表示1600万中颜色,但在图像处理的过程中有可能会使用到float或者double来表示图像的像素。

3、常用成员及含义

1、data

Mat对象中的一个指针,指向存放矩阵数据的内存(uchar* data)

2、dims

矩阵的维度,3*4的矩阵维度为2维,3*4*5的矩阵维度为3维

3、channels

矩阵通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说 3 * 4 矩阵中一共 12 个元素,如果每个元素有三个值,那么就说这个矩阵是 3 通道的,即 channels = 3。常见的是一张彩色图片有红、绿、蓝三个通道。

4、depth

深度,即每一个像素的位数,也就是每个通道的位数。在opencv的Mat.depth()中得到的是一个0 – 6的数字,分别代表不同的位数:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 },可见 0和1都代表8位, 2和3都代表16位,4和5代表32位,6代表64位。

4、常用构造方法

1、Mat::Mat()

无参数构造方法;

2、Mat::Mat(int rows, int cols, int type)

创建行数为 rows,列数为 col,类型为 type 的图像;

3、Mat::Mat(Size size, int type)

创建大小为 size,类型为 type 的图像;

4、Mat::Mat(int rows, int cols, int type, const Scalar& s)

创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s;

5、Mat::Mat(Size size, int type, const Scalar& s)

创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s;

6、Mat::Mat(const Mat& m)

将m赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象共用图像数据,属于浅拷贝;

7、Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)

创建行数为rows,列数为col,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由 step指定。

8、Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)

创建大小为size,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由step指定。

9、Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)

创建的新图像为m的一部分,具体的范围由rowRange和colRange指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据;

10、Mat::Mat(const Mat& m, const Rect& roi)

创建的新图像为m的一部分,具体的范围roi指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据。

这些构造函数中,很多都涉及到类型type。type可以是CV_8UC1,CV_16SC1,…,CV_64FC4 等。里面的 8U 表示 8 位无符号整数,16S 表示 16 位有符号整数,64F表示 64 位浮点数(即 double 类型);C 后面的数表示通道数,例如 C1 表示单通道的图像,C4 表示 4 个通道的图像,以此类推。如果你需要更多的通道数,需要用宏 CV_8UC(n),例如:

Mat M(3,2, CV_8UC(5));//创建行数为 3,列数为 2,通道数为 5 的图像。

5、其他方法

Mat::Create:创建新的阵列数据

void Mat::create(int rows, int cols, int type)void Mat::create(Size size, int type)void Mat::create(int ndims, const int* sizes, inttype)//ndims – 新数组的维数。//rows –新的行数。//cols – 新的列数。//size – 替代新矩阵大小规格:Size(cols, rows)。//sizes – 指定一个新的阵列形状的整数数组。//type – 新矩阵的类型。

Mat::resize:重新定义图片大小

void Mat::resize(size_t sz)void Mat::resize(size_t sz, const Scalar& s)//sz –新的行数。//s –分配给新添加的元素的值。

Mat::type:返回一个矩阵元素的类型。

int Mat::type() const//该方法返回一个矩阵的元素类型。兼容CvMat 类型系统,像 CV_16SC3标识符 或 16 位有符号的3 通道阵列等。

Mat::depth:返回一个矩阵元素的深度

int Mat::depth() const//该方法返回矩阵元素深度(每个单独的通道类型)的标识符。例如,对于16位有符号的3通道数组,该方法返回CV_16S。矩阵类型的完整列表包含以下内容值:// CV_8U - 8 位无符号整数 (0…..255)// CV_8S - 8 位符号整数 ( - 128…..127)// CV_16U - 16 位无符号整数 (0……65535)// CV_16S - 16 位符号整数 ( - 32768…..32767)// CV_32S - 32 位符号整数 ( - 2147483648……2147483647)// CV_32F - 32 位浮点数 ( - FLT_MAX ………FLT_MAX,INF,NAN)// CV_64F - 64 位浮点数( - DBL_MAX ……….DBL_MAX,INF,NAN)

Mat::channels:返回矩阵通道的数目

int Mat::channels() const

Mat::size:返回一个矩阵大小

Size Mat::size() const

Mat::at:返回对指定数组元素的引用

template
T& Mat::at(int i)consttemplate
const T&Mat::at(int i) consttemplate
T& Mat::at(int i,int j)template
const T&Mat::at(int i, int j) consttemplate
T& Mat::at(Pointpt)template
const T&Mat::at(Point pt) consttemplate
T& Mat::at(int i,int j, int k)template
const T&Mat::at(int i, int j, int k) consttemplate
T& Mat::at(constint* idx)template
const T&Mat::at(const int* idx) const//参数//i –索引 0 维度//j – 1 维度的索引//k – 沿 2 维度的索引//pt – Point(j, i) 作为指定元素的位置。//idx – Mat::dims 数组的索引。//该模板方法返回指定数组元素的引用。为了具有更高的性能,索引范围检查只在调试配置下执行。请注意使用具有单个索引(i) 的变量可以访问的单行或单列的2 维的数组元素。也就是比方说,如果A是1 x N 浮点矩阵和B是M x 1的整数矩阵,您只需编写A.at(k + 4) 和 B.at(2 * i + 1) 分别代替A.at(0, k + 4)和//B.at(2 * i + 1, 0)。//下面的示例将初始化希尔伯特矩阵:Mat H(100, 100, CV_64F);for(inti=0; i
(i,j)=1./(i+j+1);

6、Mat优势

1.图像的内存分配和释放由Mat类自动管理。

2.Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。Mat在进行赋值和拷贝时,只复制矩阵头,而不复制矩阵,提高效率。如果矩阵属于多个Mat对象,则通过引用计数来判断,当最后一个使用它的对象,则负责释放矩阵。

3.可以使用clone和copyTo函数,不仅复制矩阵头还复制矩阵。

7、注意事项

1.OpenCV中的内存分配是自动完成的(不是特别指定的话)

2.使用OpenCV的C++ 接口时不需要考虑内存释放问题

3.Mat的赋值运算和拷贝构造函数只会拷贝矩阵头,仍然共同同一个矩阵

4.如果要复制矩阵数据,可以使用clone和copyTo函数

8、CvMat, Mat, IplImage之间的互相转换

//1. IpIImage -> CvMat/*cvGetMat*/CvMat matheader;CvMat * mat = cvGetMat(img, &matheader);/*cvConvert*/CvMat * mat = cvCreateMat(img->height, img->width, CV_64FC3);cvConvert(img, mat);//2. IplImage -> MatMat::Mat(const IplImage* img, bool copyData=false);/*default copyData=false,与原来的IplImage共享数据,只是创建一个矩阵头*///例子:IplImage* iplImg = cvLoadImage("greatwave.jpg", 1);Mat mtx(iplImg); /* IplImage * -> Mat,共享数据; or : Mat mtx = iplImg;*///3. Mat -> IplImageMat MIplImage iplimage = M; /*只创建图像头,不复制数据*///4. CvMat -> MatMat::Mat(const CvMat* m, bool copyData=false); /*类似IplImage -> Mat,可选择是否复制数据*///5. Mat -> CvMat//例子(假设Mat类型的imgMat图像数据存在):CvMat cvMat = imgMat;/*Mat -> CvMat, 类似转换到IplImage,不复制数据只创建矩阵头

四、说在最后的话

因为Mat是最基本的内容,以后不管是学习笔记还是项目实战,都会用到Mat 类,所以在这里,很少涉及到具体的代码和实现效果,但是希望大家要多做实战,多敲代码,才能学的更好。

 

 

转载地址:http://ofyni.baihongyu.com/

你可能感兴趣的文章
FTP 常见问题
查看>>
zookeeper单机集群安装
查看>>
do_generic_file_read()函数
查看>>
Python学习笔记之数据类型
查看>>
Python学习笔记之特点
查看>>
shell 快捷键
查看>>
VIM滚屏操作
查看>>
EMC 2014存储布局及十大新技术要点
查看>>
linux内核内存管理(zone_dma zone_normal zone_highmem)
查看>>
将file文件内容转成字符串
查看>>
循环队列---数据结构和算法
查看>>
优先级队列-数据结构和算法
查看>>
链接点--数据结构和算法
查看>>
servlet中请求转发(forword)与重定向(sendredirect)的区别
查看>>
Spring4的IoC和DI的区别
查看>>
springcloud 的eureka服务注册demo
查看>>
eureka-client.properties文件配置
查看>>
MODULE_DEVICE_TABLE的理解
查看>>
platform_device与platform_driver
查看>>
platform_driver平台驱动注册和注销过程(下)
查看>>