bundle adjustment 玩具程序

结合 bundle adjustment原理(1) 和 Levenberg-Marquardt 的 MATLAB 代码 两篇博客的成果,调用MATLAB R2016a中

bundleAdjustment函数的测试程序中的数据的一部分,即“ load('sfmGlobe'); ” 里头的数据,其中17,18,19,20号点的在5个相机

中都能看到,使用这4个点以及5个相机中前面3个相机的数据。假设4个点在这3个相机中都能看到。

 

数据预处理

 

clear all;clc;close all;

% K = ...
%     [1037.57521466470                  0   0;
%                     0   1043.31575231792   0;
%      642.231583031218   387.835775096238   1];
%%
% R1 = [0.999930666970964   -0.00673945294088071 -0.00965613924202793;
%       0.00668517563735327  0.999961735652987   -0.00564230950615111;
%       0.00969379583555976  0.00557736532093060  0.999937459703543];
% 
% t1 = [-4.60753903591915 -0.701533199568890 0.119971001005677];
% P1 = [R1'; -t1*R1']*K;
% P1 = P1';
% P1 = P1./P1(3,4);

P1 = [-14620.8683429521,       47.7785183087137   -8855.66144393024   -66270.2808443708;
        -150.369995939471  -14644.8224529801      -5350.11740074225   -10324.8058386147;
          -0.135793602589110   -0.0781294079978937  -14.0074241628698      1]
%% 
% R2 = [0.999384955754123,-0.0220100395537247,-0.0272996038647805;
%     0.0221014007388922,0.999751083744459,0.00304936668163826;
%     0.0272256918683320,-0.00365085067123564,0.999622645297548];
% 
% t2 = [-5.40461035623086,-0.607149378177483,0.0285909102976046];
% P2 = [R2'; -t2*R2']*K;
% P2 = P2';
% P2 = P2./P2(3,4);

P2 = [9062.69622961192     -216.435747349655    5274.40400172506    48698.1330568296;
       288.943296284479    8952.83453874359,    3359.51179040131     6901.28235434353;
         0.234003192643106   -0.0313788430818932   8.59169682699799     1]
%% 
% R3 = [0.999208035227214,-0.0175748730472845,-0.0356991060776466;
%     0.0183984784259057,0.999569027655827,0.0228747665080092;
%     0.0352816996328509,-0.0235134597317429,0.999100755120554];
% 
% t3 = [-5.86393384504139,-0.464881933101877,-0.101272085288487];
% 
% P3 = [R3'; -t3*R3']*K;
% P3 = P3';
% P3 = P3./P3(3,4);

P3 = [3565.36981374697     -112.190837623829    2034.77954018230      21061.0035945855;
       110.651455202969    3478.99370169127     1384.37501491977       2406.37267504147;
         0.118737795949451    -0.0791327065517483  3.36239531623893       1]

clear R1 R2 R3 t1 t2 t3;

P_init = zeros(3,4,3);
P_init(:,:,1) = P1;
P_init(:,:,2) = P2;
P_init(:,:,3) = P3;
%% 
X = ...
    [-5.02625233070576,2.60296998435244,13.5169230688245;
     -6.50729565702308,0.628435271318904,11.8262215983732;
     -5.90742477200603,1.96886850306759,13.7807985561123;
     -4.56938330250176,2.35488165029457,13.6960613950965];

%% 
% 17 在相机1,2,3的坐标
pt1 = ...
    [596.60461,635.51575;
     639.97058,639.78851;
     663.65210,649.69757];
pt2 = ...
    [462.77322,497.50113;
     514.51044,498.60583;
     546.38135,507.36337];
pt3 = ...
    [531.15265,585.02240;
    573.08856,586.39777;
    597.81476,596.26666];
pt4 = ...
    [630.10583,613.12250;
    673.04602,618.44708;
    704.32239,622.03772];
%%
pt1 = pt1';
pt1 = pt1(:);

pt2 = pt2';
pt2 = pt2(:);

pt3 = pt3';
pt3 = pt3(:);

pt4 = pt4';
pt4 = pt4(:);

uvw = ...
    [pt1;
     pt2;
     pt3;
     pt4]
clear pt1 pt2 pt3 pt4;

 

P_init 是 3 x 4 x m  的投影矩阵的数据(m=3),齐次的,P(3,4) = 1

X 是 4 个点的三维坐标, n x 3 大小 n = 4

uvw 是 所有的二维特征点的坐标,按照[P1X1;P2X1;P3X1; P1X2; P2X2; ... P1X4;P2X4;P3X4]排列,

大小为 24 x 1 ,即 (m x n x 2)

 

下面是主程序:

 

clear all;clc;close all;

load('uvw.mat');
load('P_init.mat');
load('points3D.mat');

[p m] = P_to_col(P_init);
clear P_init

[x n] = X_to_col(X);

px = [p; x];
clear p x
%%
syms p x;
p_var = sym_mat(p,11*m);
x_var = sym_mat(x,3*n);
px_var = [p_var;
          x_var];
      
fx = px_var_to_fx(px_var,m,n) - uvw;
% sym_in_fx = symvar(fx) % 变量是全的,排列顺序不理想而已
S = transpose(fx)*fx;
%%
t_init = px;
u = 2;
v = 1.5;
beta = 0.4;
eps = 1.0e-6;
tol = 1;
%% 
x = t_init;

jacobian_f = jacobian(fx,px_var);
%% 
info_table = [];
k = 0;
while tol>eps
    fxk = double(subs(fx,px_var,x));
    Sxk = double(subs(S,px_var,x));  % step2: 计算 fxk Sxk
    
    delta_fxk = double(subs(jacobian_f,px_var,x));  % step3: 计算 delta_fxk(J)
    
    delta_Sxk = transpose(delta_fxk)*fxk;   % step4: 计算 delta_Sxk

    while 1
        k = k+1; % 解了一次方程就增加一次计数
        % step5: 计算Q,并解方程(Q+uI)delta_x = -delta_Sxk
        Q = transpose(delta_fxk)*delta_fxk;
        dx = -(Q+u*eye(size(Q)))\delta_Sxk;
        
        x1 = x + dx; % 注意转置
        
        fxk = double(subs(fx,px_var,x1));
        Sxk_new = double(subs(S,px_var,x1));
        
        tol = norm(dx);   % step6: 计算中止条件 norm(dx)<eps 是否满足,不满足转step 7
        tmp = [k tol u Sxk_new]  % 记录迭代过程中的信息
        info_table = [info_table;tmp];
        if tol<=eps
            break;
        end

        % step7: 
        if Sxk_new < Sxk+beta*transpose(delta_Sxk)*dx
            u = u/v;
%             disp(['误差减小 成功,u减小为',num2str(u)]);
            break;
        else
            u = u*v;
%             disp(['误差减小 失败,u增大为',num2str(u)]);
            continue;
        end
    end
    
    x = x1;
    if k>500
        break
    end
end

 

调用了

P_to_col,X_to_col,sym_mat,px_var_to_fx几个函数

function [p m] = P_to_col(P_init)
% 把 3 x 4 x m 的 多个 投影矩阵 转换成单独一列的形式
m = size(P_init,3);
p = [];

for k = 1:m
    tmp = P_init(:,:,k);
    tmp = tmp';
    tmp = tmp(:);
    tmp(12) = [];
    p = [p;tmp];
end
function [x n] = X_to_col(X)
% X是三维的点,必须是 n x 3 的形式

n = size(X,1);
X = X';
x = X(:);
function rtn = sym_mat(x,m,n)
% 生成符号矩阵,第一个参数是一个符号,后面两个参数是符号矩阵的尺寸
% 如果你想生成符号矩阵[x11 x12; x21 x22]只需输入sym_mat(x,2,2)
% 但事先要先声明符号x,用syms x
% 如果你只需要生成一维矩阵,scjsm会生成一个列向量,如sym_mat(x,2);
% 例子:
% syms x;
% A = sym_mat(x,3,4) 返回一个3 x 4的符号矩阵

if nargin == 2
    for i=1:m
        rtn(i)=sym([inputname(1),num2str(i)]);
    end    
    rtn = rtn.';
elseif nargin == 3
    for i = 1:m
        for j = 1:n
            rtn(i,j) = sym([inputname(1),num2str(i),num2str(j)]);
        end
    end
end
function fx = px_var_to_fx(px_var,m,n)

p = px_var(1:11*m);
x = px_var(11*m+1:end);

p = reshape(p,11,m);
p = [p; ones(1,m)];

p_table = [];
for k = 1:m
    tmp = p(:,k);
    tmp = reshape(tmp,4,3);
    tmp = tmp.';  % 3 x 4
    p_table = [p_table;
               tmp];
end

x = reshape(x,3,n);
x = [x; ones(1,n)];

PX = p_table*x;

idx = (1:m)*3;
w = PX(idx,:);
PX(idx,:) = []; % 现在 PX 的行数刚好是 w 的两倍

w2 = [];
for k = 1:m
    ww = repmat(w(k,:),2,1);
    w2 = [w2;
          ww];
end

fx = PX./w2;
fx = fx(:);

 

算法迭代500步后投影误差从 110 多降到了 3.83。

程序是有效的,后续还要添加

1,LDL和amd进去

2,某些点在某些相机看不到的情况

3,对稀疏矩阵分块,然后求解的步骤

4,不使用jacobian函数,J矩阵根据另一篇博客推导出的公式计算

转载于:https://www.cnblogs.com/shepherd2015/p/5867362.html

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值