RV1126-OPENCV Mat理解和AT函数

article/2025/7/22 8:58:37

一.Mat概念

        Mat 是整个图像存储的核心也是所有图像处理的最基础的类,Mat 主要存储图像的矩阵类型,包括向量、矩阵、灰度或者彩色图像等等。Mat由两部分组成:矩阵头,矩阵数据。矩阵头是存储图像的长度、宽度、色彩信息等头部信息;矩阵数据则是存储具体的图像数据。(我的理解就是,Mat是把图像分为一块一块矩阵类型保存,矩阵头显示这张图片基本信息,如这张图片多大,是不是彩色;具体的信息存储由矩阵数据存储)。

二.Mat通道

图中C1,C2,C3,C4代表几通道 ;前面CV_8U,8S,16U,16S,32U,32S代表用什么类型存储,例如:CV_8U就是用8位无符号类型存储,CV_8S就是用8位有符号存储。

  •  单通道(灰度图),就是图片是灰色的

  •  双通道(二值图像),就是黑白照片

  •  三通道(RGB 彩色图像)

  •  四通道(带 Alpha 的四通道图像),就是ARGB图像,更好看一点。

 三.Mat创建和构造方法

  • Mat(int rows, int cols, int type);

 重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是 rows、cols 以及存储类型 type
rows:行数,也指的是图像的高度,height。
cols:列数,也指的是图像的宽度,width。
type:通道类型,具体的看上面的图
示例:Mat t1 = Mat(300,300,CV_8UC1),这指的是创建一个 width:300,height:300,单通道的灰度图像.

  •  Mat(Size size, int type);

 重载的构造函数,这个构造函数在创建的时候,需要传入 Size 类和类型。
第一个传参:Size 结构体,Size(width,height)
第二个传参:type 通道类型,具体的看上面的图
示例:Mat t2 = Mat(Size(300,300),CV_8SC3),这指的是创建一个 width:300,height:300,三通道的灰度图像

  •  Mat(int rows, int cols, int type, const Scalar& s);

 重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是 rows、cols、存储类型 type、还有 Scalar 颜色标量。
第一个传参:rows 行数,也指的是图像的高度,height。
第二个传参:cols 列数,也指的是图像的宽度,width。
第三个传参:type 通道类型,具体的看上面的图
第四个传参:Scalar 颜色标量,Scalar(v0,v1,v2,v3),v0,v1,v2,v3 分别对应 OPENCV 颜色分量的四个值
示例: Mat mat = Mat(300,300,CV_8UC3,Scalar(255,255,255));表示的是创建cols:300,rows:300,三通道的灰度,颜色标量为白色的图像

  • Mat::zeros(rows,cols,type); 

 重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是 rows、cols 以及存储类型 type。ZEROS 相当于创建一张黑色的图片,每个像素通道为 0,并且 Scalar(0,0,0)。
第一个传参:rows 行数,也指的是图像的高度,height。
第二个传参:cols 列数,也指的是图像的宽度,width。
第三个传参:type 通道类型,具体的看上面的图
示例: Mat::zeros(300,300,CV_8SC3);,这指的是创建一个 width:300,height:300,三通道的彩色图像,Scalar(0,0,0),相当于Mat mat = Mat(300,300,CV_8SC3,Scalar(0,0,0));

  •  Mat::ones(rows,cols,type);

 重载的构造函数,这个构造函数在创建的时候,提供矩阵的大小,分别是 rows、cols 以及存储类型 type。ONES 相当于每个像素第一个通道为 1,后面两个通道为 0。
第一个传参:rows 行数,也指的是图像的高度,height。
第二个传参:cols 列数,也指的是图像的宽度,width。
第三个传参:type 通道类型,具体的看上面的图
示例: Mat::ones(300,300,CV_8SC3),这指的是创建一个 width:300,height:300, 三通道的彩色图像,Scalar(1,0,0),这等同于 Mat mat = Mat(300,300,CV_8SC3,Scalar(1,0,0));

四. imread读取图片信息和imwrite写入数据

  1. imread:读取图片信息。

 Mat imread( const String& filename, int flags = IMREAD_COLOR );

第一个参数:filename 图片的名称,名称可以是绝对路径也可以是相对路径
第二个参数:flags 标识符,flags 标识符默认为 IMREAD_COLOR。flags 一般分为三种:
IMREAD_UNCHANGED(<0)按原样加载图像(包括 alpha 通道(如果存在)
IMREAD_GRAYSCALE(0)将图像作为强度加载(灰白照片)
IMREAD_COLOR(> 0)以 RGB 格式加载图像(彩色照片)

返回值:Mat 矩阵

  • 例如:读取彩色三通道图片

Mat img_mat = imread("frame1.jpg");
printf("width = %d, height = %d, channels = %d\n", img_mat.cols, img_mat.rows, img_mat.channels());
...........................................................................................
输出结果:width = 1920, height = 1080, channels = 3

  • 例如:读取灰白单通道图片

Mat img_mat_gray = imread("gray_frame1.jpg", IMREAD_GRAYSCALE);
printf("img_mat_gray_width = %d, img_mat_gray_height = %d, img_mat_gray_channels = %d\n", img_mat_gray.cols,img_mat_gray.rows, img_mat_gray.channels());
.................................................................................................................
输出的结果:img_mat_gray_width = 1920, img_mat_gray_height = 1080, img_mat_gray_channels = 1 

2. imwrite:保存图片

 imwrite(const String& filename, InputArray image, const std::vector<int>& params);

第一个传参:filename 表示要保存的文件名
第二个传参:image 表示需要保存的图像数据
第三个传参:params 保存图像可选参数,主要是设置图像的质量,设置规则具体的我们来看看,该参数需要按照参数 id+参数值成对出现,可以出现多对参数值(比如 (paramId_1, paramValue_1, paramId_2, paramValue_2, ...)),但必须保证这些参数对是相关的,比如保存 JPG 图像时,只能使用和 JPEG 相关的参数 ID 进行组合使用。这里的 ID 基本上是 cv::ImwriteFlags。

  • 例如:使用默认的方式 imwrite 保存图片

Mat mat = Mat(300,300,CV_8UC3,Scalar(218,112,214));
imwrite("mat_demo.jpg", mat);
。。。。。。。。。。。。。。。。。。
上面是使用默认的方法保存图片,这种方法的所有参数都是默认选项。出来图片就是:

  •  使用 params 的方式 imwrite 保存图片

Mat quality_frame1_mat = imread("frame1.jpg");
std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 40};
imwrite("quality_mat_demo.jpg", quality_frame1_mat , params);
。。。。。。。。。。。。。。。。。。。。。。。。。
这种方法使用的是 params 参数的方式去设置,上面我们设置了图像的质量在 40,大家如果想设置其他功能可以参考上面的枚举进行设置。经过编码质量 40 的处理后的图像大小小于原图像大小,这说明编码质量关乎着文件的大小和画面的质量

五.代码具体

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>using namespace cv; //Must Need Write cv
using namespace std;int main()
{//构造参数Mat t0 = Mat(300,300,CV_8UC1); //Create a 300x300 single channel matrixMat t1 = Mat(Size(200,200),CV_8UC1); //Create a 300x300 single channel matrixMat t2 = Mat(100,100,CV_8UC1,Scalar(255,255,255)); //Create a 300x300 single channel matrixMat t3 = Mat::zeros(300,300,CV_8UC1); //Create a 300x300 single channel matrixMat t4 = Mat::ones(200,200,CV_8UC1); //Create a 300x300 single channel matrixstd::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 40};//imwrite写入数据imwrite("t0.jpg",t0);imwrite("t1.jpg",t1);imwrite("t2.jpg",t2);imwrite("t3.jpg",t3,params);imwrite("t4.jpg",t4);//imread读取数据Mat a0 = imread("t0.jpg");Mat a1 = imread("t3.jpg");Mat a2 = imread("t4.jpg",IMREAD_GRAYSCALE);printf("a0 heigh:%d weigh: %d channel:%d\n",a0.rows,a0.cols,a0.channels());printf("a3 heigh:%d weigh: %d channel:%d\n",a2.rows,a2.cols,a2.channels());return 0;
}

六.AT函数

1.作用         

        AT函数:就是用于修改Mat矩阵的像素值(上面用Mat创建的图片,这个图片都是一格一格像素点形成的,我们要想修改图片颜色,就要用到AT函数对像素点值修改就行)。AT 函数的修改一般需要循环 cols 和 rows 然后对每个像素点进行修改。

2. 定义

        at<typename>(int i, int j)

第一个参数:typename 指的是 OPENCV 的向量类型,(总结:1,2,3,4就是几通道,也可以理解为几维图像;后面b,s,w,i之类就是用什么类型读取,整型,还是字符读取),向量类型如下:

typedef Vec<uchar, 2> Vec2b:uchar 类型的数组,长度为 2, 它表示的是二维图像的位置信息、尺寸等等
typedef Vec<uchar, 3> Vec3b:uchar 类型的数组,长度为 3,它常用于彩色图像的像素值以及对 rgb 三个通道的处理,并且通道的像素值都是 uchar 类型
typedef Vec<uchar, 4> Vec4b:uchar 类型的数组,长度为 4,它常用于彩色图像的像素值以及对 argb 四个通道的处理,并且通道的像素值都是 uchar 类型
typedef Vec<short, 2> Vec2s:short 类型的数组,长度为 2, 它表示的是二维图像的位置信息、尺寸等等,但不能做像素处理
typedef Vec<short, 3> Vec3s:short 类型的数组,长度为 3, 它常用于彩色图像的像素值以及对 rgb 三个通道的处理,并且通道的像素值都是 short 类型
typedef Vec<short, 4> Vec4s:short 类型的数组,长度为 4, 它常用于彩色图像的像素值以及对 argb 四个通道的处理,并且通道的像素值都是 short 类型
typedef Vec<ushort, 2> Vec2w:ushort 类型的数组,长度为 2,它表示的是二维图像的位置信息、尺寸等等,但不能做像素处理
typedef Vec<ushort, 3> Vec3w:ushort 类型的数组,长度为 3,它常用于彩色图像的像素值以及对 rgb 三个通道的处理,并且通道的像素值都是 ushort 类型
typedef Vec<ushort, 4> Vec4w:ushort 类型的数组,长度为 4,它常用于彩色图像的像素值以及对 argb 四个通道的处理,并且通道的像素值都是 ushort 类型
typedef Vec<int, 2> Vec2i: int 类型的数组,长度为 2, 它表示的是一个包含 2 个整数的元素向量,并不能直接表示通道数
typedef Vec<int, 4> Vec4i: int 类型的数组,长度为 4, 它常用于彩色图像的像素值以及对 argb 四个通道的处理,并且通道的像素值都是 int 类型
typedef Vec<int, 6> Vec6i: int 类型的数组,长度为 6, 它常用于表示六维图像,包括:坐标、描述子、颜色直方等等,但是不能对六维图像直接进行处理
typedef Vec<int, 8> Vec8i: int 类型的数组,长度为 8, 它常用于表示八维图像,包括:坐标、描述子、颜色直方等等,但是不能对八维图像直接进行处理
typedef Vec<float, 2> Vec2f:float 类型的数组,长度为 2,它表示的是二维图像的位置信息,但不能做通道处理
typedef Vec<float, 3> Vec3f:float 类型的数组,长度为 3,它常用于彩色图像的像素值以及对 rgb 三个通道的处理,并且通道的像素值都是浮点数
typedef Vec<float, 4> Vec4f:float 类型的数组,长度为 4,它常用于彩色图像的像素值以及对 argb 四个通道的处理,并且通道的像素值都是浮点数
typedef Vec<float, 6> Vec6f: float 类型的数组,长度为 4,他用于处理 6 个维度的图像数据,需要注意的是 Vec6f 仅仅能表示具有 6 个维度的数据,并不可以对数据进行操作.
typedef Vec<double, 2> Vec2d:double 类型的数组,长度为 2,在图像处理中 Vec2d 仅仅只是表示具有 double 类型的图像数据,但是并不能直接操作数据像素
typedef Vec<double, 3> Vec3d:double 类型的数组,长度为 3,它常用于表示图像的彩色三通道,分别是 R(红色)、G(绿色)、B(蓝色),并且对于这三个通道的像素值进行 double 类型数据的处理
typedef Vec<double, 4> Vec4d:double 类型的数组,长度为 4,它常用于表示图像的彩色四通道,分别是 A(透明度)、R(红色)、G(绿色)、B(蓝色),并且对于这四个通道的像素值进行 double 类型数据的处理。
需要注意的是:一般 OPENCV 对像素的处理大部分都是用 uchar 类型,其他类型用的很少。 

第二个参数:i,指的是 rows,图像的行数据
第三个参数:j,指的是 cols,图像的列数据

3.代码示例

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>using namespace std;
using namespace cv;int main()
{//修改三通道图片像素点值Mat img_mat = imread("frame1.jpg");//读取图片//用at函数遍历整个图片三通道像素点并修改像素点值for (int i = 0; i < img_mat.rows; i++){for (int j = 0; j < img_mat.cols; j++){img_mat.at<Vec3b>(i, j)[0] = img_mat.at<Vec3b>(i, j)[0] - 10;img_mat.at<Vec3b>(i, j)[1] -= 50;img_mat.at<Vec3b>(i, j)[2] -= 10;}        }//保存修改后的图片imwrite("frame2.jpg", img_mat);//修改单通道图片像素点值Mat grayImage;Mat before_Image;cvtColor(img_mat, before_Image, COLOR_RGB2GRAY);cvtColor(img_mat, grayImage, COLOR_RGB2GRAY);//用at函数遍历整个图片单通道像素点并修改像素点值for (int i = 0; i < grayImage.rows; i++){for (int j = 0; j < grayImage.cols; j++){grayImage.at<uchar>(i, j) = 50 - grayImage.at<uchar>(i, j);}}//保存修改后的图片imwrite("frame3.jpg", before_Image);imwrite("frame4.jpg", grayImage);return 0;
}


http://www.hkcw.cn/article/iYmQkdLFmy.shtml

相关文章

DeepSeek R1-0528模型:五大升级亮点,引领AI推理新高度

在AI技术迅猛发展的浪潮中&#xff0c;模型的迭代升级不断推动着行业的进步。DeepSeek R1-0528模型的推出&#xff0c;犹如一颗重磅炸弹&#xff0c;在AI领域激起千层浪。它究竟有何神奇之处&#xff1f;下面为你揭秘其五大全新升级亮点。 深度思考能力显著提升 DeepSeek R1-05…

司机缺氧离世有5个上学孩子 家庭重担引关注

近日,46岁的河南卡车司机常志荣在青藏高原离世,卡友团队一同将其骨灰接回老家。6月1日,常志荣已经在老家安葬。他去世后,留下了重组家庭的6个孩子,其中5个孩子还在上学。车友任先生透露,常大哥出发青藏线运输前,同行曾建议他至少携带两罐氧气,但他为省下30元费用,最终…

迪士尼情侣和一家三口打架 拍照争执引发冲突

6月1日,浦东公安分局接到报警称迪士尼乐园内发生打架事件。初步调查显示,闫某某(男,22岁)与女友在拍照时,因刘某某(男,36岁)夫妻的女儿进入拍摄画面,双方发生口角并引发肢体冲突,造成闫某某和刘某某互有皮外伤,小女孩未受伤。目前,调查处理工作正在进行中。当天,…

温度计“液泡”是什么,温度计为什么能测温?

温度计“液泡”是什么&#xff0c;温度计为什么能测温&#xff1f; 液体膨胀式温度计介绍 最近&#xff0c;有位小朋友说&#xff0c;他看的一本科普书上说&#xff1a;把温度计插在水里&#xff0c;水分子就会对液泡产生撞击&#xff0c;液泡里面的分子就会跟着动起来&#x…

C++学习过程分享

空指针&#xff1a;int *p NULL; 空指针&#xff1a;指针变量指向内存中编号为0的空间&#xff1b;用途&#xff1a;初始化指针变量注意&#xff1a;空指针指向的内存不允许访问注意&#xff1a;内存编号为0-255为系统占用空间&#xff0c;不允许用户访问 野指针&#xff1a;…

【IC】RTL功耗高精度预测

介绍 美国能源部&#xff08;DOE&#xff09;的一份综合报告“半导体供应链深度潜水评估”&#xff08;2022年2月&#xff09;呼吁将能源效率提高1000倍&#xff0c;以维持未来的需求&#xff0c;因为世界能源产量有限。能源效率是当今设计师的首要任务。能源效率的整体方法必…

美国要求澳大利亚上调军费 提升至GDP的3.5%

当地时间6月1日,美国国防部长赫格塞思在新加坡会见了澳大利亚副总理兼国防部长理查德马尔斯。双方讨论了美澳联盟的关键优先事项。赫格塞思在会谈中建议澳大利亚尽快将国防开支提高到国内生产总值的3.5%。尽管澳大利亚不是北约成员国,美国总统特朗普此前曾多次要求北约成员国…

高反缺氧去世卡友已回老家下葬 留下6个孩子引关注

近日,46岁的河南卡车司机常志荣在青藏高原不幸离世。他的卡友团队一同将其骨灰接回老家,并于6月1日在老家安葬。常志荣去世后,留下了重组家庭的六个孩子,其中五个孩子还在上学。车友任先生透露,常志荣出发前曾被建议至少携带两罐氧气,但他为了节省30元费用,最终只购买了…

亚历山大本赛季两战步行者场均39分 雷霆双胜步行者

NBA总决赛的对阵双方是雷霆和步行者。本赛季两队交手两次,雷霆分别以120-114和132-111取胜。这两场比赛中霍姆格伦都没有出战。亚历山大在这两场比赛中的表现非常出色,场均能够贡献39分、7篮板、8助攻、1抢断和1盖帽,场均罚球次数达到11.5次,真实命中率为71.1%。在面对步行…

六地将有大到暴雨 端午出行需谨慎

中央气象台今日6时继续发布暴雨蓝色预警和强对流天气蓝色预警。福建、广东、广西等六个地区将出现大到暴雨,多地还将遭遇8级以上的雷暴大风或冰雹天气。正值端午假期最后一天,出行前请务必关注天气情况。责任编辑:zhangxiaohua

017搜索之深度优先DFS——算法备赛

深度优先搜索 如果说广度优先搜索是逐层扩散&#xff0c;那深度优先搜索就是一条道走到黑。 深度优先遍历是用递归实现的&#xff0c;预定一条顺序规则&#xff08;如上下左右顺序&#xff09; &#xff0c;一直往第一个方向搜索直到走到尽头或不满足要求后返回上一个叉路口按…

举办中国户外运动展哪个城市较理想

杭州&#xff1a;强劲经济引擎&#xff0c;中国户外运动展的理想之选&#xff01; 为什么是杭州&#xff1f;—— 硬核实力&#xff0c;无可争议&#xff01; 经济活力领跑&#xff1a; 浙江人均GDP超2.5万美元&#xff0c;人均收入与消费全国TOP 1&#xff01;2024年省外人口…

JMeter接口自动化脚本框架

登录后的CRUD自动化脚本 内容&#xff1a; 用户自定义变量 ${}引用 HTTP请求默认值&#xff1a;复用内容 HTTP信息头&#xff1a;请求类型、token、cookie setUp、tearDown线程组&#xff1a;前后置操作 响应断言&#xff1a;文本、代码 Json提取器&#xff1a;提取响应…

缺氧离世卡车司机已下葬卡友发声 家庭重担引关注

近日,46岁的河南卡车司机常志荣在青藏高原离世,卡友团队将其骨灰接回老家。6月1日,他在老家安葬。常志荣去世后,留下了重组家庭的6个孩子,其中5个还在上学。据车友任先生透露,常志荣出发前同行曾建议他至少携带两罐氧气,但他为省下30元费用,最终只购买了一罐氧气。常志…

【C++】多态

目录 1. 多态的概念 2. 多态的定义和实现 2.1 构成多态的条件 2.2 虚函数 2.3 虚函数的重写&#xff08;覆盖&#xff09; 2.4 小试牛刀 3. 重载/重写/隐藏的对比 4. 纯虚函数和抽象类 5.多态的原理 5.1 虚表 5.2 虚表指针 5.3 对比虚函数、虚表、虚表指针 1. 多态的…

肖战演活了藏海 台湾观众好评如潮

正在热播的电视剧《藏海传》在台湾引起了广泛关注,不仅获得了岛内观众的一致好评,也得到了媒体的争相报道。这部剧以其精良的制作、紧凑的情节以及所展现的中华文化深深吸引了台湾观众。5月31日,“肖战演藏海在台湾刷屏”这一话题冲上了微博热搜榜。近年来,大陆电视剧在台湾…

C# 多线程编程全面指南:从基础到高级实践

在现代软件开发中&#xff0c;多线程编程已成为提升应用程序性能的关键技术。C# 作为.NET平台的主力语言&#xff0c;提供了丰富的多线程处理机制。本文将全面介绍C#中的多线程编程技术&#xff0c;从基础概念到高级应用&#xff0c;帮助开发者掌握这一重要技能。 一、多线程基…

PASCAL VOC数据集/AI标注/算法训练推理EasyAML如何实现“数据不出域”的本地化AI标注训练

在当今数字化转型的大潮中&#xff0c;众多企业对AI视觉技术的需求日益增长。无论是制造业的产品质量检测、物流行业的货物识别与车辆管理&#xff0c;还是安防领域的视频监控与分析&#xff0c;AI视觉技术的应用场景广泛且多样。然而&#xff0c;在实际应用过程中&#xff0c;…

Linux系统中的shell脚本基础知识

1.shell脚本基础&#xff1a;shell脚本是文本的一种&#xff0c;属于可以运行的文本&#xff0c;shell脚本的内容是由逻辑和数据组成的。 2.shell脚本意义&#xff1a;shell脚本语言是实现Linux/unix系统管理及自动化运维所必备的重要工具。 常见shell种类&#xff1a;Bourne …

C++修炼:位图和布隆过滤器

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 1、引言 在计算机科学…