線性映射(Linear transformation),是由向量為基礎的映射函式,在OpenCV內標準的向量表達方式為通道的向量,也就是今天為一組<r,g,b>三通道所組成的圖形,則圖形內的<r,g,b>個別值則代表一個向量,cvTransform()則是為此而做的轉換,下面則是簡單的一個通道向量的運算
簡單線性映射實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols,int Channels);
float Array1[]={4,1,0,2,1,1,3,2,1,1,4,1.5};
float Array2[]={2,1,2};
int main()
{
CvMat *A=cvCreateMat(4,3,CV_32FC1);
CvMat *x=cvCreateMat(1,1,CV_32FC3);
CvMat *T_x=cvCreateMat(1,1,CV_32FC4);
cvSetData(A,Array1,A->step);
cvSetData(x,Array2,x->step);
cvTransform(x,T_x,A);
PrintMatrix(T_x,T_x->rows,T_x->cols,4);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols,int Channels)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
for(int k=0;k<Channels;k++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[k]);
}
}
printf("\n");
}
}
執行結果:
A矩陣則是叫轉移矩陣(Transition Matrix),可以專門在做基底座標變換的運用,這邊要特別注意的是,cvTransform()它拿通道來代替向量,而不是拿矩陣來代替向量,事實上,矩陣也可以作為向量的表達,但不適用於cvTransform().這邊cvTransform()輸入,x矩陣為通道三,而A則一定要輸入通道一的矩陣,輸出的T_x矩陣為通道四,而對於一個向量而言,此種運算方式叫做線性映射,如果對於一個矩陣圖形的話,則叫做矩陣變換(Matrix Transformation).
矩陣變換的部分,就拿RGB轉YCbCr的公式來實作,跟前面的線性映射不同的是,它直接拿通道三的矩陣來做色彩空間的轉換.
RGB轉YCbCr實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
float Array1[]={0.2989,0.5867,0.1140,-0.1687,-0.3312,0.5,0.5,-0.4183,-0.0816};
float Array2[]={0,128,128};
int main()
{
CvMat *TransitionMatrix=cvCreateMat(3,3,CV_32FC1);
CvMat *ShiftVector=cvCreateMat(3,1,CV_32FC1);
IplImage *Image1=cvLoadImage("MineCar.jpg",1);
IplImage *GrayImage1=cvLoadImage("MineCar.jpg",0);
IplImage *YCbCrImage1=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,3);
IplImage *YImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
IplImage *CbImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
IplImage *CrImage=cvCreateImage(cvGetSize(Image1),IPL_DEPTH_8U,1);
cvSetData(TransitionMatrix,Array1,TransitionMatrix->step);
cvSetData(ShiftVector,Array2,ShiftVector->step);
cvTransform(Image1,YCbCrImage1,TransitionMatrix,ShiftVector);
cvSplit(YCbCrImage1,YImage,CbImage,CrImage,0);
cvNamedWindow("YImage",1);
cvShowImage("YImage",YImage);
cvNamedWindow("GrayImage",1);
cvShowImage("GrayImage",GrayImage1);
cvWaitKey(0);
}
原始圖片:
執行結果:
由上面線性映射的基礎來對一個通道三個圖形做矩陣變換,這邊將RGB的圖片藉由公式轉成YCbCr的格式,這個部分就叫做色彩空間的轉換,Y代表的是亮度,也就是灰階值,Cb則是藍色的色差,Cr則為紅色的色差,因此,這邊直接拿cvLoadImage()讀取灰階圖形來跟Y值圖形來做比較.中間有用到通道分割的函式cvSplit()則是要參考前面資料結構"通道的分割,合併與混合"的部份,cvTransform()的第四個引數則是對轉移矩陣計算後的數值結果做平移的運算.
cvTransform()
將圖形或矩陣做矩陣變換,矩陣變換的向量維度是以通道為基礎,也就是轉移矩陣會對通道向量做相乘而完成色彩空間的轉換,第四個引數則是對計算結果的向量做位移的調整,而轉移矩陣的m*n大小可以決定輸出通道的維度,這邊m代表輸入通道數,n代表輸出通道數.
cvTransform(輸入CvMat或IplImage資料結構,輸出CvMat或IplImage資料結構,CvMat轉移矩陣資料結構,CvMat平移向量資料結構)
2008年8月19日 星期二
2008年8月16日 星期六
OpenCV線性代數-cvSVBkSb奇異值倒回替代法
cvSVBkSb()為解線性系統解專用的,實際上它跟前面的cvSolve()的線性系統求解的奇異值法是一樣的東西,cvSolve()內部的CV_SVD參數它的計算方式實際上就是呼叫cvSVBkSb()這個函式,所以,用起來的方式差不多,在這邊簡單的做cvSVBkSb()的使用方法.
線性系統求解-奇異值倒回替代法
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={-1,2,-1,3,1,-4,5,-5,-2,6,-5,7,-1,-4,11,-2};
float Array2[]={6,-7,7,7};
int main()
{
CvMat *A=cvCreateMat(4,4,CV_32FC1);
CvMat *b=cvCreateMat(4,1,CV_32FC1);
CvMat *W=cvCreateMat(4,4,CV_32FC1);
CvMat *U=cvCreateMat(4,4,CV_32FC1);
CvMat *V=cvCreateMat(4,4,CV_32FC1);
CvMat *x=cvCreateMat(4,1,CV_32FC1);
cvSetData(A,Array1,A->step);
cvSetData(b,Array2,b->step);
cvSVD(A,W,U,V);
cvSVBkSb(W,U,V,b,x,0);
PrintMatrix(x,x->rows,x->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
在這邊,要用cvSVBkSb()之前就要先用到前面的cvSVD()了,在將cvSVD()奇異值分解的數值餵進cvSVBkSb()裡面解線性系統解,這邊奇異值倒回替代法用的是虛反矩陣的觀念,虛反矩陣則是在前面cvInvert()裡面有提到,而它的第四個引數為cvSVBkSb()的參數及代號,與cvSVD()相同,可輸入的參數為
#define CV_SVD_U_T 2
#define CV_SVD_V_T 4
分別代表U矩陣跟V矩陣輸入是否為轉置,如果不需要任何轉置輸入則將參數代號預設為0,而此題的線性系統,驗證及計算的方式如下
cvSVBkSb()
為線性系統求解的奇異值替代倒回法,對於一個無解的線性系統,使用奇異值替代倒回法可以求得近似解,但是使用cvSVBkSb()這個函式時必須要先做cvSVD()奇異值分解的計算,在將分解後的矩陣丟給cvSVBkSb()求線性系統的解,使用到的是虛反矩陣的概念,第一個引數為CvMat結構的W矩陣,第二個引數為CvMat結構的U矩陣,第三個引數為CvMat結構的V矩陣,前面的矩陣結構都必須經由cvSVD()奇異值分解計算而得,第四個引數為Ax的線性組合數據,第五個引數為x的解集合,第六個引數則是cvSVBkSb()的參數輸入,只有CV_SVD_U_T及CV_SVD_V_T或者是0(無參數)這三種.
cvSVBkSb(CvMat資料結構W矩陣輸入,CvMat資料結構U矩陣輸入,CvMat資料結構V矩陣輸入,CvMat資料結構b矩陣輸入,CvMat資料結構線性系統解集合x矩陣,目標參數或代號)
線性系統求解-奇異值倒回替代法
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={-1,2,-1,3,1,-4,5,-5,-2,6,-5,7,-1,-4,11,-2};
float Array2[]={6,-7,7,7};
int main()
{
CvMat *A=cvCreateMat(4,4,CV_32FC1);
CvMat *b=cvCreateMat(4,1,CV_32FC1);
CvMat *W=cvCreateMat(4,4,CV_32FC1);
CvMat *U=cvCreateMat(4,4,CV_32FC1);
CvMat *V=cvCreateMat(4,4,CV_32FC1);
CvMat *x=cvCreateMat(4,1,CV_32FC1);
cvSetData(A,Array1,A->step);
cvSetData(b,Array2,b->step);
cvSVD(A,W,U,V);
cvSVBkSb(W,U,V,b,x,0);
PrintMatrix(x,x->rows,x->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
在這邊,要用cvSVBkSb()之前就要先用到前面的cvSVD()了,在將cvSVD()奇異值分解的數值餵進cvSVBkSb()裡面解線性系統解,這邊奇異值倒回替代法用的是虛反矩陣的觀念,虛反矩陣則是在前面cvInvert()裡面有提到,而它的第四個引數為cvSVBkSb()的參數及代號,與cvSVD()相同,可輸入的參數為
#define CV_SVD_U_T 2
#define CV_SVD_V_T 4
分別代表U矩陣跟V矩陣輸入是否為轉置,如果不需要任何轉置輸入則將參數代號預設為0,而此題的線性系統,驗證及計算的方式如下
cvSVBkSb()
為線性系統求解的奇異值替代倒回法,對於一個無解的線性系統,使用奇異值替代倒回法可以求得近似解,但是使用cvSVBkSb()這個函式時必須要先做cvSVD()奇異值分解的計算,在將分解後的矩陣丟給cvSVBkSb()求線性系統的解,使用到的是虛反矩陣的概念,第一個引數為CvMat結構的W矩陣,第二個引數為CvMat結構的U矩陣,第三個引數為CvMat結構的V矩陣,前面的矩陣結構都必須經由cvSVD()奇異值分解計算而得,第四個引數為Ax的線性組合數據,第五個引數為x的解集合,第六個引數則是cvSVBkSb()的參數輸入,只有CV_SVD_U_T及CV_SVD_V_T或者是0(無參數)這三種.
cvSVBkSb(CvMat資料結構W矩陣輸入,CvMat資料結構U矩陣輸入,CvMat資料結構V矩陣輸入,CvMat資料結構b矩陣輸入,CvMat資料結構線性系統解集合x矩陣,目標參數或代號)
標籤:
OpenCV,
OpenCV線性代數
2008年8月14日 星期四
OpenCV線性代數-cvSVD奇異值分解(2)
這邊就要簡單介紹cvSVD()的所有參數及用法,cvSVD()在"cxcore.h"裡面的參數分別被定義為
#define CV_SVD_MODIFY_A 1
#define CV_SVD_U_T 2
#define CV_SVD_V_T 4
第一個CV_SVD_MODIFY_A是將A矩陣的空間做填充,用空間換取時間的方式做加速的運算,而後面的CV_SVD_U_T,及CV_SVD_V_T則是單純的將U跟V做轉置.接著下面的程式拿非奇異矩陣做奇異值分解並且加上cvSVD()的參數.
非奇異矩陣奇異值分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V,CV_SVD_MODIFY_A);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面使用了CV_SVD_MODIFY_A,由上面的非奇異矩陣得知,無法求得他的Eign Value及Eigen Vector,但是可以求得它的奇異值以及它的分解矩陣,並且藉由矩陣相乘的方式計算回原矩陣.計算及驗證的方式如下
而使用了CV_SVD_V_T這個參數則可以省略掉對V做cvTranspose()轉置的步驟.
cvSVD()使用CV_SVD_V_T參數
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V_T,CV_SVD_V_T);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV_T\n");
PrintMatrix(V_T,V_T->rows,V_T->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面的程式碼跟前面的差別,就是直接在cvSVD()內部將V矩陣轉置,可以直接將奇異值分解做驗證,而CV_SVD_U_T亦是直接將U矩陣在內部轉置.
cvSVD()
將任何的矩陣做奇異值分解,假如要分解的矩陣是m*n,則W矩陣CvMat資料結構輸入格式必須是m*n,U矩陣CvMat資料結構輸入格式必須是m*m,V矩陣CvMat資料結構輸入格式必須是n*n,cvSVD()第一個引數為輸入目標CvMat矩陣資料結構,第二個引數為輸出W矩陣CvMat資料結構,第三個引數為U矩陣CvMat資料結構,第四個引數為V矩陣CvMat資料結構,第五個引數為cvSVD()的參數,分別為CV_SVD_MODIFY_A,CV_SVD_U_T,CV_SVD_V_T.
cvSVD(輸入CvMat資料結構,輸出W矩陣CvMat結構,輸出U矩陣CvMat結構,輸出V矩陣CvMat結構,目標參數或代號)
#define CV_SVD_MODIFY_A 1
#define CV_SVD_U_T 2
#define CV_SVD_V_T 4
第一個CV_SVD_MODIFY_A是將A矩陣的空間做填充,用空間換取時間的方式做加速的運算,而後面的CV_SVD_U_T,及CV_SVD_V_T則是單純的將U跟V做轉置.接著下面的程式拿非奇異矩陣做奇異值分解並且加上cvSVD()的參數.
非奇異矩陣奇異值分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V,CV_SVD_MODIFY_A);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面使用了CV_SVD_MODIFY_A,由上面的非奇異矩陣得知,無法求得他的Eign Value及Eigen Vector,但是可以求得它的奇異值以及它的分解矩陣,並且藉由矩陣相乘的方式計算回原矩陣.計算及驗證的方式如下
而使用了CV_SVD_V_T這個參數則可以省略掉對V做cvTranspose()轉置的步驟.
cvSVD()使用CV_SVD_V_T參數
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={1,3,3,-3,-5,-3,3,3,1};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V_T,CV_SVD_V_T);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV_T\n");
PrintMatrix(V_T,V_T->rows,V_T->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面的程式碼跟前面的差別,就是直接在cvSVD()內部將V矩陣轉置,可以直接將奇異值分解做驗證,而CV_SVD_U_T亦是直接將U矩陣在內部轉置.
cvSVD()
將任何的矩陣做奇異值分解,假如要分解的矩陣是m*n,則W矩陣CvMat資料結構輸入格式必須是m*n,U矩陣CvMat資料結構輸入格式必須是m*m,V矩陣CvMat資料結構輸入格式必須是n*n,cvSVD()第一個引數為輸入目標CvMat矩陣資料結構,第二個引數為輸出W矩陣CvMat資料結構,第三個引數為U矩陣CvMat資料結構,第四個引數為V矩陣CvMat資料結構,第五個引數為cvSVD()的參數,分別為CV_SVD_MODIFY_A,CV_SVD_U_T,CV_SVD_V_T.
cvSVD(輸入CvMat資料結構,輸出W矩陣CvMat結構,輸出U矩陣CvMat結構,輸出V矩陣CvMat結構,目標參數或代號)
標籤:
OpenCV,
OpenCV線性代數
2008年8月11日 星期一
OpenCV線性代數-cvSVD奇異值分解(1)
奇異值分解(Singular Value Decomposition,SVD),可以說是對角化應用的特例,它具有與Eigen Value,Eigen Vector相同的特性,分解後向量的矩陣乘積可以還原為原矩陣,而他可以對奇異矩陣(Singular Matrix)做分解,亦可以對非奇異矩陣做分解.奇異矩陣的定義就是不能計算為反矩陣的矩陣,包括方陣,以及非方陣的長方形矩陣.而奇異值分解的計算它的數學定義為
它將奇異矩陣轉置後相乘,藉由這個方法計算出對稱矩陣,在對對稱矩陣做SVD分解,由上面可知,原矩陣大小為m*n,而W(Sigma)矩陣的舉陣大小必須為m*n,U的矩陣大小必須為m*m,而V的矩陣大小為n*n,它可以藉由矩陣矩陣相乘的方式算回原矩陣.
下面這個是拿2*3的奇異矩陣做奇異值分解
奇異矩陣SVD分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={3,2,2,2,3,-2};
int main()
{
CvMat *Matrix1=cvCreateMat(2,3,CV_64FC1);
CvMat *W=cvCreateMat(2,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(2,2,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(2,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面的程式,利用了前面奇異值分解公式說明的方式,cvSVD()的內部運算,先將矩陣做轉置在相乘,求得對稱矩陣,在將該矩陣做奇異值分解,而它的W,U,V矩陣的大小皆不相同,W將會是原矩陣大小2*3,V則是2*2,U則會是3*3,因此利用公式倒回運算,可以計算出原矩陣,計算以及驗證的公式如下.
而對稱矩陣的奇異值分解,則是不需要再做轉置後相乘,直接做奇異值分解.
對稱矩陣奇異值分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={2,-2,4,-2,2,-4,4,-4,8};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
這是一個直接用對稱矩陣做奇異值分解的程式,奇異值分解很特別的地方,它對對稱矩陣做奇異值分解求得的結果為特徵值(Eigen Value)及特徵向量(Eigen Vector),但是相較於cvEigenVV()這兩個使用的是不同的演算法,而一般的矩陣則無法用cvSVD()求特徵值及特徵向量,上面的程式用cvSVD()分別求出它的W,U,V,在代回原公式做驗證,驗證的方法如下
驗證對稱矩陣奇異值分解
它將奇異矩陣轉置後相乘,藉由這個方法計算出對稱矩陣,在對對稱矩陣做SVD分解,由上面可知,原矩陣大小為m*n,而W(Sigma)矩陣的舉陣大小必須為m*n,U的矩陣大小必須為m*m,而V的矩陣大小為n*n,它可以藉由矩陣矩陣相乘的方式算回原矩陣.
下面這個是拿2*3的奇異矩陣做奇異值分解
奇異矩陣SVD分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={3,2,2,2,3,-2};
int main()
{
CvMat *Matrix1=cvCreateMat(2,3,CV_64FC1);
CvMat *W=cvCreateMat(2,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(2,2,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(2,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
上面的程式,利用了前面奇異值分解公式說明的方式,cvSVD()的內部運算,先將矩陣做轉置在相乘,求得對稱矩陣,在將該矩陣做奇異值分解,而它的W,U,V矩陣的大小皆不相同,W將會是原矩陣大小2*3,V則是2*2,U則會是3*3,因此利用公式倒回運算,可以計算出原矩陣,計算以及驗證的公式如下.
而對稱矩陣的奇異值分解,則是不需要再做轉置後相乘,直接做奇異值分解.
對稱矩陣奇異值分解
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={2,-2,4,-2,2,-4,4,-4,8};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *W=cvCreateMat(3,3,CV_64FC1);
CvMat *V=cvCreateMat(3,3,CV_64FC1);
CvMat *U=cvCreateMat(3,3,CV_64FC1);
CvMat *V_T=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSVD(Matrix1,W,U,V);
printf("\nW\n");
PrintMatrix(W,W->rows,W->cols);
printf("\nU\n");
PrintMatrix(U,U->rows,U->cols);
printf("\nV\n");
PrintMatrix(V,V->rows,V->cols);
printf("\nValid\n");
cvmMul(U,W,ResultMatrix);
cvTranspose(V,V_T);
cvmMul(ResultMatrix,V_T,ResultMatrix);
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
這是一個直接用對稱矩陣做奇異值分解的程式,奇異值分解很特別的地方,它對對稱矩陣做奇異值分解求得的結果為特徵值(Eigen Value)及特徵向量(Eigen Vector),但是相較於cvEigenVV()這兩個使用的是不同的演算法,而一般的矩陣則無法用cvSVD()求特徵值及特徵向量,上面的程式用cvSVD()分別求出它的W,U,V,在代回原公式做驗證,驗證的方法如下
驗證對稱矩陣奇異值分解
標籤:
OpenCV,
OpenCV線性代數
2008年8月3日 星期日
OpenCV線性代數-cvEigenVV實作
cvEigenVV()為計算CvMat方陣的特徵值(Eigen Value)跟特徵向量(Eigen Vector)的函式,但是,OpenCV的Eigen Value跟Eigen Vector計算並不是一般性的用法,無法處理正常的特徵值跟特徵向量的計算,cvEigenVV()是使用到Jacobi Eigenvalue Algorithm的方法,輸入必須要對稱矩陣,輸入的對稱矩陣做Jacobi Transformation的轉換,這部份的資料就要參考數值分析(Numerical Recipes)的相關書籍了,而Jacobi Eigenvalue Algorithm有將Eigen Value重新Sort過,因此特徵值的排序會是由大到小排列,而不適用於很多矩陣對角化的解題應用.
cvEigenVV()實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={2,3,0,3,5,-1,0,-1,2};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenValue_Row=cvCreateMat(3,1,CV_64FC1);
CvMat *EigenValue=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenVector=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenVector_Invert=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetZero(EigenValue);
cvEigenVV(Matrix1,EigenVector,EigenValue_Row,DBL_EPSILON);
printf("\nThe EigenValue_Row is:\n");
PrintMatrix(EigenValue_Row,EigenValue_Row->rows,EigenValue_Row->cols);
printf("\nThe EigenVector is:\n");
PrintMatrix(EigenVector,EigenVector->rows,EigenVector->cols);
printf("\nThe EigenValue is:\n");
cvSet2D(EigenValue,0,0,cvGet2D(EigenValue_Row,0,0));
cvSet2D(EigenValue,1,1,cvGet2D(EigenValue_Row,1,0));
cvSet2D(EigenValue,2,2,cvGet2D(EigenValue_Row,2,0));
PrintMatrix(EigenValue,EigenValue->rows,EigenValue->cols);
cvTranspose(EigenVector,EigenVector);
cvmMul(EigenVector,EigenValue,ResultMatrix);
cvInvert(EigenVector,EigenVector_Invert,CV_LU);
cvmMul(ResultMatrix,EigenVector_Invert,ResultMatrix);
printf("\nTo validate Matrix\n");
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
由上面可以知道Eigen Value的排列方式為
而Eigen Vector的排列方式為
因此,要驗證是否可行,利用
的方法將它還原為對稱矩陣,則必須要將輸出的列矩陣補0讓它成為對角矩陣,並且將Eigen Vector矩陣做轉置,帶入驗證公式,輸出結果為原對稱矩陣,因此可以證明此函式及輸入值無誤
cvEigenVV()第一的引數為特徵向量(Eigen Vector)第二個引數為特徵值(Eigen Value)第三個引數為精確度,DBL_EPSILON為最小double型別精確度,而一般精確度的使用定義為
#define FLT_EPSILON 1.19209290E-07F
#define DBL_EPSILON 2.2204460492503131E-16
這可以來做浮點數的精確度比較運算使用.
而他的使用方式就如同下所述
bool IsEqual(double x,double y)
{
if(x-y<DBL_EPSILON)
{
return true;
}
else
{
return false;
}
}
double型別則對照DBL_EPSILON參數,float型別則對照FLT_EPSILON,而cvEigenVV()則可以自行定義它的精確度比較運算的大小.
cvEigenVV()
利用Jacobi Eigenvalue Algorithm法計算Eigen Value,Eigen Vector,輸入只能為對稱矩陣,輸出則是Eigen Value的列舉陣及Eigen Vector的列舉陣,第一個引數為要計算的CvMat資料結構對稱矩陣,第二個引數為CvMat資料結構的Eigen Value列舉陣,第三個引數是CvMat資料結構的Eigen Vector列舉陣,第四個引數為精確度比較運算的大小.
cvEigenVV(輸入CvMat資料結構對稱矩陣,輸出CvMat資料結構的EigenValue列舉陣,輸出CvMat資料結構的EigenVector列舉陣,浮點型別精準度誤差比較數值)
cvEigenVV()實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
double Array1[]={2,3,0,3,5,-1,0,-1,2};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenValue_Row=cvCreateMat(3,1,CV_64FC1);
CvMat *EigenValue=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenVector=cvCreateMat(3,3,CV_64FC1);
CvMat *EigenVector_Invert=cvCreateMat(3,3,CV_64FC1);
CvMat *ResultMatrix=cvCreateMat(3,3,CV_64FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetZero(EigenValue);
cvEigenVV(Matrix1,EigenVector,EigenValue_Row,DBL_EPSILON);
printf("\nThe EigenValue_Row is:\n");
PrintMatrix(EigenValue_Row,EigenValue_Row->rows,EigenValue_Row->cols);
printf("\nThe EigenVector is:\n");
PrintMatrix(EigenVector,EigenVector->rows,EigenVector->cols);
printf("\nThe EigenValue is:\n");
cvSet2D(EigenValue,0,0,cvGet2D(EigenValue_Row,0,0));
cvSet2D(EigenValue,1,1,cvGet2D(EigenValue_Row,1,0));
cvSet2D(EigenValue,2,2,cvGet2D(EigenValue_Row,2,0));
PrintMatrix(EigenValue,EigenValue->rows,EigenValue->cols);
cvTranspose(EigenVector,EigenVector);
cvmMul(EigenVector,EigenValue,ResultMatrix);
cvInvert(EigenVector,EigenVector_Invert,CV_LU);
cvmMul(ResultMatrix,EigenVector_Invert,ResultMatrix);
printf("\nTo validate Matrix\n");
PrintMatrix(ResultMatrix,ResultMatrix->rows,ResultMatrix->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
由上面可以知道Eigen Value的排列方式為
而Eigen Vector的排列方式為
因此,要驗證是否可行,利用
的方法將它還原為對稱矩陣,則必須要將輸出的列矩陣補0讓它成為對角矩陣,並且將Eigen Vector矩陣做轉置,帶入驗證公式,輸出結果為原對稱矩陣,因此可以證明此函式及輸入值無誤
cvEigenVV()第一的引數為特徵向量(Eigen Vector)第二個引數為特徵值(Eigen Value)第三個引數為精確度,DBL_EPSILON為最小double型別精確度,而一般精確度的使用定義為
#define FLT_EPSILON 1.19209290E-07F
#define DBL_EPSILON 2.2204460492503131E-16
這可以來做浮點數的精確度比較運算使用.
而他的使用方式就如同下所述
bool IsEqual(double x,double y)
{
if(x-y<DBL_EPSILON)
{
return true;
}
else
{
return false;
}
}
double型別則對照DBL_EPSILON參數,float型別則對照FLT_EPSILON,而cvEigenVV()則可以自行定義它的精確度比較運算的大小.
cvEigenVV()
利用Jacobi Eigenvalue Algorithm法計算Eigen Value,Eigen Vector,輸入只能為對稱矩陣,輸出則是Eigen Value的列舉陣及Eigen Vector的列舉陣,第一個引數為要計算的CvMat資料結構對稱矩陣,第二個引數為CvMat資料結構的Eigen Value列舉陣,第三個引數是CvMat資料結構的Eigen Vector列舉陣,第四個引數為精確度比較運算的大小.
cvEigenVV(輸入CvMat資料結構對稱矩陣,輸出CvMat資料結構的EigenValue列舉陣,輸出CvMat資料結構的EigenVector列舉陣,浮點型別精準度誤差比較數值)
標籤:
OpenCV,
OpenCV線性代數
2008年8月1日 星期五
OpenCV線性代數-秩,線性系統求解(2)
在cvSolve()裡面,輸入的係數矩陣規定要方陣,那假如所求的線性系統不是方陣怎麼辦呢?那當然就是要用補0了方式填充成方陣,使用的方法請看以下程式碼.
解線性方程式4
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={1,1,0,2,1,0,3,2,0};
float Array2[]={1,3,4};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetData(Matrix2,Array2,Matrix2->step);
cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);
PrintMatrix(SolveSet,SolveSet->rows,SolveSet->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
線性系統判斷
上面的程式是尾端補0,因為這個線性系統只存在兩個未知數,三個方程式,要給它弄成方陣,則只好假設有第三個未知數存在,但係數為0,而只要是需要補0的線性系統運算,全部都需要用CV_SVD來解,LU是無法解的.再來,下面是整欄補零的範例.
解線性方程式5
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={1,1,1,1,2,0,0,0,0};
float Array2[]={4,6,0};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetData(Matrix2,Array2,Matrix2->step);
cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);
PrintMatrix(SolveSet,SolveSet->rows,SolveSet->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
線性系統判斷
這個線性系統是四個未知數,三個方程式,很顯然的是無限解,用SVD的方法的話就會任意給一個可行解,而至於cvSolve()的另外一個參數CV_SVD_SYM,則是線性系統對對稱係數矩陣的加速算法,也是跟前面相關的程式碼同樣的用法,這邊不再累述.
cvSolve()
為解線性方程式的函式,可以對唯一解,無解,無限解,而無限解的問題會給予一個答案,無解的問題則是用CV_SVD參數則可得到近似解,而無限解的問題則用cvSolve()參數可以得到可行解.第一個引數為CvMat係數矩陣,第二個引數為線性方程式的線性組合解,第三個引數為代數的解集合,第四個為解線性方程的參數輸入,分別為CV_LU,CV_SVD,CV_SVD_SYM,與求反矩陣的函式相同參數.
cvSolve(CvMat係數矩陣結構,CvMat結構線性組合解,CvMat結構代數解集合,輸入計算參數或代號)
解線性方程式4
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={1,1,0,2,1,0,3,2,0};
float Array2[]={1,3,4};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetData(Matrix2,Array2,Matrix2->step);
cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);
PrintMatrix(SolveSet,SolveSet->rows,SolveSet->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
線性系統判斷
上面的程式是尾端補0,因為這個線性系統只存在兩個未知數,三個方程式,要給它弄成方陣,則只好假設有第三個未知數存在,但係數為0,而只要是需要補0的線性系統運算,全部都需要用CV_SVD來解,LU是無法解的.再來,下面是整欄補零的範例.
解線性方程式5
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
void PrintMatrix(CvMat *Matrix,int Rows,int Cols);
float Array1[]={1,1,1,1,2,0,0,0,0};
float Array2[]={4,6,0};
int main()
{
CvMat *Matrix1=cvCreateMat(3,3,CV_32FC1);
CvMat *Matrix2=cvCreateMat(3,1,CV_32FC1);
CvMat *SolveSet=cvCreateMat(3,1,CV_32FC1);
cvSetData(Matrix1,Array1,Matrix1->step);
cvSetData(Matrix2,Array2,Matrix2->step);
cvSolve(Matrix1,Matrix2,SolveSet,CV_SVD);
PrintMatrix(SolveSet,SolveSet->rows,SolveSet->cols);
system("pause");
}
void PrintMatrix(CvMat *Matrix,int Rows,int Cols)
{
for(int i=0;i<Rows;i++)
{
for(int j=0;j<Cols;j++)
{
printf("%.2f ",cvGet2D(Matrix,i,j).val[0]);
}
printf("\n");
}
}
執行結果:
線性系統判斷
這個線性系統是四個未知數,三個方程式,很顯然的是無限解,用SVD的方法的話就會任意給一個可行解,而至於cvSolve()的另外一個參數CV_SVD_SYM,則是線性系統對對稱係數矩陣的加速算法,也是跟前面相關的程式碼同樣的用法,這邊不再累述.
cvSolve()
為解線性方程式的函式,可以對唯一解,無解,無限解,而無限解的問題會給予一個答案,無解的問題則是用CV_SVD參數則可得到近似解,而無限解的問題則用cvSolve()參數可以得到可行解.第一個引數為CvMat係數矩陣,第二個引數為線性方程式的線性組合解,第三個引數為代數的解集合,第四個為解線性方程的參數輸入,分別為CV_LU,CV_SVD,CV_SVD_SYM,與求反矩陣的函式相同參數.
cvSolve(CvMat係數矩陣結構,CvMat結構線性組合解,CvMat結構代數解集合,輸入計算參數或代號)
標籤:
OpenCV,
OpenCV線性代數
訂閱:
文章 (Atom)