Opencv的Mat内容小记
转载自知乎博主:逍遥王可爱 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内容小记相关推荐
- OpenCV实现Mat与vector,Mat与数组互转
OpenCV实现Mat与vector互转 [尊重原创,转载请注明出处]https://blog.csdn.net/guyuealian/article/details/80253066 1.Mat与v ...
- C++下的OpenCV中Mat类型存储的图像格式
在调用CV进行图像处理时,经常涉及图像格式转换,经常出现原始图像输入后CV_32F与ushort之间的数据差异导致程序报错,可使用std::cout << "dilated_ty ...
- 一句代码将OpenCV的Mat对象的数据打印输出
查看阵列的数据值在MATLAB和Python-Pycharm中是非常简单的. MATLAB直接在工作区查看即可,如下图所示: Python-Pycharm在调试时就可以看到阵列的内容,如下图所示: 但 ...
- android都图片mat_计算机视觉 OpenCV Android | Mat像素操作(图像像素的读写、均值方差、算术、逻辑等运算、权重叠加、归一化等操作)...
本文目录 1. 像素读写 2. 图像通道与均值方差计算 3. 算术操作与调整图像的亮度和对比度 4. 基于权重的图像叠加 5. Mat的其他各种像素操作 1. 像素读写 Mat作为图像容器,其数据部分 ...
- OpenCV之Mat与Bitmap之间的转换
我们想在Android平台上开发OPenCV(处理图像):避免不了显示,通常在Android当中展示图像都是通过ImageView这个控件,当然展示的方式也有几种,在下面的内容中会简单介绍一下.但是我 ...
- 在ROS下利用OpenCV的Mat类,将激光点云展开为深度图像(从零开始,超详细)
激光雷达3D目标检测任务需要将地面滤除,滤除地面的方法多种多样:基于深度学习.基于栅格.基于平面拟合.基于条件随机场.基于深度图像等等.关于将点云转化为深度图像,PCL库中有相关函数,但使用起来有一定 ...
- mat opencv java_OpenCV Mat到JavaCV Mat转换
您可以使用java.awt.image.BufferedImage作为接口. 您org.opencv.core.Mat对象只是转换为java.awt.image.BufferedImage中再取结果对 ...
- OpenCV cv::Mat::checkVector用法的实例(附完整代码)
OpenCV cv::Mat::checkVector用法的实例 OpenCV cv::Mat::checkVector用法的实例 OpenCV cv::Mat::checkVector用法的实例 # ...
- OpenCV基本mat重建的实例(附完整代码)
OpenCV基本mat重建的实例 OpenCV基本mat重建的实例 OpenCV基本mat重建的实例 #include "opencv2/calib3d.hpp" #include ...
最新文章
- Python 第三方库自动安装脚本
- SQL datediff (时间差)
- The Struts dispatcher cannot be found异常的解决方法
- 从Firefox控制您喜欢的音乐播放器
- javaWeb服务详解(含源代码,测试通过,注释) ——Emp的Dao层
- 转:陈梓瀚:关于编程的胡扯
- 刘强东发新年信:过去一年我们异常艰难
- java 同步 异步 阻塞 非阻塞_Java日志正确使用姿势,大白话搞懂什么是同步/异步/阻塞/非阻塞...
- 倒计时 5 天!年度开发者盛会 Unite Shanghai 2019 全日程揭晓(附表)
- lookup函数和vlookup_VLOOKUP和LOOKUP两个函数PK,哪个才是你心目中的查找之王?
- Test on 2018.10.21
- linux下通过文件句柄恢复误删除的数据文件
- 有关深度估计的几篇文章的阅读笔记
- 2017年笔记本计算机行业,2017笔记本电脑最新排行榜
- 用python在大麦网抢票_大麦网自动抢票工具
- 怎么查看linux系统硬盘,查看Linux磁盘空间的八大方法
- 江苏2021高考成绩查询全省排名,江苏高考排名查询方法,2021年江苏高考成绩位次全省排名查询...
- 漫话:如何给女朋友解释为什么有些网站域名不以www开头
- java版微信调小i机器人接口说明书_java版微信调用小i机器人
- 做产品也要造概念,讲故事,用优雅的措辞美化自己
热门文章
- 如何在Odoo创建新数据的时候添加自己的方法 - 重写create方法
- STM32 keil仿真点击运行后不能全速运行,点一下运行一下
- 手机端上线,破解高架区域偏航检测难题,高德提出工业级轻量模型ERNet
- laravel repository模式使用
- linux ks脚本,linux安装详解-配置ks.cfg实现自动安装过程
- Spark内核之基本名词
- Nginx网站服务(安装nginx,nginx访问配置)
- android 卡片滑动详情页,在Mugeda中制作顺畅的左右滑动切换卡片效果的教程
- 使用node.js http-server启动了,但是网页打开显示无法正常工作
- 鸿蒙用java虚拟机_鸿蒙运行Android应用的时候还会有JVM虚拟机?