Opencv Mat数据类型&操作

一、概述

Mat用来表示图像或稠密数组。

特别注意:数组中的数据不是直接绑定在mat的对象上的。Mat对象实质上是一个数据存储区的头,而非数组本身。如果忽略这点,经常会带来bug。

例如,mat1 = mat2,随后修改mat1或mat2中的一个,另一个随之改变,这是因为mat1和mat2两个对象的矩阵头不同,但共享内存空间。上述拷贝属于浅拷贝。深拷贝需要mat1=mat2.clone()。

再比如:将mat对象放入vector中,

VideoCapture cap("test.avi");
Mat currentframe;
while(true){
    cap>>currentframe;
    std::vector<cv::Mat> frames;
    frames.push_back(currentframe);
    if(currentframe.empty())
        break;
}
for(auto r& frames){
imshow(r);
}

最后,发现回放出来的视频都是最后一帧。如果想把数组连同mat一起放进vector,实际需要使用深拷贝:

imgs.push_back(img.clone());

二、矩阵元素类型

     CV_{8U,8S,16U,16S,32F,32S,64F}C{1,2,3,4}。

各类型信息:

类型 占位 取值范围 与C++等效的变量
CV_8U 8bits 0~255 unsigned char
CV_8S 8bits -128~127 char
CV_16U 16bits 0~65535 ushort,unsigned short int,unsigned short
CV_16S 16bits -32768~32767 short,short int
CV32S 32bits -2147483648~2147483647 int,long
CV32F 32bits 1.18e-38~3.40e38 float
CV_64F 64bits 2.23e-308~1.79e308 double
CV_USRTYPE1      

使用type()方法可以查看mat的类型,

Mat img;
...
img.type()

返回值对应的类型如下: 

各类型对应type()值 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
CV_USRTYPE1 7      

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

2. Mat初始化

2.1 自定义

Mat R = (Mat_<double>(3, 3) << 0, 1, 3, 0, 4, 9, 9, 8, 2);

2.2 构造函数

Mat R(2,5,CV_32FC3,Scalar(1.0f,0.0f,1.0f)); //2行,5列,3通道(其中:1通道值设为1.0f,2通道设为0.0f,3通道设为1.0f) PS:数字后指定数字类型,i是一个32位整形,f是一个32位浮点数,d是一个64位浮点数,无符号字符b和短整型s

2.3 使用特殊矩阵

Mat m = Mat::zeros(rows,cols, CV_32FC1);
Mat m = Mat::ones(rows,cols, CV_32FC1);
Mat m = Mat::eye(rows,cols, CV_32FC1);

2.4 截取另一个矩阵的一部分

Mat K=img(cv::Rect(0,0,3,3)); //从第一个元素,到(3,3)元素包含的矩形区域。PS: 不含(3,3)

2.5 使用指针

Mat (int rows, int cols, int type, void *data, size_t step=AUTO_STEP) 
Mat (Size size, int type, void *data, size_t step=AUTO_STEP)

例如使用3x3的二维数组初始化Mat

int tmp[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
Mat R(3,3,CV_32S,tmp); 

参考: https://blog.csdn.net/hehehetanchaow/article/details/85062717

3.Mat赋值

3.1 直接赋值

Mat test;
test=cv::Mat(1,4,CV_64FC1);

3.2 将vector转化为mat:

vector<double> tmp;
vec_src.push_back(3.53414314);
vec_src.push_back(34234.234234);
vec_src.push_back(-304.8069608);
vec_src.push_back(777435.2334);

Mat mat_dst(1,vec_src.size(),CV_64FC1);
memcpy(mat_dst.data, vec_src.data(), vec_src.size()*sizeof(double)); 

其中,

void* memcpy(void * destination, const void* source, size_t num); //copy the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination
mat.data; //mat的公有数据成员data是指向数据的指针 (pointer to the data)
vector.data();//vector的成员函数data()返回的是指向数据的指针(return a pointer to the first element in the array used internally by the vector. Because elements in the vector are guaranteed to be stored in contiguous storage locations in the same order as represented by the vector, the pointer retrieved can be offset to access any element in the array.)

另外,该方法同样适用于将一维的vector写入到两维的Mat矩阵中。其内在机理正如之前提到的,Mat对象实质上是一个数据存储区的头,而非数组本身,Mat的数组在内存中也可以是连续存储为1行的。因此,利用同样的方法,上面的4个元素的一维vector也可以存储到2x2的2维mat中,只需要在初始化mat时将它定义为2x2的2维mat即可。

Mat mat_dst(2,2,CV_64FC1);
memcpy(mat_dst.data, vec_src.data(), vec_src.size()*sizeof(double)); 

3.3 mat中单个元素赋值

使用模板成员函数at<>().

Mat img=cv::Mat:zeros(3,3,CV_64FC1);
img.at<double>(0,1)=34234.6;

其中, img.at<元素类型>(index)返回的是元素的引用,img.pt<元素类型>(index)返回的是元素的指针。

PS: mat第一个元素的index为(0,0)。

4. Mat成员

Mat img;

方法: img. size()   返回[width, height]

数据成员:img.rows ;  img. cols; img.dims;

reshape()

参考:https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html

猜你喜欢

转载自blog.csdn.net/Cxiazaiyu/article/details/99715715