OpenCv2 学习笔记(1) Mat创建、复制、释放

2024-06-11 21:58

本文主要是介绍OpenCv2 学习笔记(1) Mat创建、复制、释放,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenCV和VS2013的安装图文教程网上有很多,建议安装好之后,用VS2013建立一个空工程,用属性管理器分别新建一个对应debug和release工程的props配置文件,以后直接根据工程需要添加对应配置文件,而不需要每次新建工程后填写引用目录、库目录、附加依赖项,减少重复工作。

(用WLW编辑,段间距有点大!)需要说明的是,本学习笔记不会按照先讲数据结构,再讲如何使用。与OpenCv1.x不用中,opencv2.x及3.x中用Mat代替了CvMat和IplImage。因此,对Mat的使用,会从一些例子给出一个直观的感受,之后再根据一些例子遇到新的东西就进行详细的讲解,遵循学习中遇到问题解决问题的方式。

为了使得Mat的输出更美观,自己写了一个Mat的输出;首先创建工程,cpp文件的主程序如下:

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace cv;
using namespace std;  
 

void coutMat(const char *str, InputArray &_m) // _m可以是各种矩阵形式,包括vec、vector和表达式等。

{   //通过getMat()获取不同输入格式的Mat的数据,浅复制
    cout << str << endl << " " << _m.getMat() << endl << endl; 
}
 
void main()
{
    //编辑代码
    waitKet();         //避免命令行窗口一闪而过
}

1、Mat的创建、复制

/*
* Create Mat
*/
Mat M(2, 2, CV_8UC3, Scalar(0, 0, 255));   // 构造函数的一种
cout << "M=" << endl << " " << M << endl << endl;
 
Mat A;
M.copyTo(A);
 
M.release();
cout << A << endl;        // 释放不影响
 
 Mat B;
B = M.clone();
 
 M.release();
cout << "B=" << endl << " " << B << endl<<endl;    

Mat的一个构造函数 C++: Mat::Mat(int rows, int cols, int type, const Scalar& s) ,其中rows和cols是需要创建的矩阵的行数和列数,type是Mat的数据类型,s是Scalar类型的矩阵初值。

对于type,是基本数据类型,首先有枚举 enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }; 分别对应,8位无符号(uchar)、8位有符号(char)、16位无符号(ushort)、16位有符号(short)、32位有符号(int)、32位浮点(float)和64位双精度(double);其次 CV_8UC1、CV_16FC2、.. CV_64FC4等是多通道的类型,可以用CV_(深度)(类型)(通道数)描述, 例如本例中CV_8UC3,是指8位无符号3通道,其他类推。

对于s的Scalar类型,它的源头实际是一个4行1列的Mat,这里的Scalar(0,0,255),直接可以理解成M矩阵的每一个元素都是(0,0,255),当M看成图像,就是一个2x2的红色方块,Scalar有3个值,可以对应RGB色彩,通道顺序为(B,G,R)。那么,CV_8UC2,可以用Scalar(1,2)赋值,CV_64UC4可以用Scalar(0,0.1,0.08,100.1)赋值,其他类推。

Mat类的两个拷贝函数,copyTo()和clone(),都是进行深复制,也就是会另外开辟一个内存存储被复制的数据区域,对复制得到的新矩阵进行释放releas()不会影响原矩阵的数据(有其他方式会影响,后面遇到再讲)。这里的copyTo()和clone()区别在于,copyTo()可选一个参数掩膜mask,根据mask的值选择复制区域。

上面例子的结果如下:

image

 

2、Mat的释放

Mat mat1 = Mat::ones(1, 5, CV_32F);
Mat mat2 = mat1;                        // 仅创建一个mat2信息头, mat1,mat2 数据区的地址相同
Mat mat3 = Mat::zeros(1, 4, CV_32F);
mat2.release();          //  因为mat2是对mat1的引用,这里的mat2.release()只会清除mat2的信息头和数据指针
mat1.release();         //  mat1的数据区都会被释放,但是mat信息头数据还会保存(也就是还能继续被赋值)
cout << mat1 << endl;
cout << mat2 << endl;
cout << mat3 << endl << endl;
mat3.copyTo(mat1);// 拷贝会给mat1从新分配数据区域,其原来的数据区还会保留,即mat2的数据是原来mat1的数据,
//mat1 = mat3.clone();  // 最终结果是mat1和mat3的数据相同,但是数据存储空间不同,  mat2存储的是mat1最初的值
mat3.release();        // mat3的释放不会影响mat1
cout << mat1 << endl;
cout << mat2 << endl;
cout << mat3 << endl << endl;

有关注释读起来比较拗口,上面的例子最好调试下。总之,对于Mat的引用(也就是浅复制,只分配信息头,数据区共享)情况下的释放,只会清除本身的信息头和置零数据区指针,不会影响被赋值的矩阵。Mat有一个引用机制,有一个成员变量refcount,会自己根据被引用和释放的次数,自动管理内存,所以一般不需要用户自己去释放。对于创建类型的构造函数(深复制),那么会有属于自己的数据区,完全和被赋值的矩阵可以独立开。

3、Mat的复制和释放

Mat A = (Mat_<uchar>(5, 2) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); //A为5x2的uchar类型矩阵,并被赋初值1-10
Mat B = A;        // B引用A,浅复制(仅创建信息头,数据指针指向A的数据区,没有数据的复制)
Mat C = B.row(3);   // 同样是引用,C指向B的4行
Mat D = B.clone();  // D是深复制B,实际是A的深复制。
B.row(4).copyTo(C); // B、C都是引用A,这里相当于是把A的第4行“7,8”两个数换成了第5行“9,10”
A = D;      //D是从B也就是A深度复制,这里A引用了D
B.release();// B是引用,浅复制,这里释放的B的信息头并将其将数据指针置为0
C = C.clone();    // 因为C是浅复制,进过clone()深度之,开辟了内存并完全复制了数据,是完全独立于A的。

这一个例子,可以更加深入的了解Mat的复制和释放机制,调试的时候可以看下各矩阵的refcount变量。下面的一个例子,copyTo()函数有第二个参数mask情况,代码和结果如下:

Mat A = (Mat_<uchar>(5, 2) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Mat mask = (Mat_<uchar>(5, 2) << 0, 0, 1, 1, 0, 0, 0, 0, 1, 1); 
Mat C,D;
A.copyTo(C);      // 第二个参数为空,等效于A.copyTo(C,Mat());  
A.copyTo(D, mask);//mask必须和被复制矩阵大小相同 
coutMat("C = ", C);    //和C一样
coutMat("D = ", D); //D和C大小一样,但是只复制了第2、5行的数据,其他为0

image

4、其他

对于数学计算还有一些基本的构造函数,如Mat::eye()对角阵(当行、列不同时,主对角线为1)、Mat::ones()单位阵、Mat::zeros()零矩阵等。

用一个矩阵的一行复制到另外一行,不能通过直接复制,必须通过运算才行(运算的结果会返回一个实际的矩阵)。如矩阵mat的第1行复制到第2行,代码为 mat.row(1)=mat.row(0) 无效,但是 mat.row(1)=mat.row(0)+0; 或者 mat.row(1)=mat.row(0)+mat.row(2); 都是有效的。

 

总结

对于Mat一般只需要区什么是浅复制和深复制即可,何时需要就直接创建,释放可以交给OpenCv管理。另外没有提到的是,当Mat直接被另外一个大小不同的矩阵深幅值时,Mat会先被释放再被复制,不需要同OpenCv1.X中先释放再指定需要的size才能被再次使用。

这篇关于OpenCv2 学习笔记(1) Mat创建、复制、释放的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1052381

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多