Skip to content
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
2 changes: 1 addition & 1 deletion README.html
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ <h3 id="constantfunctionapproximation">Constant function approximation</h3>

<h3 id="linearfunctionapproximation">Linear function approximation</h3>

<p>If we make make a slightly more appropriate assuming that in the neighborhood
<p>If we make make a slightly more appropriate assumption that in the neighborhood
of the <span class="math">\(P_Y(\z₀)\)</span> the surface <span class="math">\(Y\)</span> is a plane, then we can improve this
approximation while keeping <span class="math">\(\f\)</span> linear in <span class="math">\(\z\)</span>:</p>

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ derived our gradients geometrically.

### Linear function approximation

If we make make a slightly more appropriate assuming that in the neighborhood
If we make make a slightly more appropriate assumption that in the neighborhood
of the $P_Y(\z₀)$ the surface $Y$ is a plane, then we can improve this
approximation while keeping $\f$ linear in $\z$:

Expand Down
25 changes: 20 additions & 5 deletions src/closest_rotation.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
#include "closest_rotation.h"
#include <Eigen/SVD>
#include <Eigen/Dense>
#include <iostream>

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

Eigen::JacobiSVD<Eigen::Matrix3d> svd(M, Eigen::ComputeThinV | Eigen::ComputeThinU);
Eigen::Matrix3d U = svd.matrixU();
Eigen::Matrix3d V = svd.matrixV();
Eigen::Matrix3d VT = V.transpose();
double d = (U * VT).determinant();
// std::cout << d << std::endl

Eigen::Matrix3d O;
O << 1, 0, 0,
0, 1, 0,
0, 0, d;

R = U * O * VT;

}
22 changes: 14 additions & 8 deletions src/hausdorff_lower_bound.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#include "hausdorff_lower_bound.h"
#include "random_points_on_mesh.h"
#include "point_mesh_distance.h"

double hausdorff_lower_bound(
const Eigen::MatrixXd & VX,
const Eigen::MatrixXi & FX,
const Eigen::MatrixXd & VY,
const Eigen::MatrixXi & FY,
const int n)
{
// Replace with your code
return 0;
const Eigen::MatrixXd &VX,
const Eigen::MatrixXi &FX,
const Eigen::MatrixXd &VY,
const Eigen::MatrixXi &FY,
const int n) {

Eigen::VectorXd D;
Eigen::MatrixXd X, P, N;
random_points_on_mesh(n, VX, FX, X);

point_mesh_distance(X, VY, FY, D, P, N);
return D.maxCoeff();
}
50 changes: 38 additions & 12 deletions src/icp_single_iteration.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
#include "icp_single_iteration.h"
#include "random_points_on_mesh.h"
#include "point_to_plane_rigid_matching.h"
#include "point_to_point_rigid_matching.h"
#include "point_mesh_distance.h"

void icp_single_iteration(
const Eigen::MatrixXd & VX,
const Eigen::MatrixXi & FX,
const Eigen::MatrixXd & VY,
const Eigen::MatrixXi & FY,
const int num_samples,
const ICPMethod method,
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
// Replace with your code
R = Eigen::Matrix3d::Identity();
t = Eigen::RowVector3d::Zero();
const Eigen::MatrixXd &VX,
const Eigen::MatrixXi &FX,
const Eigen::MatrixXd &VY,
const Eigen::MatrixXi &FY,
const int num_samples,
const ICPMethod method,
Eigen::Matrix3d &R,
Eigen::RowVector3d &t) {

/*
* Algorithm:
X ← sample source mesh (V_X,F_X)
P0 ← project all X onto target mesh (V_Y,F_Y)
R,t ← update rigid transform to best match X and P0
V_X ← rigidly transform original source mesh by R and t
*/

Eigen::MatrixXd X, P, N;
Eigen::VectorXd D;
random_points_on_mesh(num_samples, VX, FX, X);
point_mesh_distance(X, VY, FY, D, P, N);

switch (method) {
case ICPMethod::ICP_METHOD_POINT_TO_PLANE:
point_to_plane_rigid_matching(X, P, N, R, t);
break;
case ICPMethod::ICP_METHOD_POINT_TO_POINT:
point_to_point_rigid_matching(X, P, R, t);
break;
default:
assert(true);
}


}
60 changes: 48 additions & 12 deletions src/point_mesh_distance.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,52 @@
#include "point_mesh_distance.h"
#include "point_triangle_distance.h"
#include <iostream>
#include <igl/per_face_normals.h>

void point_mesh_distance(
const Eigen::MatrixXd & X,
const Eigen::MatrixXd & VY,
const Eigen::MatrixXi & FY,
Eigen::VectorXd & D,
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();
const Eigen::MatrixXd &X,
const Eigen::MatrixXd &VY,
const Eigen::MatrixXi &FY,
Eigen::VectorXd &D,
Eigen::MatrixXd &P,
Eigen::MatrixXd &N) {

P.resizeLike(X);
D.resize(P.rows(), 1);
N.resize(X.rows(), X.cols());

//computing the normals
Eigen::MatrixXd NY;
igl::per_face_normals(VY, FY, NY);

for (int i = 0; i < X.rows(); i++) {

// min_p and min_d for a given point x_i
Eigen::RowVector3d min_p, min_n;
double min_d = MAXFLOAT;

//let's find the minimum for Y for a given x
for (int j = 0; j < FY.rows(); j++) {
Eigen::RowVector3d p;
double d;

point_triangle_distance(X.row(i),
VY.row(FY(j, 0)), //a
VY.row(FY(j, 1)), //b
VY.row(FY(j, 2)), //c
d, p);

if (d < min_d) {
min_p = p;
min_d = d;
min_n = NY.row(j);
}
}
///--
P.row(i) = min_p;
D(i) = min_d;
N.row(i) = min_n;

}

}
70 changes: 61 additions & 9 deletions src/point_to_plane_rigid_matching.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,65 @@
#include "point_to_plane_rigid_matching.h"
#include "closest_rotation.h"
#include <Eigen/Dense>

void createA(const Eigen::MatrixXd &X, Eigen::MatrixXd &A) {
Eigen::VectorXd zero = Eigen::VectorXd::Zero(X.rows());
Eigen::VectorXd one = Eigen::VectorXd::Ones(X.rows());
//-
Eigen::VectorXd X_1 = X.col(1);
Eigen::VectorXd X_2 = X.col(2);
Eigen::VectorXd X_0 = X.col(0);

A << zero, X_2, -X_1, one, zero, zero,
-X_2, zero, X_0, zero, one, zero,
X_1, -X_0, zero, zero, zero, one;
}

Eigen::MatrixXd diagN(const Eigen::MatrixXd &N, int idx) {
return N.col(idx).asDiagonal();
}

void point_to_plane_rigid_matching(
const Eigen::MatrixXd & X,
const Eigen::MatrixXd & P,
const Eigen::MatrixXd & N,
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
// Replace with your code
R = Eigen::Matrix3d::Identity();
t = Eigen::RowVector3d::Zero();
const Eigen::MatrixXd &X,
const Eigen::MatrixXd &P,
const Eigen::MatrixXd &N,
Eigen::Matrix3d &R,
Eigen::RowVector3d &t) {

Eigen::MatrixXd A(3 * X.rows(), 6);
Eigen::MatrixXd d_N(X.rows(), 3 * X.rows());

//Creating A, diagonal_N and X-P
createA(X, A);
d_N << diagN(N, 0), diagN(N, 1), diagN(N, 2);
Eigen::MatrixXd XP = X - P;

Eigen::VectorXd B = Eigen::VectorXd::Zero(X.rows() * 3);
B << (X - P).col(0), (X - P).col(1), (X - P).col(2);

//Solving the equation (52) in Readme.
A = d_N * A;
B = d_N * B;

//need to be defined dynamically so that JacobiSVD works.
Eigen::VectorXd u;


u = (A.transpose() * A).inverse() * (-A.transpose() * B);

double alpha = u[0];
double beta = u[1];
double gamma = u[2];

Eigen::Matrix3d M = Eigen::MatrixXd::Identity(3, 3);
Eigen::Matrix3d buff;
buff << 0, -gamma, beta,
gamma, 0, -alpha,
-beta, alpha, 0;

M = M - buff;
closest_rotation(M, R);
t << u(3), u(4), u(5);


}
23 changes: 15 additions & 8 deletions src/point_to_point_rigid_matching.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
#include "point_to_point_rigid_matching.h"
#include <igl/polar_svd.h>
#include "closest_rotation.h"

void point_to_point_rigid_matching(
const Eigen::MatrixXd & X,
const Eigen::MatrixXd & P,
Eigen::Matrix3d & R,
Eigen::RowVector3d & t)
{
// Replace with your code
R = Eigen::Matrix3d::Identity();
t = Eigen::RowVector3d::Zero();
const Eigen::MatrixXd &X,
const Eigen::MatrixXd &P,
Eigen::Matrix3d &R,
Eigen::RowVector3d &t) {
//
//Shift to the origin
Eigen::MatrixXd X_ = X.rowwise() - X.colwise().mean();
Eigen::MatrixXd P_ = P.rowwise() - P.colwise().mean();

Eigen::MatrixXd M = (P_.transpose() * X_).transpose();
closest_rotation(M, R);
//compute t
t = P.colwise().mean().transpose() - R * X.colwise().mean().transpose();

}

Loading