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

🎉🎉🎉 欢迎各位来到小白 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}{持续更新,期待关注!} 持续更新,期待关注!💖💖💖

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

现代挖掘机vr在线互动展示厅是实现业务增长的加速度

VR数字博物馆全景展示充分应用5G、VR全景、web3d开发和三维动画等技术&#xff0c;将实体博物馆整体还原到3D数字空间&#xff0c;让游客360全景漫游式参观&#xff0c;无论大小、贵重、破损的典藏展品都能通过3D建模技术&#xff0c;逼真重现到三维虚拟场景中&#xff0c;让参…

在全新ubuntu上用gpu训练paddleocr模型遇到的坑与解决办法

目录 一. 我的ubuntu版本![在这里插入图片描述](https://img-blog.csdnimg.cn/297945917309494ab03b50764e6fb775.png)二.首先拉取paddleocr源代码三.下载模型四.训练前的准备1.在源代码文件夹里创造一个自己放东西的文件2.准备数据2.1数据标注2.2数据划分 3.改写yml配置文件4.…

OS的Alarm定时器调度机制

调度表触发的任务在编译时就被静态定义&#xff0c;任务的触发时间和执行顺序是固定的。这种方式适用于已知的、固定的任务触发模式&#xff0c;例如周期性任务或事件驱动任务。而使用 Alarm 机制触发的任务具有更大的灵活性。Alarm 允许在运行时动态地设置和修改任务的触发时间…

Megatron-LM GPT 源码分析(三) Pipeline Parallel分析

引言 本文接着上一篇【Megatron-LM GPT 源码分析&#xff08;二&#xff09; Sequence Parallel分析】&#xff0c;基于开源代码 GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale &#xff0c;通过GPT的模型运行示例&#xff0c;从三个维…

论文阅读——GPT3

来自论文&#xff1a;Language Models are Few-Shot Learners Arxiv&#xff1a;https://arxiv.org/abs/2005.14165v2 记录下一些概念等。&#xff0c;没有太多细节。 预训练LM尽管任务无关&#xff0c;但是要达到好的效果仍然需要在特定数据集或任务上微调。因此需要消除这个…

基于边缘智能网关的储能系统安全监测管理方案

“储能系统充电”是配套新能源汽车产业发展的重要应用之一。得益于电池技术的发展&#xff0c;新能源汽车正逐步迈入快充时代&#xff0c;由于在使用快速充电桩时&#xff0c;可能导致用电峰值负荷超过电网的承载能力&#xff0c;对于电网的稳定性和持续性会有较大影响&#xf…

nodejs+vue+elementui+express酒店管理系统

登录&#xff1a;运行系统后&#xff0c;进行登录&#xff0c;可使用本系统。 客房预定&#xff1a;此界面先通过条件查询客房信息&#xff0c;然后进行客房预定。对预定的客房还可以取消和支付操作。 信息查询&#xff1a;可查询所有的公告信息&#xff0c;点击公告名称&#…

单目3D目标检测 方法综述——直接回归方法、基于深度信息方法、基于点云信息方法

本文综合整理单目3D目标检测的方法模型&#xff0c;包括&#xff1a;基于几何约束的直接回归方法&#xff0c;基于深度信息的方法&#xff0c;基于点云信息的方法。万字长文&#xff0c;慢慢阅读~ 直接回归方法 涉及到模型包括&#xff1a;MonoCon、MonoDLE、MonoFlex、CUPNet…

Unity的碰撞检测(五)

温馨提示&#xff1a;本文基于前一篇“Unity的碰撞检测(四)​​​​​​​”继续探讨两个游戏对象具备刚体的BodyType均为Dynamic&#xff0c;但是Collision Detection属性不同的碰撞检测&#xff0c;阅读本文则默认已阅读前文。 &#xff08;一&#xff09;测试说明 在基于两…

Git窗口打开vim后如何退出编辑(IDEA/Goland等编辑器)

最近在学习git高级操作过程中&#xff0c;遇到了一下问题&#xff1a; 我在学习Git合并多个commit为一个的时候&#xff0c;需要输入一个命令 git rebase -i HEAD~2 这说明已经是编辑模式了。当我写好后&#xff0c;我还按照原来在linux上的按下ESC键&#xff0c;但是只是光…

【错误解决方案】ModuleNotFoundError: No module named ‘cPickle‘

1. 错误提示 在python程序中试图导入一个名为cPickle的模块&#xff0c;但Python提示找不到这个模块。 错误提示&#xff1a;ModuleNotFoundError: No module named cPickle 2. 解决方案 实际上&#xff0c;cPickle是Python的pickle模块的一个C语言实现&#xff0c;通常用于…

分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测

分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测 目录 分类预测 | MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双向门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-CNN-BiGRU麻雀算法优化卷积双…

2023年中国机场建设标准、机场数量及机场系统投资完成情况分析[图]

机场&#xff0c;亦称飞机场、空港&#xff0c;较正式的名称是航空站。机场有不同的大小&#xff0c;除了跑道之外&#xff0c;机场通常还设有塔台、停机坪、航空客运站、维修厂等设施&#xff0c;并提供机场管制服务、空中交通管制等其他服务。 机场建设资质等级标准 资料来源…

2-多媒体数据压缩国际标准

文章目录 多媒体数据压缩编码的重要性和分类为什么要压缩?计算: 未压缩音频的数据率简答: 环绕声系统-作业题9(简述7.4.3全景声)计算: 未压缩图像的数据量-作业题10(估计尺寸及容量)计算: 未压缩视频的数据率 为什么能压缩?数据压缩编码的两大类无损压缩算法: LZ77-作业题6-(…

嵌入式中的MCU、ARM、DSP、FPGA

目录 “角色扮演” MCU ARM 特点 DSP 特点 FPGA 特点 应用 “角色扮演” MCU&#xff08;Microcontroller Unit&#xff09;、ARM&#xff08;Advanced RISC Machine&#xff09;、DSP&#xff08;Digital Signal Processor&#xff09;和FPGA&#xff08;Field-Progr…

DevOps与CI/CD的最佳实践

在当今的软件开发领域&#xff0c;DevOps&#xff08;开发与运维的结合&#xff09;和CI/CD&#xff08;持续集成/持续交付&#xff09;已经成为了不可或缺的一部分。它们不仅提高了软件开发的效率&#xff0c;还帮助团队更快地交付高质量的软件。本文将深入探讨DevOps文化和CI…

计算机网络重点概念整理-第五章 传输层【期末复习|考研复习】

第五章 传输层 【期末复习|考研复习】 计算机网络系列文章传送门&#xff1a; 第一章 计算机网络概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层 第七章 网络安全 计算机网络整理-简称&缩写 文章目录 第五章 传输层 【期末复习|考研复习…

替换所有的问号

这篇也是凑数的 哈哈.... 稍后会整合到算法通关第三关白银挑战 . 描述 : 给你一个仅包含小写英文字母和 ? 字符的字符串 s&#xff0c;请你将所有的 ? 转换为若干小写字母&#xff0c;使最终的字符串不包含任何 连续重复 的字符。 注意 : 不能 修改非 ? 字符 . 题目 : …

读图数据库实战笔记02_图数据建模

1. 概念 1.1. 实体 1.1.1. 通常用名词来表示 1.1.2. 描述一个领域中的事物或者事物类型 1.1.2.1. 汽车 1.1.2.2. 用户 1.1.2.3. 地理位置 1.1.3. 在逻辑模型和技术实现过程中&#xff0c;实体通常会变成“顶点” 1.2. 关系 1.2.1. 用动词&#xff08;或动词短语&#…

[量化投资-学习笔记003]Python+TDengine从零开始搭建量化分析平台-Grafana画K线图

在前面两个笔记&#xff1a; PythonTDengine从零开始搭建量化分析平台-数据存储 PythonTDengine从零开始搭建量化分析平台-MA均线的多种实现方式 中有提到使用 Grafana 画图&#xff0c;不过画的都是均线。除了均线&#xff0c;Grafana 非常人性的提供了 K线图模块 搭配 TDeng…