最近在做基于双目视觉的三维重建。比较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 '); else % Append mode file = fopen( fileName, 'a');%存在则追加模式 end % Write variable header fprintf( file, '%s: !!opencv-matrix ', inputname(1)); fprintf( file, ' rows: %d ', rows); fprintf( file, ' cols: %d ', cols); fprintf( file, ' dt: d ');%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, ', '); else fprintf( file, ', '); end end fprintf( file, '] '); fclose(file);
接着就可以从.mat立体标定结果文件中提取需要的信息保存到CvMat中:
*******************************创建脚本savemat2yml.m****************************
%利用matlab2opencv函数从matlab标定结果矩阵中提取所需的数值保存到对应的yml文件中(按opencv函数所需矩阵的顺序设置值),以供opencv直接利用cvLoad等加载调用. cd D:MATLABR2014a oolboxTOOLBOX_calibcalib_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<<"
["<<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<<"
]
";
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入门级,解决该问题还是花费了一定时间,望本博客对可能同是菜鸟的你有所帮助。