Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Shashwat] Assignment submission #30

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions src/closest_rotation.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
#include "closest_rotation.h"
#include <Eigen/SVD>
#include <Eigen/LU>
#include <iostream>

void closest_rotation(
const Eigen::Matrix3d & M,
Eigen::Matrix3d & R)
{
// Replace with your code
R = Eigen::Matrix3d::Identity();
// // Replace with your code
// R = Eigen::Matrix3d::Identity();

// Compute the SVD of the matrix M
Eigen::MatrixXd M_Xd = M;
Eigen::JacobiSVD<Eigen::MatrixXd> svd(M, Eigen::ComputeThinU | Eigen::ComputeThinV);

// Compute the product of the left and right orthogonal matrices
Eigen::MatrixXd UVT = svd.matrixU()*svd.matrixV().transpose();
double detUVT = UVT.determinant();

Eigen::Matrix3d Omega;
Omega.resize(3,3);

// Populate the Omega matrix, as per notes
for (int ii = 0; ii < 3; ii++)
{
for (int jj = 0; jj < 3; jj++)
{
Omega(ii,jj) = 0.0;

if (ii == jj && ii != 2)
Omega(ii,jj) = 1.0;
if (ii == 2 && jj == 2)
Omega(ii,jj) = detUVT;
}
}

// Finally, compute the rotation matrix
R = svd.matrixU()*Omega*svd.matrixV().transpose();
// std::cout << R << std::endl;

return;

}
21 changes: 19 additions & 2 deletions src/hausdorff_lower_bound.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include "hausdorff_lower_bound.h"
#include "random_points_on_mesh.h"
#include "point_mesh_distance.h"
#include <iostream>

double hausdorff_lower_bound(
const Eigen::MatrixXd & VX,
Expand All @@ -7,6 +10,20 @@ double hausdorff_lower_bound(
const Eigen::MatrixXi & FY,
const int n)
{
// Replace with your code
return 0;
// Get the random sampling on X
Eigen::MatrixXd X;
random_points_on_mesh(n, VX, FX, X);

// Compute the set of closest points for all X samples
Eigen::VectorXd D;
Eigen::MatrixXd P, N;
point_mesh_distance(X, VY, FY, D, P, N);

// Now find the maximum of these distances. This is the required bound.
int i;
double H = D.maxCoeff(&i);
// std::cout << H << std::endl;

return H;

}
69 changes: 68 additions & 1 deletion src/icp_single_iteration.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#include "icp_single_iteration.h"
#include "random_points_on_mesh.h"
#include "hausdorff_lower_bound.h"
#include "point_mesh_distance.h"
#include "point_to_point_rigid_matching.h"
#include "point_to_plane_rigid_matching.h"
#include <iostream>

void icp_single_iteration(
const Eigen::MatrixXd & VX,
Expand All @@ -10,7 +16,68 @@ void icp_single_iteration(
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
// Replace with your code

// Set seed for random numbers
srand(1);

// Initial guesses
R = Eigen::Matrix3d::Identity();
t = Eigen::RowVector3d::Zero();

Eigen::MatrixXd VX_updated = VX;

// Define tolerance based on initial Haussdorf distance
double H = hausdorff_lower_bound(VX_updated, FX, VY, FY, num_samples);
double tol = 1.0e-3;

int iter = 0;
while (H > tol && iter < 10)
{
iter++;

H = hausdorff_lower_bound(VX_updated, FX, VY, FY, num_samples);
std::cout << "Haussdorf lower bound: " << H << " at iteration " << iter << std::endl;

// Sample the source mesh
Eigen::MatrixXd X;
random_points_on_mesh(num_samples, VX_updated, FX, X);

// Compute the set of closest points for all X samples
Eigen::VectorXd D;
Eigen::MatrixXd P, N;
point_mesh_distance(X, VY, FY, D, P, N);

if (method == ICP_METHOD_POINT_TO_POINT)
{
point_to_point_rigid_matching(X, P, R, t);

// Apply the updated transforms
for (int ii = 0; ii < VX_updated.rows(); ii++)
{
Eigen::MatrixXd temp1 = R*(VX_updated.row(ii).transpose()) + t.transpose();
VX_updated(ii,0) = temp1(0,0);
VX_updated(ii,1) = temp1(1,0);
VX_updated(ii,2) = temp1(2,0);
}

}
else
{
point_to_plane_rigid_matching(X, P, N, R, t);

// Apply the updated transforms
for (int ii = 0; ii < VX_updated.rows(); ii++)
{
Eigen::MatrixXd temp1 = R*(VX_updated.row(ii).transpose()) + t.transpose();
VX_updated(ii,0) = temp1(0,0);
VX_updated(ii,1) = temp1(1,0);
VX_updated(ii,2) = temp1(2,0);
}

}


}


}
68 changes: 63 additions & 5 deletions src/point_mesh_distance.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include "point_mesh_distance.h"
#include "point_triangle_distance.h"
#include <igl/per_face_normals.h>
#include <iostream>

void point_mesh_distance(
const Eigen::MatrixXd & X,
Expand All @@ -8,9 +11,64 @@ void point_mesh_distance(
Eigen::MatrixXd & P,
Eigen::MatrixXd & N)
{
// Replace with your code
P.resizeLike(X);
N = Eigen::MatrixXd::Zero(X.rows(),X.cols());
for(int i = 0;i<X.rows();i++) P.row(i) = VY.row(i%VY.rows());
D = (X-P).rowwise().norm();
// // Replace with your code
// P.resizeLike(X);
// N = Eigen::MatrixXd::Zero(X.rows(),X.cols());
// for(int i = 0;i<X.rows();i++) P.row(i) = VY.row(i%VY.rows());
// D = (X-P).rowwise().norm();

Eigen::RowVector3d a, b, c, p;
a.resize(3); b.resize(3); c.resize(3); p.resize(3);
double d;

P.resize(X.rows(),3);
N.resize(X.rows(),3);
D.resize(X.rows());

// Compute all face normals for later use
Eigen::MatrixXd allN;
igl::per_face_normals(VY, FY, Eigen::Vector3d(1,1,1).normalized(), allN);

// First, loop through each point in X
for (int ii = 0; ii < X.rows(); ii++)
{
// Extract the current x-point
Eigen::RowVector3d x; x(0) = X(ii,0); x(1) = X(ii,1); x(2) = X(ii,2);

// Now loop through all the triangles in Y and compute the point-to-triangle
// closest points. The smallest of these distances is the one we're after.
double x_min_dist = 1.0e10;

for (int jj = 0; jj < VY.rows(); jj++)
{
a(0) = VY(FY(jj,0),0); a(1) = VY(FY(jj,0),1); a(2) = VY(FY(jj,0),2);
b(0) = VY(FY(jj,1),0); a(1) = VY(FY(jj,1),1); a(2) = VY(FY(jj,1),2);
c(0) = VY(FY(jj,2),0); a(1) = VY(FY(jj,2),1); a(2) = VY(FY(jj,2),2);

point_triangle_distance(x, a, b, c, d, p);

if (d < x_min_dist)
{
x_min_dist = d;

// Pick this closest point to be *the* closest point
P(ii,0) = p(0);
P(ii,1) = p(1);
P(ii,2) = p(2);

// Pick the right normal that corresponds to this closest triangle
N(ii,0) = allN(jj,0);
N(ii,1) = allN(jj,1);
N(ii,2) = allN(jj,2);
}

}

D(ii) = x_min_dist;

}


return;

}
89 changes: 86 additions & 3 deletions src/point_to_plane_rigid_matching.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#include "point_to_plane_rigid_matching.h"
#include <igl/polar_svd.h>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/QR>
#include "closest_rotation.h"

void point_to_plane_rigid_matching(
const Eigen::MatrixXd & X,
Expand All @@ -7,7 +12,85 @@ void point_to_plane_rigid_matching(
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
// Replace with your code
R = Eigen::Matrix3d::Identity();
t = Eigen::RowVector3d::Zero();
// // Replace with your code
// R = Eigen::Matrix3d::Identity();
// t = Eigen::RowVector3d::Zero();

// Based on taking the derivative of the equation to be minimized in the notes,
// the only difference here should be factor of two in the numerator of the
// right-hand side...although this seems suspicious given that the vector of
// normals N would remain unused. But the matrix that contains those diagonal
// matrices is a constant w.r.t. the derivative with u, so it should just go
// outside of the derivative. And since that matrix cannot be 0, it can be
// ignored.

// Extract the columns of X and P
Eigen::MatrixXd A, X1, X2, X3, P1, P2, P3, diffVec, diffVec1, diffVec2, diffVec3, Ivec;
X1 = X.col(0);
X2 = X.col(1);
X3 = X.col(2);
P1 = P.col(0);
P2 = P.col(1);
P3 = P.col(2);

// Compute the vector Xi - Pi
diffVec1 = X1 - P1;
diffVec2 = X2 - P2;
diffVec3 = X3 - P3;

diffVec.resize(3*X.rows(), 1);
diffVec.block(0, 0, X.rows(), 1) = diffVec1;
diffVec.block(X.rows(), 0, X.rows(), 1) = diffVec2;
diffVec.block(2*X.rows(), 0, X.rows(), 1) = diffVec3;

// Create the big matrix A
Ivec.setOnes(X.rows(), 1);
A.resize(3*X.rows(), 3*X.cols()+3);
A.setZero(3*X.rows(), 3*X.cols()+3);

A.block(0, 1, X.rows(), 1) = X3;
A.block(X.rows(), 0, X.rows(), 1) = -X3;
A.block(2*X.rows(), 0, X.rows(), 1) = X2;
A.block(0, 2, X.rows(), 1) = -X2;
A.block(X.rows(), 2, X.rows(), 1) = X1;
A.block(2*X.rows(), 1, X.rows(), 1) = -X1;
A.block(0, 3, X.rows(), 1) = Ivec;
A.block(X.rows(), 4, X.rows(), 1) = Ivec;
A.block(2*X.rows(), 5, X.rows(), 1) = Ivec;

// Compute A^T*A
Eigen::MatrixXd bigA = A.transpose()*A;

// Compute the right hand side
Eigen::VectorXd b = -2.0*A.transpose()*diffVec;

// Solve the system
Eigen::ColPivHouseholderQR<Eigen::MatrixXd> QRsolver(bigA);
Eigen::VectorXd soln = QRsolver.solve(b);

double alpha = soln(0);
double beta = soln(1);
double gamma = soln(2);
t(0) = soln(3);
t(1) = soln(4);
t(2) = soln(5);

Eigen::Matrix3d M;

M(0,0) = 1.0;
M(1,1) = 1.0;
M(2,2) = 1.0;
M(0,1) = -gamma;
M(0,2) = beta;
M(1,0) = gamma;
M(2,0) = -beta;
M(1,2) = -alpha;
M(2,1) = alpha;

closest_rotation(M, R);


return;

}

Loading