本博客转载于这里!

Mat 基础

图片在计算机中的本质就是一个数组。其中 Mat 就是在 OpenCV 中图像的表示形式,因此简单介绍 Mat 中一些常用的基础知识。

其中 Mat 类中有一些基本属性:

cols :矩阵列数

rows:矩阵行数

channels:通道数

type:数据类型

total:矩阵总元素数

data:指向矩阵数据块的指针

其中 Mat 排列方式如下:


通道顺序为 BGR

参考:https://blog.csdn.net/x199699/article/details/82424596

1、Mat 类型

在访问图片像素点时,了解 Mat 的类型至关重要。我们可以通过 Mat.type() 函数返回类型,通过下表的数值对应可知预定义名,如

​ “22" 表示 CV_64FC3,Mat 有三个通道,每个像素点是一个 64位double 类型的数值。

命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:

  C1 C2 C3 C4
CV_8U 0 8 16 24
CV_8S 1 9 17 25
CV_16U 2 10 18 26
CV_16S 3 11 19 27
CV_32S 4 12 20 28
CV_32F 5 13 21 29
CV_64F 6 14 22 30
用户定义 7      
图像深度 枚举数值 空间大小 范围 等同C++变量
CV_8U 0 8bits 0~255 unsigned char
CV_8S 1 8bits -128~127 char
CV_16U 2 16bits 0~65535 ushort,unsigned short int,unsigned short
CV_16S 3 16bits -32768~32767 short,short int
CV32S 4 32bits -2147483648~2147483647 int,long
CV32F 5 32bits 1.18e-38~3.40e38 float
CV_64F 6 64bits 2.23e-308~1.79e308 double
CV_USRTYPE1 7 -    

参考:<https://segmentfault.com/a/1190000015653101>

2、Mat 元素访问

先行后列
图片的 高(height)==> Mat 的 行(row)==> 坐标系的 y
图片的 宽(width) ==> Mat 的 列(col)==> 坐标系的 x

2.1 at访问

img.at<type>(row, col)[channel];
// 三通道
for(int h = 0 ; h < image.rows ; ++ h)
{for(int w = 0 ; w < image.cols ; ++ w){std::cout << image.at<Vec3b>(h , w)[0] << std::endl;std::cout << image.at<Vec3b>(h , w)[1] << std::endl;std::cout << image.at<Vec3b>(h , w)[2] << std::endl;}
}
// 单通道
std::cout << image.at<uchar>(h , w) << std::endl;

2.2 ptr访问

// 三通道
for(int h = 0 ; h < image.rows ; ++ h)
{for(int w = 0 ; w < image.cols ; ++ w){// 输出 [1.1, 1.2, 1.3] 的形式,输出都一样Vec3b*ptr = image.ptr<Vec3b>(h , w) ;std::cout << ptr[0] << std::endl;std::cout << ptr[1] << std::endl;std::cout << ptr[2] << std::endl;// 输出 每个通道的值,将上边形式的数值分开输出//Vec3b *ptr = image.ptr<Vec3b>(h , w) ;//std::cout << ptr->val[0] << std::endl;//std::cout << ptr->val[1] << std::endl;//std::cout << ptr->val[2] << std::endl;}
}
// 单通道
double* ptr = image.ptr<double>(h , w) ;
std::cout << *ptr << std::endl;

2.3 迭代器(安全)

// 三通道
Mat_<Vec3b>::iterator it = image.begin<Vec3b>() ;
Mat_<Vec3b>::iterator itend = image.end<Vec3b>() ;
for(;it != itend ; ++ it)
{std::cout << (*it)[0] << std::endl;std::cout << (*it)[1] << std::endl;std::cout << (*it)[2] << std::endl;
}
// 单通道
std::cout << (*it1) << std::endl;

2.4 data 访问

uchar *data = image.data ;
// 三通道
for(int h = 0 ; h < image.rows ; ++ h)
{for(int w = 0 ; w < image.cols ; ++ w){std::cout << *data ++ << std::endl;std::cout << *data ++ << std::endl;std::cout << *data ++ << std::endl;}
}
// 单通道
for(int h = 0 ; h < image.rows ; ++ h)for(int w = 0 ; w < image.cols; ++ w)std::cout << *data ++ << std::endl ;

2.5 continuous+channels 访问(高效)

isContinuous() 判断 image 存储是否为连续,连续为 true,不连续为 false。

可以将简单元素操作的性能提高10-20%,特别是如果图像相当小并且操作非常简单。

一般读取图片都为连续,但是裁剪过后的图片返回为不连续

int nRows = image.rows ;
int nCols = image.cols * image.channels() ;if(image.isContinuous())
{nCols = nRows * nCols ;nRows = 1 ;
}for(int h = 0 ; h < nRows ; ++ h)
{uchar *ptr = image.ptr<double>(h) ;for(int w = 0 ; w < nCols ; ++ w)std::cout << *ptr++ << std::endl;
}

2.6 step 访问



改变 “0”,“1”,“2” 为 “i”,“j”,“k” 即可以访问任意位置像素值(不要越界)

for (int row = 0; row < img.rows; row++)
{for (int col = 0; col < img.cols; col++){//[row,col]像素的第1通道地址解析为Blue通道*(img.data + img.step[0] * row + img.step[1] * col) += 15;//[row,col]像素的第2通道地址解析为Green通道*(img.data + img.step[0] * row + img.step[1] * col + img.elemSize1()) += 16;//[row,col]像素的第3通道地址解析为Red通道*(img.data + img.step[0] * row + img.step[1] * col + img.elemSize1() * 2) += 17;}}

参考:https://blog.csdn.net/BoaHock/article/details/80790323

2.7 单个像素点类型

种类 C1 C2 C3 C4 C6
uchar8U uchar cv::Vec2b cv::Vec3b cv::Vec4b  
char8S          
ushort16U          
short16S short cv::Vec2s cv::Vec3s cv::Vec4s  
int32S int cv::Vec2i cv::Vec3i cv::Vec4i  
float32F float cv::Vec2f cv::Vec3f cv::Vec4f cv::Vec6f
double64F double cv::Vec2d cv::Vec3d cv::Vec4d cv::Vec6d

当需要访问 Mat 类型为 CV_64FC3 的图片像素时

cv::Vec3d vec3d      = img.at<cv::Vec3d>(0,0);
uchar     vec3d0     = img.at<cv::Vec3d>(0,0)[0];
uchar     vec3d1     = img.at<cv::Vec3d>(0,0)[1];
uchar     vec3d2     = img.at<cv::Vec3d>(0,0)[2];
std::cout<<"vec3d = "<<vec3d<<std::endl;
std::cout<<"vec3d0 = "<<(double)vec3d0<<std::endl;
std::cout<<"vec3d1 = "<<(double)vec3d1<<std::endl;
std::cout<<"vec3d2 = "<<(double)vec3d2<<std::endl;

2.5 convertTo()

当我们了解 Mat 数据类型时,我们可以方便的进行 像素运算:

1、将整型类型的 Mat 转化为 double 类型:利用 convertTo() 函数

src.convertTo(dst, CV_64FC3);

2、将 Mat 中元素进行统一运算,如 matlab 中点除

比如:dst = a* src + b

src.convertTo(dst, CV_32F, a, b);    //CV_32F为 B 中 Mat 类型

当然,也可以利用遍历进行运算

3、Mat 初始化

(1) Mat::Mat()
(2) Mat::Mat(int rows, int cols, int type)
(3) Mat::Mat(Size size, int type)
(4) Mat::Mat(int rows, int cols, int type, const Scalar& s)
(5) Mat::Mat(Size size, int type, const Scalar& s)
(6) Mat::Mat(const Mat& m)
(7) Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
(8) Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
(9) Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
(10) Mat::Mat(const Mat& m, const Rect& roi)
(11) Mat::Mat(const CvMat* m, bool copyData=false)
(12) Mat::Mat(const IplImage* img, bool copyData=false)
(13) template<typename T, int n> explicit Mat::Mat(const Vec<T, n>& vec, bool copyData=true)
(14) template<typename T, int m, int n> explicit Mat::Mat(const Matx<T, m, n>& vec, bool copyData=true)
(15) template explicit Mat::Mat(const vector& vec, bool copyData=false)
(16) Mat::Mat(const MatExpr& expr)
(17) Mat::Mat(int ndims, const int* sizes, int type)
(18) Mat::Mat(int ndims, const int* sizes, int type, const Scalar& s)
(19) Mat::Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0)

其中 clone() 也可以实现初始化

Mat img(640, 480, CV_8UC3);
Mat roi(img, Rect(10,10,100,100));

*深拷贝浅拷贝

OpenCV 中 ”=“ 是浅拷贝,只赋值图片的指针头,所以在修改 Mat 元素时,会影响另一个。

如果想实现图片复制为两个图片,应当选择 clone() 或copyto()

dst = src.clone();
src.copyto(dst);

*特殊矩阵初始化

Mat eye   = Mat::eye(4,4,CV_8U);
Mat ones  = Mat::ones(4,4,CV_8U);
Mat zeros = Mat::zeros(4,4,CV_8U);
Mat img = (Mat_<double>(3,3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);// 随机初始化像素值
Mat r = Mat(3,3,CV_8UC3);
randu(r, Scalar::all(0), Scalar::all(255));

4、显示图片

#include <opencv2/opencv.hpp>//opencv的头文件using namespace cv;int main()
{Mat img = imread("C:/daima practice/opencv/mat3/mat3/image4.jpg");imshow("显示灰度图",img);waitKey(0);return 0;
}

5、播放视频

#include <opencv2/opencv.hpp>using namespace cv;int main()
{// VideoCapture capture(0);        摄像头VideoCapture cap("test.avi");if (!cap_PD_depth.isOpened())return -1;double rate = capture.get(CV_CAP_PROP_FPS);//获取视频文件的帧率int delay = cvRound(1000.000 / rate);     // 设置帧率Mat Frame;while(1){cap >> Frame;if (frame.empty()) break;imshow("视频", frame);waitKey(delay);}return 0;
}

6、waitKey

#include <iostream>
#include <opencv2\opencv.hpp>using namespace std;
using namespace cv;
int main()
{Mat Frame;VideoCapture cap;cap.open(0);if (!cap.isOpened())return 0;while (1){cap >> Frame;if (Frame.empty())return 0;imshow("camera", Frame);if (waitKey(10) == 'b')              // 设置为按下 b 键退出程序{break;}}return 0;
}

opencv Mat类相关推荐

  1. OpenCV Mat类详解和用法(官网原文)

    参考文章:OpenCV Mat类详解和用法 我马克一下,日后更 官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_i ...

  2. OpenCV Mat类详解和用法

    OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...

  3. OpenCV | Mat类的copyT、clone、=赋值的区别

    OpenCV | Mat类的copyT.clone.=赋值的区别 1.clone 2.copyTo 3.等号'='赋值 4.验证 先说一下Mat类的结构. Mat类我们可以分成两部分:头部分.矩阵数据 ...

  4. OpenCV——Mat类的创建、复制、函数

    Mat类的创建: 方法一: 通过读入一张图像,直接转换为Mat对象 Mat image = imread("test.jpg"); 其中 imread()方法需要传入String类 ...

  5. java OpenCv Mat 类的基本操作(3)

    对初学者来说,我们总是希望通过Opencv实现一些功能,当我们去研究一个陌生的东西,我们总是想着利用他去实现某一个功能 比如Opencv,我们很容易利用他去进行人脸识别,人脸识别也有很多的方式比如利用 ...

  6. OpenCV Mat类详解

    光心:每个透镜主轴上都有一个特殊点,凡是通过该点的光,其传播方向不变,这个点叫光心. 光线经过透镜后不会发生折射,仍然沿原方向射出. 基础矩阵(Fundamental matrix)是一个3×3的矩阵 ...

  7. 微软符号服务器opencv的符号,Opencv Mat类详解和用法1

    Mat OpenCV 自 2001 年出现以来.在那些日子里库是围绕C接口构建的.在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像.这是您将在大多数较旧的教程和教材中看到的那个. ...

  8. OpenCv Mat -类 成员函数

    先从最简单的学起来 1.mat.cols() mat 矩阵的列数,和矩阵的通道数无关 new Mat(10,20,CvType.CV_8UC2)      mat.cols==20 2.mat.row ...

  9. OpenCV mat类实现水平投影和垂直投影

    图像经过灰度化和otsu阈值分割,分别绘制水平和垂直投影 #include<iostream> #include <cv.h> #include <highgui.h&g ...

最新文章

  1. PMVS:多视图匹配经典算法
  2. 你的vs.net 2005过期了吗?
  3. C语言 大小写字符转换
  4. 计算机系统的数制及转换
  5. Android 驱动(3)---Android驱动开发知识储备
  6. 嵌入式linux加载引导内核和根文件系统的方法
  7. vue.js页面刷新出现闪烁问题的解决
  8. 老兵不死:Radionomy正式宣布收购Winamp
  9. linux能虚拟化windows,在Linux和Windows下查看CPU是否支持虚拟化的方法
  10. 基于卡尔曼滤波器的回声消除算法
  11. cmd net命令详解与图片示意
  12. 《SRE Google运维解密》散文
  13. new Date() 获取当前时间对象(getFullYear、getMonth、getDate、getHours、getMinutes、getSeconds、getDay、getTime)
  14. php汉字转拼音百家姓版,百家姓全文查询,百家姓全文带拼音
  15. js验证身份证合法性(最后一位的校验)
  16. Ubuntu 10.04环境下载编译Android-2.2.1 (froyo) 源代码 1/2
  17. 思维方式-《思维的发现》书中的精髓:两个天才心理学家经历的奇妙经济学之旅。
  18. 轻流整体调研-v 1.0
  19. 微信小程序判断手机系统
  20. 十二个SOLIDWORKS使用小技巧,解决日常绘图令你抓狂的瞬间!

热门文章

  1. 无线信号功率计算公式(自由空间模型,地面反射模型)
  2. AIX 操作系统中AIO、DIO、CIO 的相关概念介绍 (二)
  3. 如何将自己写的verilog模块封装成IP核(一)
  4. 如何有效抵抗电脑辐射
  5. 从源码分析DEARGUI之add_tooltip
  6. 中文语音识别pytorch
  7. 放大倍数超5万倍的Memcached DDoS反射攻击,怎么破?
  8. SSM+maven实现答题管理系统(二)
  9. 面试题: 数据库 已看1 视图 游标
  10. Could not find Developer Disk Image