最近在做基於雙目視覺的三維重建。比較opencv和matlab工具箱的立體標定結果精度時,發現貌似如果手工選取角點不那么離譜的話,matlab標定結果精度更高也更魯棒。就想先用matlab標定好相機,再把結果供opencv函數加載使用。如何將Matlab標定結果的.mat文件轉成需要的CvMat矩陣,就是本篇博客所要講的。
主要參考:http://www.jianshu.com/p/ad6a2f8a3fc8
這里分以下三步來講:
1、先在matlab中加載.mat文件成matlab中的矩陣;
(1)生成MAT文件
eg1:
>>A=[1 2;3 4];%matlab中矩陣按列保存而非opencv中按行保存
>>save mydata A;%mydata表示文件名
eg2:
>>A=[1 2;3 4];
>>B=[2 3;5 6];
>>save mydata A B;%保存多個矩陣直接將矩陣名都寫上,簡單方法是save mydata;回車即可則將運行空間中的所有變量都保存到文件中.
(2)從.mat文件中讀取所有數據
首先將想打開的mat文件所在的目錄設置為當前工作目錄(cd 路徑);
然后執行:load mydata;即可,想看哪個變量的值直接輸入變量名回車即可.
若只想讀取mat文件指定數據,eg:load mydata A;則運行空間中將不出現B
2、再將該矩陣按yml格式保存成yml文件;
matlab中int類型對應i,float類型對應f,double類型對應d.
定義了函數的.m腳本文件,若想在命令行窗口中直接調用,即使當前運行路徑與腳本文件相同也需要將腳本文件所在目錄添加到設置路徑中才能夠直接調用,否則會說該函數未定義.(在腳本中調用某個腳本函數,只需要將兩個腳本文件放在同一目錄下即可)
*************************創建腳本matlab2opencv.m**************************************
%該函數將matlab中的mat矩陣保存成yml文件 function matlab2opencv( variable, fileName, flag) [rows cols] = size(variable); % Beware of Matlab's linear indexing variable = variable'; % Write mode as default if ( ~exist('flag','var') ) flag = 'w'; end if ( ~exist(fileName,'file') || flag == 'w' ) % New file or write mode specified file = fopen( fileName, 'w');%不存在則創建寫入模式 fprintf( file, '%%YAML:1.0\n'); else % Append mode file = fopen( fileName, 'a');%存在則追加模式 end % Write variable header fprintf( file, '%s: !!opencv-matrix\n', inputname(1)); fprintf( file, ' rows: %d\n', rows); fprintf( file, ' cols: %d\n', cols); fprintf( file, ' dt: d\n');%double類型 fprintf( file, ' data: [ '); % Write variable data for i=1:rows*cols fprintf( file, '%.16d', variable(i));%16表示小數點后有16位 if (i == rows*cols), break, end if mod(i+1,4) == 0 fprintf( file, ',\n '); else fprintf( file, ', '); end end fprintf( file, ']\n'); fclose(file);
接着就可以從.mat立體標定結果文件中提取需要的信息保存到CvMat中:
*******************************創建腳本savemat2yml.m****************************
%利用matlab2opencv函數從matlab標定結果矩陣中提取所需的數值保存到對應的yml文件中(按opencv函數所需矩陣的順序設置值),以供opencv直接利用cvLoad等加載調用. cd D:\MATLAB\R2014a\toolbox\TOOLBOX_calib\calib_images;%切換到立體標定結果的目錄下 load Calib_Results_stereo.mat;%加載標定結果矩陣 %左攝像機內參數矩陣3x3 %fx 0 cx %0 fy cy %0 0 1 M1(1,1)=fc_right(1); M1(1,2)=0; M1(1,3)=cc_right(1); M1(2,1)=0; M1(2,2)=fc_right(2); M1(2,3)=cc_right(2); M1(3,1)=0; M1(3,2)=0; M1(3,3)=1; %左畸變參數向量1x5(貌似也可以是5x1則直接用),記錄的順序為k1,k2,p1,p2,k3 D1(1,1)=kc_right(1); D1(1,2)=kc_right(2); D1(1,3)=kc_right(3); D1(1,4)=kc_right(4); D1(1,5)=kc_right(5); %一般為0 %右攝像機內參數矩陣3x3 %fx 0 cx %0 fy cy %0 0 1 M2(1,1)=fc_right(1); M2(1,2)=0; M2(1,3)=cc_right(1); M2(2,1)=0; M2(2,2)=fc_right(2); M2(2,3)=cc_right(2); M2(3,1)=0; M2(3,2)=0; M2(3,3)=1; %右畸變參數向量1x5(貌似也可以是5x1則直接用),記錄的順序為k1,k2,p1,p2,k3 D2(1,1)=kc_right(1); D2(1,2)=kc_right(2); D2(1,3)=kc_right(3); D2(1,4)=kc_right(4); D2(1,5)=kc_right(5); %攝像機間的旋轉矩陣3x3,可直接用 %攝像機間的平移矩陣3x1,也可直接用 %調用matlab2opencv函數保存矩陣到yml文件 matlab2opencv(M1,'M1.yml');%注意該函數腳本要與本腳本在同一目錄下或者該函數腳本已設置路徑了 matlab2opencv(D1,'D1.yml'); matlab2opencv(M2,'M2.yml'); matlab2opencv(D2,'D2.yml'); matlab2opencv(R,'R.yml'); matlab2opencv(T,'T.yml');
3、最后opencv加載該yml文件,並以Mat、CvMat的格式保存到一個變量中.
若yml文件中只有一個矩陣可以直接調用cvSave和cvLoad保存和加載yml文件.eg:
1 #include <cv.h>
2 #include <highgui.h> 3 #include<iostream> 4 using namespace std; 5 6 ostream& operator<<(ostream& out,CvMat* mat) 7 { 8 cout<<"C++方式輸出矩陣:"<<endl; 9 cout<<"mat.rows="<<mat->rows<<",mat.cols="<<mat->cols<<"\n["<<endl; 10 for(int i=0;i<mat->rows;i++) 11 { 12 for(int j=0;j<mat->cols;j++) 13 { 14 //設置輸出寬度為25,按左對齊,數值的有效數字位數為20(整數+小數) 15 cout<<setw(25)<<setiosflags(ios::left)<<setprecision(20)<<CV_MAT_ELEM(*mat,double,i,j); 16 } 17 if(i==mat->rows-1) 18 cout<<"\n]\n\n"; 19 else 20 cout<<endl; 21 } 22 return out; 23 } 24 25 26 void main() 27 { 28 CvMat* M1=(CvMat*)cvLoad("C:/Users/shark/Desktop/M1.yml"); 29 cout<<M1<<endl; 30 getchar(); 31 }
博主matlab入門級,解決該問題還是花費了一定時間,望本博客對可能同是菜鳥的你有所幫助。