function [H,Hnorm,inv_Hnorm] = compute_homography(m,M);
%compute_homography
%
%[H,Hnorm,inv_Hnorm] = compute_homography(m,M)
%
%Computes the planar homography between the point coordinates on the plane (M) and the image
%point coordinates (m).
%
%INPUT: m: homogeneous coordinates in the image plane (3xN matrix)
% M: homogeneous coordinates in the plane in 3D (3xN matrix)
%
%OUTPUT: H: Homography matrix (3x3 homogeneous matrix)
% Hnorm: Normalization matrix used on the points before homography computation
% (useful for numerical stability is points in pixel coordinates)
% inv_Hnorm: The inverse of Hnorm
%
%Definition: m ~ H*M where "~" means equal up to a non zero scalar factor.
%
%Method: First computes an initial guess for the homography through quasi-linear method.
% Then, if the total number of points is larger than 4, optimize the solution by minimizing
% the reprojection error (in the least squares sense).
%
%
%Important functions called within that program:
%
%comp_distortion_oulu: Undistorts pixel coordinates.
%
%compute_homography.m: Computes the planar homography between points on the grid in 3D, and the image plane.
%
%project_points.m: Computes the 2D image projections of a set of 3D points, and also returns te Jacobian
% matrix (derivative with respect to the intrinsic and extrinsic parameters).
% This function is called within the minimization loop.
Np = size(m,2);
if size(m,1)<3,
m = [m;ones(1,Np)];
end;
if size(M,1)<3,
M = [M;ones(1,Np)];
end;
m = m ./ (ones(3,1)*m(3,:));
M = M ./ (ones(3,1)*M(3,:));
% Prenormalization of point coordinates (very important):
% (Affine normalization)
ax = m(1,:);
ay = m(2,:);
mxx = mean(ax);
myy = mean(ay);
ax = ax - mxx;
ay = ay - myy;
scxx = mean(abs(ax));
scyy = mean(abs(ay));
Hnorm = [1/scxx 0 -mxx/scxx;0 1/scyy -myy/scyy;0 0 1];
inv_Hnorm = [scxx 0 mxx ; 0 scyy myy; 0 0 1];
mn = Hnorm*m;
% Compute the homography between m and mn:
% Build the matrix:
L = zeros(2*Np,9);
L(1:2:2*Np,1:3) = M';
L(2:2:2*Np,4:6) = M';
L(1:2:2*Np,7:9) = -((ones(3,1)*mn(1,:)).* M)';
L(2:2:2*Np,7:9) = -((ones(3,1)*mn(2,:)).* M)';
if Np > 4,
L = L'*L;
end;
[U,S,V] = svd(L);
hh = V(:,9);
hh = hh/hh(9);
Hrem = reshape(hh,3,3)';
%Hrem = Hrem / Hrem(3,3);
% Final homography:
H = inv_Hnorm*Hrem;
if 0,
m2 = H*M;
m2 = [m2(1,:)./m2(3,:) ; m2(2,:)./m2(3,:)];
merr = m(1:2,:) - m2;
end;
%keyboard;
%%% Homography refinement if there are more than 4 points:
if Np > 4,
% Final refinement:
hhv = reshape(H',9,1);
hhv = hhv(1:8);
for iter=1:10,
mrep = H * M;
J = zeros(2*Np,8);
MMM = (M ./ (ones(3,1)*mrep(3,:)));
J(1:2:2*Np,1:3) = -MMM';
J(2:2:2*Np,4:6) = -MMM';
mrep = mrep ./ (ones(3,1)*mrep(3,:));
m_err = m(1:2,:) - mrep(1:2,:);
m_err = m_err(:);
MMM2 = (ones(3,1)*mrep(1,:)) .* MMM;
MMM3 = (ones(3,1)*mrep(2,:)) .* MMM;
J(1:2:2*Np,7:8) = MMM2(1:2,:)';
J(2:2:2*Np,7:8) = MMM3(1:2,:)';
MMM = (M ./ (ones(3,1)*mrep(3,:)))';
hh_innov = inv(J'*J)*J'*m_err;
hhv_up = hhv - hh_innov;
H_up = reshape([hhv_up;1],3,3)';
%norm(m_err)
%norm(hh_innov)
hhv = hhv_up;
H = H_up;
end;
end;
if 0,
m2 = H*M;
m2 = [m2(1,:)./m2(3,:) ; m2(2,:)./m2(3,:)];
merr = m(1:2,:) - m2;
end;
return;
%test of Jacobian
mrep = H*M;
mrep = mrep ./ (ones(3,1)*mrep(3,:));
m_err = mrep(1:2,:) - m(1:2,:);
figure(8);
plot(m_err(1,:),m_err(2,:),'r+');
std(m_err')