One effective way to combat error accumulation is called loop closure. When you take multiple captures, a loop may be formed. For instance, when you use a camera to take a panorama view, view 1 and view n overlap. Then there should exist two ways to derive the relative location difference between view 1 and n. The first way is to combine 1->2, 2->3, ..., n-1->n. The second way is to directly find out from n->1 since view 1 and n ends at roughly the same place and form a loop. Due to error accumulation, result obtained by the first way often turns out to be less accurate than the result got from the second method. Thus we can use the second result to calibrate the first result. The outcome of this loop closure technique is that each estimate of 1->2 to n-1->n becomes more accurate.
A seminal paper about loop closure is "Multiview Registration of 3D Scenes by Minimizing Error between Coordinate Frames" written by G C Sharp et. al. Our coding mainly follows this paper and we will call this paper "the paper" for later text. Assuming from view i to view j, the 3D transformation matrix is R(i,j) and offset is t(i.j) where R is a 3-by-3 matrix and t is a 3-by-1 vector, we know R(1,2), R(2,3), ..., R(n-1,n), R(n,1) as well as t(1,2), t(2,3), ..., t(n-1,n), t(n,1). Based on Eq. (11) in the paper, we have:
R(1,2)...R(k,k+1)E(k,k+1)R(k+1,k+2)...R(n,1)=I
where I is a 3-by-3 identity matrix and E(k,k+1) is a 3-by-3 matrix to be found out. We will present Matlab code to calculate E(k,k+1). In Matlab code, R is a matrix which has 3*(n+1) lines and 4 rows. R has format as:
[R(1,2) t(1,2)]
[R(2,3) t(2,3)]
...
[R(n-1,n) t(n-1,n)]
[R(n,1) t(n,1)]
The code to calculate E(k,k+1) is:
Ralpha = zeros(mx, 3); Rbeta = zeros(mx, 3); for i = 1:mx/3 if (i == 1) Ralpha(3*(i-1)+1:3*(i-1)+3,1:3) = R(3*(i-1)+1:3*(i-1)+3,1:3); else Ralpha(3*(i-1)+1:3*(i-1)+3,1:3) = Ralpha(3*(i-2)+1:3*(i-2)+3,1:3)*R(3*(i-1)+1:3*(i-1)+3,1:3); end end for i=mx/3:-1:1 if (i == mx/3) Rbeta(3*(i-1)+1:3*(i-1)+3,1:3) = R(3*(i-1)+1:3*(i-1)+3,1:3); else Rbeta(3*(i-1)+1:3*(i-1)+3,1:3) = R(3*(i-1)+1:3*(i-1)+3,1:3)*Rbeta(3*(i)+1:3*(i)+3,1:3); end end Emat = zeros(mx, 3);Emat_divN = zeros(mx, 3); for i = 1:mx/3 if (i ~= mx/3) Emat(3*(i-1)+1:3*(i-1)+3,1:3) = Ralpha(3*(i-1)+1:3*(i-1)+3,1:3)'*Rbeta(3*i+1:3*i+3,1:3)'; else Emat(3*(i-1)+1:3*(i-1)+3,1:3) = Ralpha(3*(i-1)+1:3*(i-1)+3,1:3)'; end endAfter calculating E(k,k+1), according to Eq. (22) of the paper we need to find the 1/n power of E(k,k+1). Without quaternion, it will be clueless to find the 1/n power of a rotation matrix. But by using quaternion, this become straightforward. We first convert E(k,k+1) to quaternion, divide the rotation angle by n, and then convert it back with the following Matlab code:
for i = 1:mx/3 [w, x, y, z] = R2quaternion(Emat(3*(i-1)+1:3*(i-1)+3,1:3)); w_new=cos(acos(w)/(mx/3)); x_new=x*sin(acos(w)/(mx/3))/sin(acos(w)); y_new=y*sin(acos(w)/(mx/3))/sin(acos(w)); z_new=z*sin(acos(w)/(mx/3))/sin(acos(w)); Emat_divN(3*(i-1)+1:3*(i-1)+3,1:3) = quaternion2R(w_new,x_new,y_new,z_new); endThe final step is to use E_divN(k,k+1) to calibrate R(k,k+1):
Rtilda = zeros(mx, 4); for i = 1:mx/3 Rtilda(3*(i-1)+1:3*(i-1)+3,1:3) = R(3*(i-1)+1:3*(i-1)+3,1:3)*Emat_divN(3*(i-1)+1:3*(i-1)+3,1:3); endFor vector t, we use the simplified approach to calculate the average of all t vectors and deduct this average from each t:
tsum = zeros(3,1); for i = 1:mx/3 tsum = tsum+R(3*(i-1)+1:3*(i-1)+3,4); end tavg = tsum/(mx/3);followed by
for i = 1:mx/3 Rtilda(3*(i-1)+1:3*(i-1)+3,4) = R(3*(i-1)+1:3*(i-1)+3,4)-tavg; endThe whole Matlab code can be downloaded from here: https://drive.google.com/folderview?id=0B05MVyfGr8lmQWZVV25qQWpmbkE&usp=sharing