OpenCV3入门(二)Mat操作
1、Mat结构
1.1、Mat数据
Mat本质上是由两个数据部分组成的类:
矩阵头:包含信息有矩阵的大小,用于存储的方法,矩阵存储的地址等
数据矩阵指针:指向包含了像素值的矩阵。
矩阵头部的大小是恒定的,矩阵本身的大小因图像的不同而不同,通常是较大的数量级。
在程序中传递图像并在有些时候创建图像副本需要花费很大的代价生成图像矩阵本身,而不是图像的头部。为了解决这一问题 OpenCV 使用引用计数系统。其思想是Mat的每个对象具有其自己的头,但可能他们通过让他们矩阵指针指向同一地址的两个实例之间共享该矩阵。此外,拷贝运算符将只能复制矩阵头部,也还将复制指针到大型矩阵,但不是矩阵本身。如果需要复制矩阵的本身,要使用 clone() 或 copyTo() 函数。
其中 Mat 类中有一些基本属性:
cols :矩阵列数
rows:矩阵行数
channels:通道数
type:数据类型
total:矩阵总元素数
data:指向矩阵数据块的指针
1.2、Mat数据类型定义
其中 Mat 排列方式如下:
CV_[位数][带符号与否][类型前缀]C[通道数]
带符号与否:S为符号整型,U为无符号整型,F为浮点型
例如CV_8UC3

多通道数据类型的定义如下:
#define CV_8U 0
#define CV_8S 1
#define CV_16U 2
#define CV_16S 3
#define CV_32S 4
#define CV_32F 5
#define CV_64F 6
#define CV_USRTYPE1 7 #define CV_MAT_DEPTH_MASK (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags) ((flags) & CV_MAT_DEPTH_MASK)
#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
#define CV_MAKE_TYPE CV_MAKETYPE #define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
2、Mat应用
2.1 构造函数
() Mat::Mat()
() Mat::Mat(int rows, int cols, int type)
() Mat::Mat(Size size, int type)
() Mat::Mat(int rows, int cols, int type, const Scalar& s)
() Mat::Mat(Size size, int type, const Scalar& s)
() Mat::Mat(const Mat& m)
() Mat::Mat(int rows, int cols, int type, void* data, size_t step = AUTO_STEP)
() Mat::Mat(Size size, int type, void* data, size_t step = AUTO_STEP)
() Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
() Mat::Mat(const Mat& m, const Rect& roi)
() Mat::Mat(const CvMat* m, bool copyData = false)
() Mat::Mat(const IplImage* img, bool copyData = false)
() template<typename T, int n>explicit Mat::Mat(const Vec<T, n>& vec, bool copyData = true)
() template<typename T, int m, int n> explicit Mat::Mat(const Matx<T, m, n>& vec, bool copyData = true)
() template explicit Mat::Mat(const vector& vec, bool copyData = false)
() Mat::Mat(const MatExpr& expr)
() Mat::Mat(int ndims, const int* sizes, int type)
() Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)
() Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps = )
2.2 创建Mat类型数据
1)使用Mat构造函数创建
Mat mat = Mat(, , CV_8UC1); cout << "rows="<<mat.rows << ",cols=" << mat.cols << endl; cout << mat << endl;
输出:
|
rows=2,cols=3 [205, 205, 205; 205, 205, 205] |
创建三通道矩阵Mat mat(2, 3, CV_8UC3);输出如下。
|
rows=2,cols=3 [205, 205, 205, 205, 205, 205, 205, 205, 205; 205, 205, 205, 205, 205, 205, 205, 205, 205] |
创建三通道矩阵Mat mat(2, 3, CV_8UC3, Scalar(0,0,255)
|
rows=2,cols=3 [ 0, 0, 255, 0, 0, 255, 0, 0, 255; 0, 0, 255, 0, 0, 255, 0, 0, 255] |
2)使用Create函数进行初始化
Mat M;
M.create(, , CV_8UC1);
cout << "M = " << endl << " " << M << endl << endl;
输出如下。
|
M = [205, 205, 205; 205, 205, 205] |
3)使用标准函数进行特定矩阵初始化
Mat M;
M = Mat::eye(, , CV_8U);
Mat M1 = Mat::ones(, , CV_8U);
Mat M2= Mat::zeros(, , CV_8U);
cout << "M = " << endl << " " << M << endl << endl;
cout << "M1 = " << endl << " " << M1 << endl << endl;
cout << "M2 = " << endl << " " << M2 << endl << endl;
输出如下。
|
M = [ 1, 0, 0, 0; 0, 1, 0, 0; 0, 0, 1, 0; 0, 0, 0, 1] M1 = [ 1, 1, 1, 1; 1, 1, 1, 1; 1, 1, 1, 1; 1, 1, 1, 1] M2 = [ 0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 0, 0; 0, 0, 0, 0] |
输出Mat矩阵可以格式化不同的形式,如下所示。
cout <<"M = "<< endl <<" "<< format( M, Formatter::FMT_PYTHON) << endl << endl;
M =
[[ 1, 0, 0, 0],
[ 0, 1, 0, 0],
[ 0, 0, 1, 0],
[ 0, 0, 0, 1]]
2.3 Mat操作像素
1. at定位符访问
2、指针访问
3.迭代器iterator访问
1)Mat::at
Mat数据结构,操作灰度图像像素点:
int gray_value = (int) image.at<uchar>(i , j) ;
操作彩色图像像素点:
int color_value = (int) image.at<Vec3b>(i , j) [k];
其中:
gray_value中存放灰度值,image是读入的图像,i表示行,j表示列;
color_value中存放彩色像素值,image是读入的图像,i表示行,j表示列,k表示通道,即R、G、B,取值范围为2、1、0.
template<typename T> T& Mat::at(int i)const
template<typename T> const T&Mat::at(int i) const
template<typename T> T& Mat::at(int i,int j)
template<typename T> const T&Mat::at(int i, int j) const
template<typename T> T& Mat::at(Pointpt)
template<typename T> const T&Mat::at(Point pt) const
template<typename T> T& Mat::at(int i,int j, int k)
template<typename T> const T&Mat::at(int i, int j, int k) const
template<typename T> T& Mat::at(constint* idx)
template<typename T> const T&Mat::at(const int* idx) const
参数
i –索引 0 维度
j – 1 维度的索引
k – 沿 2 维度的索引
pt – Point(j,i) 作为指定元素的位置。
idx – Mat::dims 数组的索引
int main() {
Mat M= Mat::eye(, , CV_8U);
for(int i=; i<M.rows; i++)
for (int j = ; j < M.cols; j++)
{
M.at<uchar>(i, j) = j / * ;
}
imshow("pic1", M);
waitKey();
}

2)指针访问
Mat mat = Mat(, , CV_8UC1);
cout << "rows=" << mat.rows << ",cols=" << mat.cols << endl;
for (int i = ; i < mat.rows; i++)
{
uchar* row = mat.ptr<uchar>(i); // 行指针
for (int j = ; j < mat.cols; j++) // 遍历每一行
{
row[j] = (uchar)((j / 5) * );
}
}
cout << "M = " << endl << " " << format(mat, Formatter::FMT_PYTHON) << endl << endl;
waitKey();
输出如下。
|
rows=10,cols=15 |
3)迭代器iterator访问
Mat M = Mat(, , CV_8UC3);
cout << "rows=" << M.rows << ",cols=" << M.cols << endl; Mat_<Vec3b>::iterator it = M.begin<Vec3b>();//初始位置的迭代器
Mat_<Vec3b>::iterator itend = M.end<Vec3b>();//终止位置的迭代器
for (; it != itend; it++)
{
//处理BGR三个通道
(*it)[] = ;//B
(*it)[] = ;//G
(*it)[] = ;//R
}
imshow("pic1", M);
使用下面配色表实验:

配色1: RGB(182,194,154)

配色2:RGB(229,131, 8)

2.4 其他数据结构
1)点的表示:Point
Point p1 = { , };
Point p2 = Point2i(, );
Point2f p3;
p3.x = 1.1;
p3.y = 1.2;
cout << "p1=" << p1 << endl;
cout << "p2=" << p2 << endl;
cout << "p3=" << p3 << endl;
waitKey();
输出为:
p1=[2, 3]
p2=[3, 4]
p3=[1.1, 1.2]
2)颜色表示:Scalar
Scalar(r, g, b)分别表示红绿蓝颜色。
3)尺寸的表示:Size
Size a = Size(, );
cout <<"a.width=" << a.width << ":a.height=" << a.height;
输出为:
a.width=5:a.height=6
4)矩形的表示:Rect
Rect rect = Rect(, , , ); // 参数:x、y、width、height
cout << rect.area() << endl; //返回rect的面积 200
cout << rect.size() << endl; //返回rect的尺寸 [10 × 20]
cout << rect.tl() << endl; //返回rect的左上顶点的坐标 [100, 50]
cout << rect.br() << endl; //返回rect的右下顶点的坐标 [110, 70]
cout << rect.width << endl; //返回rect的宽度 10
cout << rect.height << endl; //返回rect的高度 20
cout << rect.contains(Point(, ) ) << endl; //返回布尔变量,判断是否包含Point点
输出为:
|
200 [10 x 20] [100, 50] [110, 70] 10 20 1 |
3、参考文献
1、Mat - The Basic Image Container
https://docs.opencv.org/master/d6/d6d/tutorial_mat_the_basic_image_container.html
2、cv::Mat Class Reference
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html
3、OpenCV Mat 常用的基础知识
https://blog.csdn.net/Librarvl/article/details/89892352
4、OpenCV Mat类详解和用法
https://blog.csdn.net/Mason_Mao/article/details/82254285
5、《OpenCV3 编程入门》 , 电子工业出版社,毛星雨著
尊重原创技术文章,转载请注明。
OpenCV3入门(二)Mat操作的更多相关文章
- Thinkphp入门 二 —空操作、空模块、模块分组、前置操作、后置操作、跨模块调用(46)
原文:Thinkphp入门 二 -空操作.空模块.模块分组.前置操作.后置操作.跨模块调用(46) [空操作处理] 看下列图: 实际情况:我们的User控制器没有hello()这个方法 一个对象去访问 ...
- 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...
- Swift语法基础入门二(数组, 字典, 字符串)
Swift语法基础入门二(数组, 字典, 字符串) 数组(有序数据的集) *格式 : [] / Int / Array() let 不可变数组 var 可变数组 注意: 不需要改变集合的时候创建不可变 ...
- DevExpress XtraReports 入门二 创建 data-aware(数据感知) 报表
原文:DevExpress XtraReports 入门二 创建 data-aware(数据感知) 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的, ...
- 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...
- [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么? http://www.52im.net/thread-1732-1-1.html 1.引言 本文接上篇<脑残式网 ...
- C#基础入门 二
C#基础入门 二 循环语句 与C语言中用法相同. continue:结束本次循环(continue)后面的代码不再执行,进入下次循环(通常与if连用). 数组 一维数组定义:int[] intArra ...
- Android入门之文件系统操作
Android入门之文件系统操作(二)文件操作相关指令 (转) (一)获取总根 File[] fileList=File.listRoots(); //返回fileList.length为1 // ...
- redis入门(二)
目录 redis入门(二) 前言 持久化 RDB AOF 持久化文件加载 高可用 哨兵 流程 安装部署 配置技巧 集群 原理 集群搭建 参考文档 redis入门(二) 前言 在redis入门(一)简单 ...
随机推荐
- C# 字段与属性的区别
在C#中,我们可以非常自由的.毫无限制的访问公有字段, 但在一些场合中,我们可能希望限制只能给字段赋于某个范围的值.或是要求字段只能读或只能写, 或是在改变字段时能改变对象的其他一些状态,这些单靠字段 ...
- 【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)
[题解]LOJ2759. 「JOI 2014 Final」飞天鼠(最短路) 考虑最终答案的构成,一定是由很多飞行+一些上升+一些下降构成. 由于在任何一个点上升或者下降代价是一样的,所以: 对于上升操 ...
- Electron-forge应用(打包填坑)
Electron-forge应用 一. 使用Electron-Forge做应用的缘由 最近遇到一个需求,Web应用登录时要校验用户的登录Mac地址,以确定该用户是在授权过的电脑设备上登录的.没错 ...
- CentOS防火墙iptables使用
1.1 企业安全优化配置原则 尽可能不给服务器配置外网ip ,可以通过代理转发或者通过防火墙映射.并发不是特别大情况有外网ip,可以开启防火墙服务高并发的情况,不能开iptables,会影响性能,利用 ...
- dos2unix命令 – 将DOS格式的文本文件转换成UNIX格式
今天做题的时候,出现了个很冷门的: 查找子目录src下所有后缀为.txt的文件执行dos2unix命令,把文件从Dos格式转换为Linux格式,正确的命令是:find src "*.txt& ...
- DNS自述:我是如何为域名找到家的
对于互联网一代的我们,一出生就学会使用电脑.当我们对着浏览器地址栏输入www.baidu.com的时候,百度的首页就出现在面前.但你可曾想过,为什么我们输入www.baidu.com就可以弹出百度首页 ...
- 【转】ArcGIS Server 10.1 动态图层—更改风格
在 ArcGIS Server REST API中我们可以通过向Graphicslayer中添加临时图元的方法来完成对显示结果的渲染:如果仅仅是更改原有地图服务显示风格,在ArcGIS10.1下使用动 ...
- echarts设置网格线颜色
xAxis: { type: 'value', //设置网格线颜色 splitLine: { show: true, lineStyle:{ color: ['#315070'], width: 1, ...
- ThreadLocal = 本地线程?
一.定义 ThreadLocal是JDK包提供的,从名字来看,ThreadLocal意思就是本地线程的意思. 1.1 是什么? 要想知道他是个啥,我们看看ThreadLocal的源码(基于JDK 1. ...
- C#实现DataTable转.CSV文件
将DataTable转换成CSV文件是一种常见的转换形式,主要通过遍历Table的每行,再对每行遍历每列,实现对数据的读取,然后用分隔符分隔Table的每个栏位数据,把读取的字符写入到CSV文件中.这 ...