opencv Mat类
本博客转载于这里!
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 |
---|---|---|---|---|---|
uchar 8U
|
uchar
|
cv::Vec2b
|
cv::Vec3b
|
cv::Vec4b
|
|
char 8S
|
|||||
ushort 16U
|
|||||
short 16S
|
short
|
cv::Vec2s
|
cv::Vec3s
|
cv::Vec4s
|
|
int 32S
|
int
|
cv::Vec2i
|
cv::Vec3i
|
cv::Vec4i
|
|
float 32F
|
float
|
cv::Vec2f
|
cv::Vec3f
|
cv::Vec4f
|
cv::Vec6f
|
double 64F
|
double
|
cv::Vec2d
|
cv::Vec3d
|
cv::Vec4d
|
cv::Vec6d
|
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 中点除
src.convertTo(dst, CV_32F, a, b); //CV_32F为 B 中 Mat 类型
3、Mat 初始化
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类相关推荐
- OpenCV Mat类详解和用法(官网原文)
参考文章:OpenCV Mat类详解和用法 我马克一下,日后更 官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_i ...
- OpenCV Mat类详解和用法
OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...
- OpenCV | Mat类的copyT、clone、=赋值的区别
OpenCV | Mat类的copyT.clone.=赋值的区别 1.clone 2.copyTo 3.等号'='赋值 4.验证 先说一下Mat类的结构. Mat类我们可以分成两部分:头部分.矩阵数据 ...
- OpenCV——Mat类的创建、复制、函数
Mat类的创建: 方法一: 通过读入一张图像,直接转换为Mat对象 Mat image = imread("test.jpg"); 其中 imread()方法需要传入String类 ...
- java OpenCv Mat 类的基本操作(3)
对初学者来说,我们总是希望通过Opencv实现一些功能,当我们去研究一个陌生的东西,我们总是想着利用他去实现某一个功能 比如Opencv,我们很容易利用他去进行人脸识别,人脸识别也有很多的方式比如利用 ...
- OpenCV Mat类详解
光心:每个透镜主轴上都有一个特殊点,凡是通过该点的光,其传播方向不变,这个点叫光心. 光线经过透镜后不会发生折射,仍然沿原方向射出. 基础矩阵(Fundamental matrix)是一个3×3的矩阵 ...
- 微软符号服务器opencv的符号,Opencv Mat类详解和用法1
Mat OpenCV 自 2001 年出现以来.在那些日子里库是围绕C接口构建的.在那些日子里,他们使用名为IplImage C 的结构在内存中存储图像.这是您将在大多数较旧的教程和教材中看到的那个. ...
- OpenCv Mat -类 成员函数
先从最简单的学起来 1.mat.cols() mat 矩阵的列数,和矩阵的通道数无关 new Mat(10,20,CvType.CV_8UC2) mat.cols==20 2.mat.row ...
- OpenCV mat类实现水平投影和垂直投影
图像经过灰度化和otsu阈值分割,分别绘制水平和垂直投影 #include<iostream> #include <cv.h> #include <highgui.h&g ...
最新文章
- PMVS:多视图匹配经典算法
- 你的vs.net 2005过期了吗?
- C语言 大小写字符转换
- 计算机系统的数制及转换
- Android 驱动(3)---Android驱动开发知识储备
- 嵌入式linux加载引导内核和根文件系统的方法
- vue.js页面刷新出现闪烁问题的解决
- 老兵不死:Radionomy正式宣布收购Winamp
- linux能虚拟化windows,在Linux和Windows下查看CPU是否支持虚拟化的方法
- 基于卡尔曼滤波器的回声消除算法
- cmd net命令详解与图片示意
- 《SRE Google运维解密》散文
- new Date() 获取当前时间对象(getFullYear、getMonth、getDate、getHours、getMinutes、getSeconds、getDay、getTime)
- php汉字转拼音百家姓版,百家姓全文查询,百家姓全文带拼音
- js验证身份证合法性(最后一位的校验)
- Ubuntu 10.04环境下载编译Android-2.2.1 (froyo) 源代码 1/2
- 思维方式-《思维的发现》书中的精髓:两个天才心理学家经历的奇妙经济学之旅。
- 轻流整体调研-v 1.0
- 微信小程序判断手机系统
- 十二个SOLIDWORKS使用小技巧,解决日常绘图令你抓狂的瞬间!