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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章