1、Mat类数据的读取(Mat类元素的读取):也就是说我们如何读取一个图像中的像素值信息。这部分也是困扰初学者的问题。
我们的一个彩色图像每个像素通常都是由三个通道组成的:蓝色通道、绿色通道、红色通道。也就是BGR模型(MFC中使用RGB,但是OpenCV很特立独行,它是BGR模型。)
Mat数据在内存中存放时都是以临近方式存放的,也就是说我存一个像素的蓝色通道,绿色通道和红色通道,完事儿我再存储第二个像素的蓝色、绿色、红色通道。
假如我有个 3X3X3的矩阵,那么它在Mat类中应该是一个3行9列的矩阵,所以我们在读取的时候一定要注意,它不是3*3*3的形式,而是一个3*9的形式。
1-1、Mat类的常用属性方法
Mat类常用的属性:
属性 作用 举例
cols 矩阵的列数 a.cols
rows 矩阵的行数 a.rows
step 以字节为单位的矩阵的
有效的宽度 这个值可以
与每个元素的字节数进行
运算,得到矩阵的列数。
elemSize() 每个元素的字节数
total() 矩阵中元素的个数 它等于函数乘以列数,
是整数类型。
channels 矩阵的通道数 a.channels
1-2、如何读取单通道和多通道的Mat数据
Mat元素的读取:使用 .at 方法读取Mat矩阵元素: a. at(int row,int col)
单通道读取举例:int value=(int)a.at<uchar>(0,0);//读取第1行第1列的数值
单通道的就是挨着的每个内存单位中存储的就是一个像素元素。我们只需要
告诉at方法我们需要的是第几行第几列的这个元素的值。
注意:此时我们需要知道Mat类中的数据类型,我们在取出的时候也是需要知道Mat类中的
存储的数据类型。<>尖括号就是声明了我们要取的这个Mat类的数据类型的。
前边的(int)是加了强制转换的。
我们读出的值虽然也是0-255但是,它在存储的时候其实是字符类型(uchar)存储的。所以
要强制转换。
多通道读取举例:cv::Vec3b vc3= a.at<cv::Vec3b>(0,0);//读取一个三通道像素
int first=(int)vc3.val[0]; //获取该像素中的GBR中的G(蓝色)的数值
多通道在内存中存储时,(比如三通道)紧邻的3个内存块表示的是一个像素元素。
□□□□□□
□□□□□□
□□□□□□
你看这个3通道的mat值,其(0,0)就表示的是整个红色区的这个像素。而(0,1)则表
示整个绿色区域的这个像素值。
在OpenCV中定义了一种数据类型: Vec3b 表示一个三通道的矩阵。其中这三个通道中的每一个数据都是以b为代表的数据类型。
b代表的就是uchar类型(来,跟我读:安杈儿)。
如果我要是double类型那么就是:Vec3d。
同理:对于多种通道类型的像素在OpenCV中都定义了对应的数据类型:
比如Vec2b就是2通道的uchar。
比如Vec4i就是4通道的int类型的
读取多通道时,我们先将每个像素都存入了vec向量,然后我们如果想获取第一个元素的第一个通道值,再继续如下操作:int first=(int)vc3.val[0];
注意:我们想读取Mat类中的矩阵元素时我们肯定要知道这个矩阵是几通道的,而且矩阵中存是什么数据类型。如果不匹配的话是没有办法读取的。
1-3、介绍一种不需要知道数据类型的元素读取的方式:
不管是单通道的还是多通道的我都统一转换成单通道的,
单通道:int(*(b.data+b.step[0]*row+b.step[1]*col+channel));
这种方式比较直观不用考虑数据类型。
比如我想读取: 第一行 第二列 第三个通道 也就是X Y Z的思维方式去获取。
此时我使用指针的方式直接访问内存
1-4、使用代码展示如何读取Mat中的元素
#include<iostream>
#include<opencv2/opencv.hpp>//使用这个大的头文件可以将所有的opencv的头文件全都包含进去
using namespace std;
using namespace cv;
int main()
{
system("color F0");//将C++黑色的界面调节成白色,方便看官看明白
Mat a= (cv::Mat_<int>(3, 3) << 1,2,3,4,5,6,7,8,9);//利用枚举法创建一个单通道的Mat
cout << a.at<int>(0, 0) << endl;//读取单通道中的元素,需要知道通道数和数据类型,
这是毫无疑问的。
Mat c0(5,5,CV_8UC1,Scalar(4,5,6));//创建一个1通道的Mat值,赋值时却是赋值3个通道
Mat c1(5,5,CV_8UC2,Scalar(4,5,6));//创建一个2通道的Mat值,赋值时却是赋值3个通道
Mat c2(5,5, CV_8UC3, Scalar(4,5,6));//创建一个3通道的Mat值,赋值时却是赋值3个通道
cv::Vec2b vec2b = c1.at<cv::Vec2b>(0, 0);//获取两通道中的某个元素
cout << vec2b << endl;//打印出这个数组
cout << (int)vec2b.val[0] << endl; //如果不加(int)强制转换的话,打印出来是方块儿,
因为我们的Mat矩阵中8u其实是Uchar类型
//使用通用方法读取,这里我们读到的是X为0 Y为1 Z为3的这样一个数据。
cout<< (int)(* (c2.data + c2.step[0] *2 /*row*/ + c2.step[1] *2/* col*/ +3/*
channel通道数*/));
return 0;
}
/结尾处 感谢上次几位大爷打赏给我吃的老冰棍儿,一并谢过///