白手起家opencv,如果有理解错误的,希望得到大家的指正!
1.Mat数据类型
Mat是一个类,由两个数据部分组成,包括矩阵头(尺寸信息等),和指向存储图像像素的矩阵的指针
(1)成员变量
官方文档中Mat的所有变量包括:
ndims – 数组维度.
rows – 在2D数组里的行数.
cols – 在2D数组里的列数.
size – 2D 数组size: Size(cols, rows) . 在Size() 中行数和列数顺序相反
sizes – 一组整数,用来说明一个n维数组的shape
type – 数组类型. 使用 CV_8UC1, …, CV_64FC4 来创建 1-4 通道的矩阵, 或者 CV_8UC(n), …, CV_64FC(n) 创造多通道的矩阵 (最大到 CV_MAX_CN通道) . s –
设置矩阵初始化值,使用指定的操作 Mat::operator=(const Scalar& value) .
data –指向像素数据的指针. data和step不会特别地分配内存,也就是不会copy一份图像数据,而是指向一块数据. 并且外部数据不会自动释放
step – 每个矩阵行占用的字节数(包含每一行末尾地填充字节),如果该参数没有赋值,实际可计算维cols*elemSize() . See Mat::elemSize() .
steps – 对于多维数组的具有ndims-1个元素的steps数组, (steps[ndims-1]=元素的大小). 如果未被指定,则矩阵被认为是连续的
m – Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead,
the header pointing to m data or its sub-array is constructed and
associated with it. The reference counter, if any, is incremented. So,
when you modify the matrix formed using such a constructor, you also
modify the corresponding elements of m . If you want to have an
independent copy of the sub-array, use Mat::clone() .
img – Pointer to the old-style IplImage image structure. By default, the data is shared between the original image and the new
matrix. But when copyData is set, the full copy of the image data is
created.
vec – STL vector whose elements form the matrix. The matrix has a single column and the number of rows equal to the number of vector
elements. Type of the matrix matches the type of vector elements. The
constructor can handle arbitrary types, for which there is a properly
declared DataType . This means that the vector elements must be
primitive numbers or uni-type numerical tuples of numbers. Mixed-type
structures are not supported. The corresponding constructor is
explicit. Since STL vectors are not automatically converted to Mat
instances, you should write Mat(vec) explicitly. Unless you copy the
data into the matrix ( copyData=true ), no new elements will be added
to the vector because it can potentially yield vector data
reallocation, and, thus, the matrix data pointer will be invalid.
copyData – Flag to specify whether the underlying data of the STL vector or the old-style CvMat or IplImage should be copied to (true)
or shared with (false) the newly constructed matrix. When the data is
copied, the allocated buffer is managed using Mat reference counting
mechanism. While the data is shared, the reference counter is NULL,
and you should not deallocate the data until the matrix is not
destructed.
rowRange – Range of the m rows to take. As usual, the range start is inclusive and the range end is exclusive. Use Range::all() to take
all the rows.
colRange – Range of the m columns to take. Use Range::all() to take all the columns.
ranges – Array of selected ranges of m along each dimensionality.
expr – Matrix expression. See Matrix Expressions.
其中,存储的数据格式是uchar(unsigned char,8-bit无符号整形数据,范围为[0, 255]),一维数组存储。
(附:uchar、schar、char的区别)
现分别以原图、(gray_)灰度图、(BGR_)BGR的格式读入一张图片,打印各个数据,看一下各个数据到底表示什么
可以看出数据的维数dims都是2,行列数分别为1385和1080,可以理解为一个1080*1385的二维矩阵
通道数channel不同,原图和BGR中,都用3个数据表示一个像素点,所以通道数是3,而灰度图则是1,原图形式和BGR形式读出的矩阵中,一个矩阵元素是(X1,X2,X3),而灰度图则是(X)。
size相同,表示为cols * rows
type类型表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值:
所以原图和BGR的类型为CV_8U,C3,灰度图为CV_8U,C1。
step也是一个记录尺寸的数据,dim为2,则step具有两个数据。对于step[0],读入的图像的列值为1080,则一行有1080个像素点,对于灰度图像,一行的字节数为1080,对于原图和BGR格式,一行有1080*3个字节(一个像素点用3个数据表示),即3240个字节。对于step[1],灰度图一个像素点用1字节表示,则为1,另外两个用3个字节表示,即为3。
可以使用step进行像素寻址。
在官方文档中,像素寻址描述如下:
The data layout of the array M is defined by the array M.step[] , so that the address of element (i_0,…,i_{M.dims-1}) , where 0\leq
i_k<M.size[k] , is computed as:
M.step[i] >= M.step[i+1] (in fact, M.step[i] >= M.step[i+1]*M.size[i+1] );
也就是说n维矩阵,像素坐标为(i0,i1…,in),像素地址=首地址+偏移地址
(2)成员函数
int mat_function()
{
Mat src,dst;
src = imread("D:\\opencv_test_img\\sz.jpg",1);
//Mat构造函数
//Mat cdst(src); //拷贝src的指针和数据头,如果对dst进行操作,相当于对src进行操作
//cdst=Scalar(255,0,0);
//一类构造函数,rows,cols,type,(Scalar)
//其中rows,cols可以被size代替,(Scalar)可选,用于初始化填充,里面的数据维度要和type匹配
dst = Mat(src.size(),src.type()); //Mat构造函数
dst = Scalar(0,111,0); //填充值(B,G,R)
dst = Mat(src.rows,src.cols,CV_8UC3, Scalar(255,0,0)); //Scaler()初始化值
//另一类构造函数使用dims,构造多维图像
int size[3] = { 1,2,3 };
dst = Mat(3, size, CV_8UC3); //第一个参数要和size的大小相同,可以有scalar
//使用create函数
dst.create(src.size(),src.type());
dst = Scalar(0, 111, 0);
//创建小数组
dst = (Mat_<char>(3, 3, 3) << 1, 0, 1, 0, 1, 0, 1, 1, 1);
cout << dst<<endl;
//创建0矩阵
dst = Mat::zeros(src.size(),src.type());
//创建单位矩阵
dst = Mat::eye(5,5, CV_8UC1);
cout << dst;
//克隆
dst = src.clone();
src.copyTo(dst); //两个均可以复制数据
//其它函数
//精度转换函数
Mat cdst,tdst;
src.convertTo(cdst, CV_16UC3); //只能转换精度,不能改变通道数
cout << endl <<"cdst type:"<< cdst.type() << endl;
cdst.convertTo(tdst, CV_8UC3);
cout << "tdst type:" << tdst.type() << endl;
//判断空函数
Mat zero;
if (zero.empty()) //如果为空则返回1
cout << "zero is empty"<<endl;
else
cout << "zero is not empty" << endl;
//获取行指针的函数
const uchar* p = src.ptr<uchar>(0);
printf("src 像素数据首地址:%x\n",p);
printf("src 第一个像素值:%d\n", *p);
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
namedWindow("dst", WINDOW_AUTOSIZE);
imshow("dst", dst);
waitKey(0);
system("pause");
return 0;
}
(3)使用要点
1.关于对象的拷贝,使用直接用对象A,初始化对象B会导致浅拷贝,即只赋值对象A的指针和头,而没有数据部分,使用A.copyTo(B)和B=A.clone(),可以实现数据部分的拷贝
2.输出图像的内存是自动分配的
参考链接:
C++下的OpenCV中Mat类型存储的图像格式
Opencv学习(三)简记Mat中的数据类型
Mat官方文档
OpenCV基础课程