Opencv Mat矩陣操作
1.生成矩陣:
Mat image(240, 320, CV8UC3);
第一個參數是rows,該矩陣的行數;第二個參數是cols,該矩陣的列數;第三個參數是該矩陣元素的類型。這句話表示創建一個大小爲240×320的矩陣,裏面的元素爲8位unsigned型,通道數(channel)有3個。
image.create(480, 640, CV8UC3);
分配(或重新分配)image矩陣,把大小設爲480×640,類型設爲CV8UC3。
Mat A33(3, 3,CV_32F, Scalar(5));
定義並初始化一個3×3的32bit浮點數矩陣,每個元素都設爲5。
Mat B33(3, 3,CV_32F);
B33 = Scalar(5);
和上面的作用一樣。
Mat C33 =Mat::ones(3, 3, CV32F)*5.0;
ones函數很像MATLAB裏的語句。這句的意思是先定義一個3×3的32bit浮點數矩陣,元素全爲1,所有元素再乘以5.0。
Mat D33 =Mat::zeros(3, 3, CV32F) + 5.0;
和上面類似,先定義個3×3的32bit浮點數矩陣,元素全爲0,再將所有元素加上5.0;
Mat D33 = Mat::eye(4,4,CV_64F);//對角矩陣
double a = CV_PI/3;
Mat A22 = (Mat_(2, 2) << cos(a), -sin(a), sin(a), cos(a));
CV_PI就是圓周率。是創建一個2×2的float矩陣,把後面四個三角函數值分別賦給4個元素。
float B22data[] ={cos(a), -sin(a), sin(a), cos(a)};
Mat B22 = Mat(2, 2, CV32F, B22data).clone();
第一句創建一個普通數組B22data,第二句創建一個2×2的32bit浮點數矩陣,並使用用B22data數組裏的值初始化,然後克隆一下賦給B22矩陣。
爲什麼這裏還要克隆一下,不是多此一舉嗎?不是,因爲用一個數組去初始化一個矩陣的話,你會發現這個矩陣引用了數組的內存地址。不克隆的話,上面例程的後果是B22data數組、Mat(2,2…)這個臨時變量矩陣、B22矩陣這三把勺子都插在同一個碗裏。
randu(image,Scalar(0), Scalar(256));
把image弄成一個符合正太分佈的隨機數矩陣,rand表示random,u表示uniform;第二個參數是隨機數下限,包含該數;第三個參數是隨機數上限,不包含該數。
randn(image,Scalar(128), Scalar(10));
高斯分佈的隨機數矩陣;第二個參數是均值,第三個參數是標差。
矩陣輸出:
cout<< "M = " << endl << " " << M<< endl << endl;
2. 賦值運算
Mat A,C; //僅創建了頭部
Mat B(A); //複製構造函數
C=A; //複製運算
**注:**賦值運算符和複製構造函數 (構造函數)只複製頭,沒有數據。
src.copyTo(dst); //把src矩陣中的數據拷貝到dst
src.convertTo(dst, type, scale, shift);
縮放並轉換到另外一種數據類型:dst:目的矩陣 type:需要的輸出矩陣類型,或者更明確的,是輸出矩陣的深度,如果是負值(常用-1)則輸出矩陣和輸入矩陣類型相同 scale和shift:縮放參數,也可以寫爲alpha和beta這個命令也等價於下面的轉換公式:
m.row(i), m.col(i);
創建一個矩陣頭,指向m矩陣的第i行/列,新的矩陣頭所代表的矩陣和m矩陣的第i行/列共享數據。
m.rowRange(Range(i1,i2));
m.colRange(Range(j1,j2));
創建一個矩陣頭,指向m矩陣的第i1到i2行或者第j1到j2列
m.diag(i);
創建一個矩陣頭,指向m矩陣的對角線,生成的是一個單列矩陣,O(1)複雜度,不拷貝數據。i=0時表示主對角線,i>0表示下半邊的對角線,i<0表示上半邊的對角線。
m(Range(i1,i2),Range(j1,j2)); //Range(i1,i2)包含i1不包含i2 行列編號從0開始
從矩陣m中的第i1行到第i2行以及第j1列到第j2列所劃定的範圍提取一個小矩陣。
m(Range::all(),Range(j1,j2)); //Range::all()表示所有行 [j1,j2]列
m.repeat(ny,nx);
把m矩陣貼馬賽克,獲取一個大矩陣,在y方向上重複ny次,在x方向上重複nx次。
flip(src,dst,dir);
翻轉矩陣,dir是翻轉方向,0表示沿x軸翻轉,1表示沿y軸翻轉,-1表示沿x軸和y軸都進行翻轉。
3、算術運算
1.加法
I = I1 + I2; //等同add(I1,I2,I);
add(I1,I2,dst,mask,dtype);
scaleAdd(I1,scale,I2,dst); //dst=scale*I1+I2;
2.減法
absdiff(I1,I2,I); //I=|I1-I2|;
A-B;A-s;s-A;-A;
subtract(I1,I2,dst);
3.乘法
I = I.mul(I); //點乘,I.mul(I,3);-->I=3*I.^2
Mat C=A.mul(5/B); //==divide(A,B,C,5);
A * B; //矩陣相乘
A.dot(B); //A和B點乘,然後求所有元素和,
pow(src,double p,dst); //如果p是整數dst(I)=src(I)^p;其他|src(I)|^p
Mat::cross(Mat); //三維向量(或矩陣)的叉乘,A.cross(B)
4.除法
divide(I1,I2,dst,scale,int dtype=-1); //dst=saturate_cast(I1*scale/I2);
A/B; alpha/A; //都是點除
4、其他操作
1.矩陣元素訪問
A.rows //矩陣行數
A.cols //矩陣列數
A.row(i) //取第i行 行編號從0開始
A.col(j) //取第i列 列編號從0開始
A.at<type>(i,j) //訪問矩陣第(i,j) 注意矩陣A的類型,否則異常或取值出錯 如:A爲CV_32CF1時,type爲int型時,所取值爲異常值,不是矩陣值。
2.矩陣變形:
A.reshape(int cn, int rows);
參數cn:新的通道數;如果cn值爲0表示變換前後通道數不變
參數rows:新的行數;如果rows值爲0表示變換後矩陣的行數不變
該函數會爲當前矩陣創建一個新的矩陣頭(指針),新的矩陣擁有不同的尺寸或者不同的通道數,其優點在於運算複雜度爲O(1),不用複製矩陣數據.正是因爲不用複製數據,所以在轉變過程中要保證原數據矩陣在數據上的連續性(這裏的連續性是相對於原矩陣來說)。
注:A要爲單獨矩陣,不能直接爲矩陣的一部分。
3.轉置運算:
A.t()
4.矩陣求逆:
A.inv(type)
Type: CV_LU - 最佳主元選取的高斯消除法
CV_SVD - 奇異值分解法 (SVD)
CV_SVD_SYM - 對正定對稱矩陣的 SVD 方法
5.SVD分解:
SVD::compute(A,D,U,V,flag=0);
Flag可以爲空即:SVD::compute(A,D,U,V),D爲列矩陣,元素爲A的特徵值,A=U*diag(D)*V ,diag(D)是把D變成對角陣,與matlab相比,U與matlab值相同,正負號不同,V爲matlab中V的轉置,正負號不同。
6.最大最小值:
不需的值可以設成0,如: minMaxLoc(A, 0, 0, 0, &max_loc); 求A中最大值的位置,max_loc定義爲:Point max_loc max_loc.x爲橫座標,對應圖像的列,max_loc.y爲縱座標,對應圖像的行。
7.矩陣合併
hconcat(A,B,dst1) 水平方向合併
vconcat(A,B,dst2) 垂直方向合併
A=[1 ,2; B=[5,6; dst1=[ 1 2 5 6;
3 ,4 ] 7,8] 3 4 7 8 ]
dst2=[1 2;
3 4;
5 6;
7 8]
8.矩陣底部添加、刪除元素
A.push_back(B); //B添加在A的底部,B可以是常數
A.pop_back(m); //從A的底部刪除m行
注:添加時A,B的類型和行數必須相同,刪除時,m不能大於A的行數,否則異常,另外,添加和刪除後的矩陣,不能用於算術運算,否則異常。
9.矩陣行列求和
Reduce( inputArry src, outputArry, int dim, int rtype,int dtype=-1);
dim :
矩陣被簡化後的維數索引.0意味着矩陣被處理成一行,1意味着矩陣被處理成爲一列,-1時維數將根據輸出向量的大小自動選擇.
rtype :
簡化操作的方式,可以有以下幾種取值:
CV_REDUCE_SUM-輸出是矩陣的所有行/列的和.
CV_REDUCE_AVG-輸出是矩陣的所有行/列的平均向量.
CV_REDUCE_MAX-輸出是矩陣的所有行/列的最大值.
CV_REDUCE_MIN-輸出是矩陣的所有行/列的最小值.