• Matlab立体标定mat转换成Opencv的CvMat


    最近在做基于双目视觉的三维重建。比较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入门级,解决该问题还是花费了一定时间,望本博客对可能同是菜鸟的你有所帮助。

  • 相关阅读:
    Goroutine被动调度之一(18)
    实战分析一个运行起来会卡死的Go程序
    Go语言调度器之盗取goroutine(17)
    第三章 Goroutine调度策略(16)
    非main goroutine的退出及调度循环(15)
    Go语言调度器之调度main goroutine(14)
    PHP经典面试题之 Redis 内存满了怎么办?
    【PHP】让新人快速理解ThinkPHP6中的事务操作
    面试官:说说swoole+PHP实现自动取消订单,还原库存等操作
    最新整理的PHP高级面试题来啦!【附答案】
  • 原文地址:https://www.cnblogs.com/luckyboylch/p/6482579.html
Copyright © 2020-2023  润新知