转载自知乎博主:逍遥王可爱   https://zhuanlan.zhihu.com/p/258369721

1.Mat是什么

Mat是一种图像容器,是二维向量,灰度图的Mat一般存放<uchar>类型,RGB彩色图像一般存放<Vec3b>类型。

单通道灰度图数据存放样式:

RGB三通道彩色图存放形式不同,每列并列存放通道数量的子列(注意通道数量反转为了BGR):

通常情况下Mat的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,在用指针访问时可以提供很大方便。可以用 isContinuous()函数来判断图像数组是否为连续的,语句为

if (img.isContinuous()){}

2.如何创建Mat对象

Mat到底有哪些参数呢,OpenCV官方文档对Mat的描述如下:

class CV_EXPORTS Mat
{
public:
// ... a lot of methods ...
...
/*! includes several bit-fields:
- the magic signature
- continuity flag
- depth
- number of channels
*/
int flags;
//! the array dimensionality, >= 2
int dims;
//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
int rows, cols;
//! pointer to the data
uchar* data;
//! pointer to the reference counter;
// when array points to user-allocated data, the pointer is NULL
int* refcount;
// other members
...
};

当我们用构造函数创建一个Mat对象的时候,可以指定图像的数据类型有CV_8UC1、CV_8UC3、CV_32FC1、CV_32FC3等多种形式,如定义

Mat img(480, 640, CV_16UC1);

就是创建一个640*480的16位深的单通道Mat对象。CV_8UC3自然就是最常见的8位3通道图(即255的RGB图像)。

当然最常用的是用opencv读入一张本地图像,此时自动就是一个Mat对象,但有时我们需要像python里的numpy那样方便地转换Mat对象的数据类型,numpy里可以这样操作

img=img.astype(np.uint16)#此时转为了16位深的无符号整数类型

在C++的opencv里,就是这样转为16位的无符号整数三通道的:

using namespace cv;
Mat Data = imread("xxxx.jpg");
Mat output;
Data.convertTo(output,CV_16UC3);//想覆盖原图的话直接Data,convertTo(Data,CV_16UC3);即可

Mat也可以通过深拷贝创建一个新地址的Mat,避免影响原始的Mat:

Mat copy;
image.copyTo(copy);
//也可用下面的语句
Mat copy = image.clone();

除此之外,python的numpy里经常采用如下的方式构建全1的矩阵:

import numpy as np
FULL_KERNEL_5 = np.ones((5, 5), np.uint8)

那么c++里如何构建这样的Mat呢?

Mat kernel = Mat::ones(3,3,CV_8UC1);

这样就创建了一个全为1的矩阵了(类似的可以zeros等等是一样的创建方法)。

有时我们对图像进行一些像素值的缩放,也就是对某个图像进行全部元素的加减乘除,python里自然非常方便,如所有元素除以100,那么image / 100.0即可。c++里使用convertTo非常容易实现这点(不必for循环了)。

如果我们要对矩阵A进行元素的加减乘除操作得到B,即B=a*A+b,则

A.convertTo(B,CV_32F,a,b);

举个例子,刚刚提到的全部元素除以100那就是

A.convertTo(B,CV_32F,0.01,0.00);

Mat也支持自己给值初始化:

Mat T_cam_in_O_g0 = (Mat_ <float>(1, 3) << 8, -2.60446658, -8.59534703);

如果要把已存在的vector转为Mat,那怎么转呢?

一维vector转Mat:

cv::Mat convertVector2Mat(vector<float> v, int rows)
{     cv::Mat mat = cv::Mat(v);//将vector变成单列的mat     cv::Mat dest = mat.reshape(1, rows).clone();//PS:必须clone()一份,否则返回出错     return dest;
}

二维vector转Mat:

void two_d_vector2Mat(vector<vector<float>> src,Mat &dst)
{Mat temp(src.size(),src.at(0).size(),CV_32FC1);for(int i=0; i<temp.rows; ++i)for(int j=0; j<temp.cols; ++j)temp.at<float>(i, j) = src.at(i).at(j);temp.copyTo(dst);
}

3.Mat对象如何访问元素

从Mat的类定义看,用data可以方便访问图像元素值。用Mat存储一幅图像时,若图像在内存中是连续存储的(即Mat对象的isContinuous == true),则可将图像的数据看成是一个一维数组,而其data(uchar*)成员就是指向图像数据的第一个字节的指针,因此可以用data指针访问图像数据,OpenCV中将data定义为uchar*类型。那么我们如何通过data指针去访问和修改图像的某一个像素值呢,对于数据为uchar类型的Mat对象,可以直接用data访问和修改,对于其他类型的Mat对象,将data强制转换成指向Mat对象对应数据类型的指针即可访问。

可以把Mat对象方便地转为一维指针数组,便于指针操作(指针访问数组进行操作速度更快):

unsigned short* Array = (unsigned short*)Data.data;
delete[] Array;

当然借用opencv里Mat类的智能指针最佳,这样即可auto data = Data.ptr();

对这个数组进行了一系列图像处理操作后,如果要保存回Mat便于后续imshow和imwrite,保存方式可以这样:

Mat newData(480, 640, CV_16UC3, Array);

当然这样是灵活的提供了自己创的指针,用了后还需要delete,为了方便可以用Mat自带的智能指针进行操作。

这里举一个实例:如果我们只对像素值小于0.1的像素才执行膨胀操作(也就是为了填充0),python里搞一个mask就可以轻易实现

empty_pixels = (image < 0.1)
dilated = cv2.dilate(image)
depth_map[empty_pixels] = dilated[empty_pixels]

在c++里则不然,用智能指针可以这样操作:(构建行智能指针数组)

 Mat depth_tmp;//初始化一个矩阵备用dilate(image, tmp);for (int k = 0; k < 480; k++){auto *data1 = image.ptr<float>(k);//创建行智能指针auto *data2 = tmp.ptr<float>(k);for (int q = 0; q < 640; q++){if (data1[q] < 0.1)//小于0.1的视作空像素(空洞){data1[q] =  data2[q];//对于image里的的空洞,把tmp赋给image}}}

这样使用智能指针也可以(这样可以操作每个元素了,但速度慢于上面的方法)

 for (int k = 0; k < 480; k++){for (int q = 0; q < 640; q++){auto *ptr = depthArray.ptr<uint16_t>(k, q);if (ptr[0] ==0){ptr[0] = 10;}}}

当然也可以不用指针,而是用at方法去读取任意的[i,j]位置(i为多少行,即y坐标,j为多少列,即x坐标)的像素值,但这个方法速度慢于指针读取的方法,depthArray.at<uint16_t>(i, j)。

4.Mat的计算

转置:mat.t()

求逆:cv::invert(matrix, mat_inv, DECOMP_LU);

但这里invert得到的是double类型,转为float
       mat_inv.convertTo(mat_inv, CV_32FC1);

矩阵乘法:A*B(当然A可以是矩阵也可是某个标量)

矩阵取某行/列或者某些行/列:out_mat = mat.colRange(0,2).clone();//复制第0列和第1列(注意左闭右开)

如果需要把某个Mat结果(这里是result)存入到float *out这样的指针当中,这时可以用memcpy

memcpy(out, result, sizeof(float) * result.rows * result.cols);

Opencv的Mat内容小记相关推荐

  1. OpenCV实现Mat与vector,Mat与数组互转

    OpenCV实现Mat与vector互转 [尊重原创,转载请注明出处]https://blog.csdn.net/guyuealian/article/details/80253066 1.Mat与v ...

  2. C++下的OpenCV中Mat类型存储的图像格式

    在调用CV进行图像处理时,经常涉及图像格式转换,经常出现原始图像输入后CV_32F与ushort之间的数据差异导致程序报错,可使用std::cout << "dilated_ty ...

  3. 一句代码将OpenCV的Mat对象的数据打印输出

    查看阵列的数据值在MATLAB和Python-Pycharm中是非常简单的. MATLAB直接在工作区查看即可,如下图所示: Python-Pycharm在调试时就可以看到阵列的内容,如下图所示: 但 ...

  4. android都图片mat_计算机视觉 OpenCV Android | Mat像素操作(图像像素的读写、均值方差、算术、逻辑等运算、权重叠加、归一化等操作)...

    本文目录 1. 像素读写 2. 图像通道与均值方差计算 3. 算术操作与调整图像的亮度和对比度 4. 基于权重的图像叠加 5. Mat的其他各种像素操作 1. 像素读写 Mat作为图像容器,其数据部分 ...

  5. OpenCV之Mat与Bitmap之间的转换

    我们想在Android平台上开发OPenCV(处理图像):避免不了显示,通常在Android当中展示图像都是通过ImageView这个控件,当然展示的方式也有几种,在下面的内容中会简单介绍一下.但是我 ...

  6. 在ROS下利用OpenCV的Mat类,将激光点云展开为深度图像(从零开始,超详细)

    激光雷达3D目标检测任务需要将地面滤除,滤除地面的方法多种多样:基于深度学习.基于栅格.基于平面拟合.基于条件随机场.基于深度图像等等.关于将点云转化为深度图像,PCL库中有相关函数,但使用起来有一定 ...

  7. mat opencv java_OpenCV Mat到JavaCV Mat转换

    您可以使用java.awt.image.BufferedImage作为接口. 您org.opencv.core.Mat对象只是转换为java.awt.image.BufferedImage中再取结果对 ...

  8. OpenCV cv::Mat::checkVector用法的实例(附完整代码)

    OpenCV cv::Mat::checkVector用法的实例 OpenCV cv::Mat::checkVector用法的实例 OpenCV cv::Mat::checkVector用法的实例 # ...

  9. OpenCV基本mat重建的实例(附完整代码)

    OpenCV基本mat重建的实例 OpenCV基本mat重建的实例 OpenCV基本mat重建的实例 #include "opencv2/calib3d.hpp" #include ...

最新文章

  1. Python 第三方库自动安装脚本
  2. SQL datediff (时间差)
  3. The Struts dispatcher cannot be found异常的解决方法
  4. 从Firefox控制您喜欢的音乐播放器
  5. javaWeb服务详解(含源代码,测试通过,注释) ——Emp的Dao层
  6. 转:陈梓瀚:关于编程的胡扯
  7. 刘强东发新年信:过去一年我们异常艰难
  8. java 同步 异步 阻塞 非阻塞_Java日志正确使用姿势,大白话搞懂什么是同步/异步/阻塞/非阻塞...
  9. 倒计时 5 天!年度开发者盛会 Unite Shanghai 2019 全日程揭晓(附表)
  10. lookup函数和vlookup_VLOOKUP和LOOKUP两个函数PK,哪个才是你心目中的查找之王?
  11. Test on 2018.10.21
  12. linux下通过文件句柄恢复误删除的数据文件
  13. 有关深度估计的几篇文章的阅读笔记
  14. 2017年笔记本计算机行业,2017笔记本电脑最新排行榜
  15. 用python在大麦网抢票_大麦网自动抢票工具
  16. 怎么查看linux系统硬盘,查看Linux磁盘空间的八大方法
  17. 江苏2021高考成绩查询全省排名,江苏高考排名查询方法,2021年江苏高考成绩位次全省排名查询...
  18. 漫话:如何给女朋友解释为什么有些网站域名不以www开头
  19. java版微信调小i机器人接口说明书_java版微信调用小i机器人
  20. 做产品也要造概念,讲故事,用优雅的措辞美化自己

热门文章

  1. 如何在Odoo创建新数据的时候添加自己的方法 - 重写create方法
  2. STM32 keil仿真点击运行后不能全速运行,点一下运行一下
  3. 手机端上线,破解高架区域偏航检测难题,高德提出工业级轻量模型ERNet
  4. laravel repository模式使用
  5. linux ks脚本,linux安装详解-配置ks.cfg实现自动安装过程
  6. Spark内核之基本名词
  7. Nginx网站服务(安装nginx,nginx访问配置)
  8. android 卡片滑动详情页,在Mugeda中制作顺畅的左右滑动切换卡片效果的教程
  9. 使用node.js http-server启动了,但是网页打开显示无法正常工作
  10. 鸿蒙用java虚拟机_鸿蒙运行Android应用的时候还会有JVM虚拟机?