【C++的OpenCV】第十四课-OpenCV基础强化(二):访问单通道Mat中的值

news2024/11/28 2:46:51

🎉🎉🎉 欢迎各位来到小白 p i a o 的学习空间! \color{red}{欢迎各位来到小白piao的学习空间!} 欢迎各位来到小白piao的学习空间!🎉🎉🎉
💖💖💖 持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖


我的主页: \color{purple}{我的主页:} 我的主页:我的主页

  1. Python基础、中级、高级;
  2. C++数据结构和算法;
  3. Python数据结构和算法;
  4. OpenCV相关内容等重点内容

我的资源: \color{purple}{我的资源:} 我的资源:我的资源

  1. IT技术各档次模板
  2. 各类项目(企业、毕设)
  3. 数据库安装包(Mysql8.0)
  4. 技能资料(电子书、软考等)

目录


----------------------------------以下为正式内容----------------------------------------

前言 \color{purple}{前言} 前言

        书接上回,我们继续来讨论有关Mat的基本知识,这次我们继续深化了解Mat对象,以便后期更好的进行开发工作。这一章节主要是一些使用层面的知识,相比上章节,我相信读者更愿意看本章内容,因为可以快速得到自己想要的结果,但是还是那句话,最好掌握原理之后,再去使用更为科学


前文链接:【C++的OpenCV】第十三课-OpenCV基础强化(一):绝对有用!Mat相关的一系列知识(基础->进阶)


一、访问的方法 \color{blue}{一、访问的方法} 一、访问的方法

1.1 利用成员函数 a t ( ) \color{green}{1.1 利用成员函数at()} 1.1利用成员函数at()

        先来通过帮助文档了解一下at函数的基本信息:点击这里了解详情,总共有12种形式,这里为大家略微截图,大家可以自行阅读,我摘抄其中重点,其余感兴趣的可以做进一步了解:
![在这里插入图片描述](https://img-blog.csdnimg.cn/8348bd8fc8794491a72ce953b909a378.png

1.1.1 at函数的功能:

在这里插入图片描述        这么多英文懵了吧?懵了就对了,下边我给大家讲几句!!!😃
        大概意思就是说,这个方法会返回一个你所指定的数组元素的引用,而关于下标索引范围的检查动作仅仅在测试模式下生效(生产模式下不生效的目的是为了提高程序的执行效率)。注意:这里得到是某个元素的引用哦!!!
        再直白一点,就是说它可以得到矩阵的某行某列的元素。

1.1.2 多种at()函数原型的介绍及案例

a) 类型一:_Tp& cv::Mat::at ( int i = 0)
template<typename _Tp >
_Tp& cv::Mat::at ( int  i = 0) 	

        原文:That is, if, for example, A is a 1 x N floating-point matrix and B is an M x 1 integer matrix, you can simply write A.at<float>(k+4) and B.at<int>(2i+1) instead of A.at<float>(0,k+4) and B.at<int>(2i+1,0), respectively.
大概意思:这个参数i,可以指代任意一个单行或者单列的二维矩阵,例如:一个1行N列的浮点矩阵A,和一个M行1列的整型矩阵B,分别找到其中某个元素的方法就可以简化为:A.at<float>(k+4) 和 B.at<int>(2*i+1)。
        注意:这里函数原型中的返回值部分是_TP&哦,大家知道这是什么意思吧?(&是引用)
        这里来给大家一个使用上的要求:


    If matrix is of type CV_8U then use Mat.at<uchar>(y,x).
    如果矩阵是CV_8U的类型,那么使用模版时类型也要是对应的数据类型uchar,即:Mat.at<uchar>(y,x)
    这里和大家解释一个细节:8U的意思就是8bit的无符号整数。
    If matrix is of type CV_8S then use Mat.at<schar>(y,x).
    同上的翻译,一个意思,即类型是CV_8S,则使用类型为schar,即:Mat.at<schar>(y,x),下边不再赘述。
    If matrix is of type CV_16U then use Mat.at<ushort>(y,x).
    If matrix is of type CV_16S then use Mat.at<short>(y,x).
    If matrix is of type CV_32S then use Mat.at<int>(y,x).
    If matrix is of type CV_32F then use Mat.at<float>(y,x).
    If matrix is of type CV_64F then use Mat.at<double>(y,x).

b) 类型二:_Tp& cv::Mat::at( int row,int col )
template<typename _Tp >
_Tp& cv::Mat::at( int row,int col ) 		

        那这种就是最常见的那种咯,输入行列找到对应的值咯。给大家个例子:

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;

int main()
{
	 Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6)
	 cout << m.at<int>(1,1)<< endl; // 这里的结果是:4 ,为什么知道吗?
	 cout << m <<endl; // 注意:显示的是3行2列
	//首先,这里创建的是一个3行2列的矩阵,这个不难懂,4是出现在第二行第二列的元素:
	/*
	[1,2
	 3,4
	 5,6]
	*/
	// 那这个m.at<int>(1,1)中的两个1,其实就得知道at的参数含义了,
	//注意,at()方法中的row和col都是从0开始的,0即代表第一行或者第一列,明白了吧?
	//注意:at()中是先行后列!
    return 0;
}
c)类型三 :_Tp& cv::Mat::at ( Point pt)
template<typename _Tp >
_Tp& cv::Mat::at ( Point  	pt) 	

        其实这种也很常见以及其返回const类型的方法都是一个原理,这里需要传入一个点对象作为参数,说白了,就是按照点的位置在对应矩阵这种查找对应的元素即可了。举个例:

#include<iostream>
#include"opencv2/core/utility.hpp"
using namespace std;
using namespace cv;

int main()
{
	Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6);
	cout<<m<<endl;
	/*
	[1, 2;
 	 3, 4;
 	 5, 6]
	*/
	cout << m.at<int>(Point(1,0)) << endl; // 结果是2哦,看看上一节内容就知道,Point(c,r),是先列后行,且这两个值都是列和行的索引(基于0)
	return 0;
}

在这里插入图片描述
        虽然方法很多,其他的方法都可以触类旁通,只要学好C++的基础语法,这都不是难事哦,后期我也将会为大家写写C++和Python的基础教程,大家都可以持续关注起来哦!

1.2 利用成员函数 p t r ( ) \color{green}{1.2利用成员函数ptr()} 1.2利用成员函数ptr()

        先来通过帮助文档了解一下at函数的基本信息:点击这里了解详情,这个方法更多,有20种,是不是看文档很累?看我的吧,帮你总结好了学习的方法,轻松上手,熟练掌握!
在这里插入图片描述

1.2.1 ptr()函数的功能

        首先呢,它会返回一个指向矩阵中某元素(或者行)的指针!注意哦,返回的是指针!并且哦,这个指针是uchar类型的哦!

1.2.2 多种ptr()函数原型介绍及案例

a) 类型一:uchar* cv::Mat::ptr ( int i0 = 0 )
 // 这个是模版方法:
 template<typename _Tp >
_Tp* cv::Mat::ptr 	( 	int  	i0 = 0	) 	// i0 :基于0的行索引,说白了,从零开始!

//个人而言,更乐意直接使用模版方法,因为它可以返回模版类型的指针(行或者元素),而不是单纯的uchar*!!


//以下这个是基础款:
uchar* cv::Mat::ptr (int  i0 = 0) 	


        注意,这个方法!返回的就是某一行的行指针!
        举个浅显易懂的例子吧:

#include<iostream>
#include"opencv2/core/utility.hpp"
using namespace std;
using namespace cv;

int main()
{
	Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6);
	cout << m <<endl; // 注意:显示的是3行2列
	/*
	[1, 2;
 	 3, 4;
 	 5, 6]
	*/
	cout << m.size() << endl; // [2 x 3] 注意:size()的表示方式是2列3行!
	for(int r=0; r < m.rows; r++){
		//得到每行的行首指针,r就是当前行的索引
		const int* rptr = m.ptr<int>(r);
		//打印第r行的元素的所有值:
		for(int c=0; c<m.cols; c++){ //c是列的索引,也是基于0的索引,几乎所有数字型索引都是从0开始!
			cout<<rptr[c]<<",";
		}
		cout<<endl; //换行
	}
	return 0;
}

        结果如下:
在这里插入图片描述

b) 类型二:uchar* cv::Mat::ptr ( int row,int col )
// 这个是模板:
 template<typename _Tp >
_Tp* cv::Mat::ptr 	( 	int  	row,
		int  	col 
	) 		

//以下这个是基础款:
uchar* cv::Mat::ptr ( int  row,int  col ) 		

        这种方式不就更直接了吗?直接通过行列访问到对应元素上(注意此时这个返回值就是直接返回元素的指针了!),我们试试看:

#include<iostream>
#include"opencv2/core/utility.hpp"
using namespace std;
using namespace cv;

int main()
{
	Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6);
	cout << m <<endl; // 注意:显示的是3行2列
	/*
	[1, 2;
 	 3, 4;
 	 5, 6]
	*/
	cout << m.size() << endl; // [2 x 3] 注意:size()的表示方式是2列3行!
	cout << *m.ptr<int>(1,1) << endl; //注意这里一个细节哦,仔细看哦,结果是4
	//这里m.ptr<int>(1,1)得到的是索引为(1,1)的元素的指针!
		//而在其之前加上*号就是获取该指针地址对应的元素(这个过程通常被称为“解引用”操作)
	return 0;
}

        看着方法众多,很多方法几乎用不到,但是得有这个功能,新手先掌握这些,剩下的内容等用到了再查就行!掌握了规律,剩下的无师自通了哈!

1.3 利用成员函数 i s C o n t i n u o u s 和 p t r \color{green}{1.3利用成员函数isContinuous和ptr} 1.3利用成员函数isContinuousptr

1.3.1 isContinuous()介绍

        原文链接得有:点击这里了解详情,毕竟是教大家学东西,同时培养自学能力,这么良心的作者已经很少了!
        函数功能:
        **如果矩阵元素连续存储,且每行末尾没有间隙,则该方法返回true。否则,它将返回false。**显然,1x1或1xN矩阵总是连续的。使用Mat::create创建的矩阵总是连续的。但是,如果 使用Mat::col、Mat::diag等提取矩阵的一部分,或者为外部分配的数据构造矩阵头,则此类矩阵可能不再具有此属性。 想想看,图像边界连续性检测不就是这个原理吗?

        💖这里,为了给大家更好的理解,我们加一节小灶:Mat对象至少一行中的所有元素在内存汇总的排布是连续的!而行与行之间不一定连续(除非你用create创建Mat),如果不连续,其行与行的间隔也是一样的!!
在这里插入图片描述

        函数的原型:

bool cv::Mat::isContinuous ( ) const

// 返回值是一个布尔值,如果是连续的就是true,否则就是false呗!

1.3.2 我们来看看其和ptr()组合如何完成实际需求(访问Mat中的值)

        这里就不废话了,都是讲过的内容,直接上代码:

#include<iostream>
#include"opencv2/core/utility.hpp"
using namespace std;
using namespace cv;

int main()
{
	Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6);
	cout << m <<endl; // 注意:显示的是3行2列
	/*
	[1, 2;
 	 3, 4;
 	 5, 6]
	*/
	if(m.isContinuous()){
		int* ptr = m.ptr<int>(0); // 得到第一行行首指针
		for(int n = 0; n < m.rows*m.cols; n++){
			//解释一下:n < m.rows*m.cols这个边界条件是一种经验!
			//意思:m.rows*m.cols即行数*列数
			//其次,在内存层面上,如果矩阵连续(m.isContinuous()的结果为true),
			//就是说内存上这些值都是挨着存储的,所以索引也是连续的
			//故这是一个以为数组,则最大索引就是m.rows*m.cols-1
			//怎么样?有意思吧?认真学习起来。
			cout<<ptr[n]<<",";
		}
	}
	return 0;
}

        注意仔细看,上述代码如下的结果 \color{red}{注意仔细看,上述代码如下的结果} 注意仔细看,上述代码如下的结果
在这里插入图片描述
        说明上述代码不连续哦,当然你也可以尝试一下加一个else结构去打印一下“不连续”!证明,这样子创建的矩阵,每行之间是有固定间隙的哦(仔细看下下边的内容)!

在这里插入图片描述        那我们来换一种方式:

#include<iostream>
#include"opencv2/core/utility.hpp"
using namespace std;
using namespace cv;

int main()
{
	Mat m = (Mat_<int>(3,2) << 1,2,3,4,5,6);
	Mat m_c;
	m_c.create(m.size(),m.type());//注意上文提到过:create创建的是连续存储的矩阵
	
	cout << m_c <<endl; // 注意:显示的是3行2列
	/*
	[1, 2;
 	 3, 4;
 	 5, 6]
	*/
	if(m.isContinuous()){
		int* ptr = m_c.ptr<int>(0); // 得到第一行行首指针
		for(int n = 0; n < m_c.rows*m_c.cols; n++){
			cout<<ptr[n]<<",";
		}
		cout<<endl;
	}
	return 0;
}

        这下结果明朗了,顺道学习了新技能!
在这里插入图片描述

四、总结 \color{red}{四、总结} 四、总结

内容虽然不多,分成两章更新,下章还在持续更新!但都是精华如果你觉得内容难懂,不妨从最基础的内容学起来,请看我的首页哦!我的主页
       

顺道呢,发现一个不错的资源:点我进入

其中包含了opencv入门的保姆级教程(环境的安装—>实际的项目【人脸识别&教程】,以及配套了一本中文版OpenCV书籍)


💖💖💖 持续更新,期待关注! \color{blue}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1146222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++——类和对象(上)

1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 例如手洗衣服 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间…

如何借助数据集更好的评估NLP模型的性能?

随着信息时代的迅猛发展&#xff0c;每天有无数文本、声音、图片和视频不断涌入互联网。如何从海量数据中提炼有意义信息成为学术界和工业界迫切需要解决的问题。在此背景下&#xff0c;自然语言处理&#xff08;NLP&#xff09;应运而生&#xff0c;成为人工智能领域最为活跃的…

python基础语法(十一)

目录 文件文件是什么文件路径文件操作1. 打开文件关闭文件写文件读文件 关于中文的处理使用上下文管理器 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个人主页 &#x1f978;&#x1f978;&#x1f978;C语言 &…

串行原理编程,中文编程工具中的串行构件,串行连接操作简单

串行通信原理编程&#xff0c;中文编程工具中的串行通信构件&#xff0c;串行通信连接设置简单 编程系统化课程总目录及明细&#xff0c;点击进入了解详情。https://blog.csdn.net/qq_29129627/article/details/134073098?spm1001.2014.3001.5502 串行端口 是串行的基础&#…

第22天:time模块与datetime模块

time模块 时间的三种格式&#xff1a; 1. 时间戳&#xff1a;从1970年1月1号到现在的秒数&#xff0c;他是一个数字 2. 结构化时间: 不是让我们看的&#xff0c;让计算机看的&#xff0c;他是时间之间相互转换的时候的中间桥梁 3. 格式化时间&#xff1a;就是符…

【贝叶斯回归】【第 1 部分】--pyro库应用

Bayesian Regression - Introduction (Part 1) — Pyro Tutorials 1.8.6 documentation 一、说明 我们很熟悉线性回归的问题&#xff0c;然而&#xff0c;一些问题看似不似线性问题&#xff0c;但是&#xff0c;用贝叶斯回归却可以解决。本文使用土地平整度和国家GDP的关系数据…

栈、共享栈、链式栈(C++实现)

文章目录 前言1. 栈的顺序存储&#xff08;顺序栈&#xff09;2. 栈的基本操作&#x1f351; 入栈操作&#x1f351; 出栈操作&#x1f351; 获取栈顶元素&#x1f351; 获取栈的长度&#x1f351; 判断是否为空栈&#x1f351; 判断栈是否满了&#x1f351; 打印栈内的元素&am…

『VUE2 - 车牌号软键盘』

一、需求描述 在 VUE2 Vant2 的项目中&#xff0c;实现 车牌号软键盘 的功能。 二、引入全局组件 引入封装好的 vant-number-plate 组件&#xff0c;整个文件夹放在 src/components 里面&#xff1a; git clone https://gitee.com/csheng-gitee/vant-number-plate.git三、具…

IMYAI-人工智能聊天绘画机器人4.0 - 终身学习者的超级生产力工具!

什么是ChatGPT&#xff1f;ChatGPT能帮我干什么&#xff1f; 在开始之前&#xff0c;我们首先需要知道ChatGPT是什么。 ChatGPT 全名Chat Generative Pre-trained Transformer (聊天生成性预训练转换模型) 说简单点&#xff0c;ChatGPT就是一个AI聊天机器人&#xff0c;背后是一…

Redis(08)| 线程模型

一、redis 的线程模型 redis 内部使用文件事件处理器 file event handler&#xff0c;它是单线程的&#xff0c;所以redis才叫做单线程模型。它采用IO多路复用机制同时监听多个 socket&#xff0c;将产生事件的 socket 压入内存队列中&#xff0c;事件分派器根据 socket 上的事…

Vue3.3指北(四)

Vue3.3指北 1、WebPack - VueCLI1.1、WebPack安装VueCli1.2、vue create 创建项目1.3、项目目录结构介绍 2、ViteVue32.1、认识create-vue2.2、使用create-vue创建项目2.3、项目目录剖析2.4、ESlint代码规范及手动修复2.5、通过eslint插件来实现自动修正 3、VueRouter43.1、单页…

SpringCloud 微服务全栈体系(七)

第九章 Docker 一、什么是 Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署&#xff0c;环境不一定一致…

基于SpringBoot的个人博客系统

基于SpringBootVue的个人博客系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 系统公告 博客详情 后台发文 摘要 基于Spring Boot的个人博客系统是一种…

实用搜索小技巧——站在巨人的肩膀上看世界

文章目录 1. 关于搜索效率2. 谷歌搜索语法2.1 “” 限定关键词2.2 intitle 限定标题2.3 限定关键词限定标题2.4 allintitle 标题多个关键词2.5 intext 限定内容关键词2.6 inurl 限定网址关键词2.7 site 限定网址来源2.8 imagesize 限定图片尺寸2.9 filetype 限定文件格式 3. in…

8.自定义组件布局和详解Context上下文

pages/index.vue layout布局运行在服务端 1、在项目的目录下新建layout文件夹&#xff0c;并新建一个blog.vue布局文件 2、在页面中的layout函数里&#xff0c;返回刚才新建布局文件的名字blog就可以使用了 export default {...layout (context) {console.log(context)retu…

探索Vue 3和Vue 2的区别

目录 响应式系统 性能优化 Composition API TypeScript支持 总结 Vue.js是一款流行的JavaScript框架&#xff0c;用于构建用户界面。Vue 3是Vue.js的最新版本&#xff0c;相较于Vue 2引入了许多重大变化和改进。在本文中&#xff0c;我们将探索Vue 3和Vue 2之间的区别。 …

【中国知名企业高管团队】系列50:荣耀手机

今天为您介绍中国手机的一个“新势力”——荣耀。说是“新”是因为他单独运作的时间最短&#xff0c;说他“势力”是因为他的崛起自带光环&#xff0c;市场拓展和发展让OPPO、VIVO和小米都感到巨大的压力&#xff0c;可以说中国市场的大部分份额都被苹果、华为、OPPO、VIVO、小…

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器,看完薪水涨一千

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器 HashMap简单介绍HashMap在并发场景下的问题HashMap在并发场景下的替代方案ConcurrentHashMap如何在线程安全的前提下提升并发度1.71.8 JDK1.7的ConcurrentHashMap源码JDK1.8的ConcurrentHashMap源…

2016年上半年上午易错题(软件设计师考试)

以下媒体文件格式中&#xff0c;&#xff08; 12 &#xff09;是视频文件格式。 A &#xff0e; WAV B &#xff0e; BMP C &#xff0e; MP3 D&#xff0e;MOV 以下软件产品中&#xff0c;属于图像编辑处理工具的软件是&#xff08; 13 &#xff09;。 A &#xff0e; Po…

Flask 路由机制分析之一

一、前言 《Flask Run运行机制剖析》这篇我们讲了应用启动的内部机制&#xff0c;启动后就开始监听Http请求了&#xff0c;请求过来如何跳到对应的函数执行&#xff0c;这就是路由机制。我们沿用上一篇例子&#xff0c;来探究一下app.route("/")内部干了些什么事。 …