OpenCV(c++) 矩阵 Mat 类的用法与注意事项
Mat类
基本介绍
Mat类是OpenCV中使用最频繁的类之一,用于储存矩阵数据及相关操作,也是程序中图像的主要形式。
Mat类主要由两部分组成:一个描述头(matrix header)及一个指向矩阵数据的指针。其中,描述头包含了矩阵的一些基本信息,如矩阵的尺寸,所占空间大小等。
Mat类有以下几个特点:
- Mat类会自动分配内存,使用者无需考虑内存的管理。(老版的OpenCV中使用IPIImage类,需要用户自己管理内存)
- Mat类使用了引用计数系统(Reference Counting System),不同的Mat对象可共享同一个矩阵的数据。
- 赋值号和拷贝构造只会拷贝描述头,不会开辟新的空间保存矩阵数据。在下面的例子中,如果B,C的值发生变化,那么A的值也会发生变化。
Mat A,C;
Mat B(A);
C = A;
- 如果想要矩阵数据一同被拷贝,则可用cv::Mat::clone()命令。
Mat D = A.clone();
声明与初始化
1. cv::Mat A(2, 2, cv::CV_8UC3, cv::Scalar(0,0,255));
2. cv::Mat B = cv::Mat::eye(4, 4, cv::CV_64F); // 单位矩阵
3. cv::Mat C = cv::Mat::ones(2, 2, cv::CV_32F); // 元素均为1的矩阵
4. cv::Mat D = cv::Mat::zeros(3, 3, cv::CV_8UC1); // 元素均为0的矩阵
其中,CV_8UC3中的’8’表示8个比特,'U’表示无符号(unsigned),'C3’表示通道有三个通道。即,A中像素值都为无符号类型,有8个比特长,并且有3个通道。
存储形式
Mat 类本质上是一个通用的矩阵类型,可存储不同类型的图像。灰度图和RGB图的存储形式有所不同,具体看下图。
除此之外,一般而言,每一行的数据在内存中的地址都是连续的,但不同的行之间不一定。可以用isContinuous()成员函数判断行与行之间地址是否连续。
访问Mat中的任意元素
可使用at()函数来访问任意元素。at()是一个函数模板,需要指定元素类型,一般而言,灰度图的元素类型为uchar,RGB图的元素类型为Vec3b,是一个三维的向量。具体使用方式如下 :
uchar gray = img_gray.at<uchar>(i,j); // 灰度图
auto r = img_rgb.at<cv::Vec3b>(i,j)[0]; // RGB图
auto g = img_rgb.at<cv::Vec3b>(i,j)[1];
auto b = img_rgb.at<cv::Vec3b>(i,j)[2];
img_rgb.at<cv::Vec3b>(i,j) = cv::Vec3b(0,0,0); // 将某一点赋值为0
获得 Mat 的维度
cv::Mat m;
// do something to m
int channels = m.channels(); // 通道数
int rows = m.rows; // 行数
int cols = m.cols; // 列数
扫描整副图像
扫描图像上的每个元素,本质上就是要访问Mat矩阵中的每个元素。主要有三种方式扫描图像:
- 用指针扫描:
用成员函数ptr< type >()获取矩阵某一行首元素的指针,达到访问元素的目的。由于每一行的内存是连续的,因此能够按顺序扫描矩阵,效率较高。
// 用C语言的[]运算符访问
Mat &ScanImageAndReduceC(Mat& I, const uchar* const table) {CV_Assert(I.depth() == CV_8U);int channels = I.channels();int nRows = I.rows;int nCols = I.cols*channels;// 一般而言,每一行的数据在内存中都是连续的;但不同行之间可能会有所不同if (I.isContinuous()) {nCols *= nRows;nRows = 1;}uchar *p;for (int i = 0; i < nRows; ++i) {p = I.ptr<uchar>(i);//获得第i行的首指针for (int j = 0; j < nCols; ++j) {p[j] = table[p[j]];}}return I;
}
- 用迭代器扫描
成员函数begin< type >()和end< type >()可获取Mat类的迭代器,进行数据元素的遍历。这种方法相比第一种方法更安全,不会有下标溢出的问题,但效率更低。
// 用迭代器迭代
Mat& ScanImageAndReduceIterator (Mat &I, const uchar* const table) {CV_Assert(I.depth() == CV_8U);const int channels = I.channels();switch (channels){case 1:{MatIterator_<uchar> it, end;for (it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) {*it = table[*it];}break;}case 3:{MatIterator_<Vec3b> it, end;for (it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it) {(*it)[0] = table[(*it)[0]];(*it)[1] = table[(*it)[1]];(*it)[2] = table[(*it)[2]];}break;}}return I;
}
- 通过at()函数扫描
该方法本质上是依次任意访问矩阵中的每一个元素,在遍历时,每一个循环都要重新计算指针的地址,因此效率更低。但这种方式最直观,可读性高。
// 利用at()函数随机访问元素,达到扫描的效果
Mat& ScanImageAndReduceRandomAccess (Mat &I, const uchar* const table) {CV_Assert(I.depth() == CV_8U);const int channels = I.channels();switch (channels){case 1:{for (int i = 0; i < I.rows; ++i) {for (int j = 0; j < I.cols; ++j) {I.at<uchar>(i,j) = table[I.at<uchar>(i,j)];}}break;}case 3:{for (int i = 0; i < I.rows; ++i) {for (int j = 0; j < I.cols; ++j) {I.at<Vec3b>(i,j)[0] = table[I.at<Vec3b>(i,j)[0]];I.at<Vec3b>(i,j)[1] = table[I.at<Vec3b>(i,j)[1]];I.at<Vec3b>(i,j)[2] = table[I.at<Vec3b>(i,j)[2]];}}break;}}return I;
}
图像操作
Input/Output/Visualizing
Mat img = imread(filename, IMREAD_GRAYSCALE);
// Mat img = imread(filename, IMREAD_COLOR);
if (img.empty()) {cout << "something wrong\n";
}
imwrite(filename, img);
namedWiodow("demo", WINDOW_AUTOSIZE);
imshow("image", img);
waitKey(0);
访问某一像素值
- 灰度图:
Scalar intensity = img.at<uchar>(y,x);
- RGB图:
Vec3b intensity = img.at<Vec3b>(y,x);
uchar b = intensity.val[0];
uchar g = intensity.val[1];
uchar b = intensity.val[2];
选择某一子区域
Rect r(top_x, top_y, width, height);
Mat subMatrix = img(r);
颜色空间转换
Mat img = imread(filename, IMREAD_COLOR);
Mat grey;
cvColor(img, grey, COLOR_BGR2GRAY);
线性加权
可使用addWeighted函数进行线性加权:
addWeighted(src1, alpha, src2, beta, 0.0, dst);
其中,参数含义如下:
模板运算
可使用filter2D()函数对图片进行模板运算。
Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,-1, 5, -1,0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
其他常用函数
- saturat_cast< T >(): 防止数值溢出
- CV_Assert(): 相当于Python中的assert
OpenCV(c++) 矩阵 Mat 类的用法与注意事项相关推荐
- 【从零学习OpenCV 4】Mat类介绍
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 基于c++版本的opencv操作(Mat类)
图像的基本操作(一) 前言 一.Mat类? 1.c++版本代码 添加链接描述 前言 一.Mat类? 1.c++版本代码 1.1 at()函数 1.2 使用迭代器 2.代码结果展示 2.1 at()函数 ...
- openCV图像矩阵Mat和二维数组的互相转换
openCV图像矩阵Mat和二维数组的互相转换 在openCV的应用中,我们获取图像的矩阵信息很简单.但是我们可能想调用其他的矩阵运算库(比如Eigen库)来进行计算.那么我们就需要把openCV读取 ...
- 【从零学习OpenCV 4】Mat类构造与赋值
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 如何将OpenCV中的Mat类绑定为OpenGL中的纹理
https://blog.csdn.net/TTTTzTTTT/article/details/53456324 如果要调用外接的USB摄像头获取图像通常使用OpenCV来调用,如何调用摄像头请参考本 ...
- Opencv中Mat类详细解读(学习笔记)
基于windows10.vs2015.OpenCv4.1.0. 目录 1.Mat类简介 2.Mat类的构造与赋值 2.1.Mat类的构造 2.2.Mat类的赋值 3.Mat类支持的运算 3.1Mat类 ...
- OpenCV Mat类详解和用法(官网原文)
参考文章:OpenCV Mat类详解和用法 我马克一下,日后更 官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_i ...
- OpenCV Mat类详解和用法
OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...
- OpenCV中Mat类的重载运算符operator()的用法
图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 定义如下: inline Mat Mat::op ...
最新文章
- java圆周率流程图,流程图、PI图入门知识 课件.doc
- IT项目管理总结:第九章 项目人力资源管理
- 【推荐一位Python大佬】 从程序员到创业者,再到自由职业
- 阿里云张毅萍:构建边缘云全站加速网络体系
- 二叉树的最小深度Python解法
- linux超级工具,linux运维超级工具--sysdig
- 对于原型链的彻底理解
- Learn For Flutter
- 回顾2019,展望2020
- 谭浩强c语言第六版答案,C语言谭浩强版本第6章课后练习题答案
- TP340G+硬改山寨UBNT,
- [ZJOI2008]树的统计
- dota2服务器位置设置在哪里,《DOTA2》自走棋国服怎么进入 自走棋国服服务器进入方法...
- 苹果macbookpro多少钱_买一套可用的苹果全家桶,要花多少钱?
- MySQL 排序 输出序号
- IPSEC对称解密以及非对称加密
- MySql存储过程与函数
- Code_Aster comm命令文件结构与说明(by Yang 2017.3.30)
- N+1 架构支持更高的电源可靠性
- 声源分离算法性能评估指标SIR、SDR、SAR
热门文章
- 换行样式不要首行缩进_CSS实现文章段落首行缩进两个字符不再每次空格
- 工业互联网平台七大核心技术
- 工业大数据云平台,设备大数据云平台
- cv2.imwrite()不能成功保存图片
- 杰里之AC695N/AC696N 蓝牙耳机PCB LAYOUT 说明【篇4】
- 互联网日报 | 天猫京东618再创新纪录;字节跳动成立抖音电商部门;全国普速铁路20日起实施电子客票...
- StartCom 申请 免费的SSL 证书(绑定多个域名)
- 生成带图片无白边的二维码
- linux more 结合 grep查询日志信息
- unity 网络检测