diff --git a/README.html b/README.html
index 6c13281..c163d77 100644
--- a/README.html
+++ b/README.html
@@ -343,7 +343,7 @@
Constant function approximation
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\):
diff --git a/README.md b/README.md
index bce5dc2..ce58753 100644
--- a/README.md
+++ b/README.md
@@ -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$:
diff --git a/src/closest_rotation.cpp b/src/closest_rotation.cpp
index 54403c1..40040c8 100644
--- a/src/closest_rotation.cpp
+++ b/src/closest_rotation.cpp
@@ -1,9 +1,16 @@
#include "closest_rotation.h"
+#include
+#include
void closest_rotation(
- const Eigen::Matrix3d & M,
- Eigen::Matrix3d & R)
+ const Eigen::Matrix3d & M,
+ Eigen::Matrix3d & R)
{
- // Replace with your code
- R = Eigen::Matrix3d::Identity();
+ Eigen::JacobiSVD svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Eigen::MatrixXd U = svd.matrixU();
+ Eigen::MatrixXd V = svd.matrixV();
+ Eigen::Matrix3d Omega(3, 3);
+ double det = (U * V.transpose()).determinant();
+ Omega << 1, 0, 0, 0, 1, 0, 0, 0, det;
+ R = U * Omega * V.transpose();
}
diff --git a/src/hausdorff_lower_bound.cpp b/src/hausdorff_lower_bound.cpp
index 8608964..3536d7c 100644
--- a/src/hausdorff_lower_bound.cpp
+++ b/src/hausdorff_lower_bound.cpp
@@ -1,12 +1,22 @@
#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)
+ 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;
+ // random choose points
+ Eigen::MatrixXd X;
+ random_points_on_mesh(n, VX, FX, X);
+
+ // compute point to mesh distance
+ Eigen::VectorXd D;
+ Eigen::MatrixXd P, N;
+ point_mesh_distance(X, VY, FY, D, P, N);
+
+ return D.maxCoeff();
}
diff --git a/src/icp_single_iteration.cpp b/src/icp_single_iteration.cpp
index 1e8fda9..8c565bb 100644
--- a/src/icp_single_iteration.cpp
+++ b/src/icp_single_iteration.cpp
@@ -1,16 +1,29 @@
#include "icp_single_iteration.h"
+#include "random_points_on_mesh.h"
+#include "point_mesh_distance.h"
+#include "point_to_point_rigid_matching.h"
+#include "point_to_plane_rigid_matching.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)
+ 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();
+ Eigen::MatrixXd X;
+ random_points_on_mesh(num_samples, VX, FX, X);
+
+ 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);
+ } else if (method == ICP_METHOD_POINT_TO_PLANE) {
+ point_to_plane_rigid_matching(X, P, N, R, t);
+ }
}
diff --git a/src/point_mesh_distance.cpp b/src/point_mesh_distance.cpp
index 2e6a070..9841eab 100644
--- a/src/point_mesh_distance.cpp
+++ b/src/point_mesh_distance.cpp
@@ -1,16 +1,43 @@
#include "point_mesh_distance.h"
+#include "point_triangle_distance.h"
+#include
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)
+ 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
void point_to_plane_rigid_matching(
- const Eigen::MatrixXd & X,
- const Eigen::MatrixXd & P,
- const Eigen::MatrixXd & N,
- Eigen::Matrix3d & R,
- Eigen::RowVector3d & t)
+ 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();
+ // compute [diag(N0), diag(N1), diag(N2)]
+ Eigen::MatrixXd normal(X.rows(), 3*X.rows());
+ Eigen::MatrixXd N0 = N.col(0).asDiagonal();
+ Eigen::MatrixXd N1 = N.col(1).asDiagonal();
+ Eigen::MatrixXd N2 = N.col(2).asDiagonal();
+ normal << N0, N1, N2;
+ // compute A
+ Eigen::RowVectorXd zero = Eigen::RowVectorXd::Zero(X.rows());
+ Eigen::RowVectorXd ones = Eigen::RowVectorXd::Ones(X.rows());
+ Eigen::MatrixXd A(3*X.rows(), 6);
+ A << zero, X.col(2), -X.col(1), ones, zero, zero,
+ -X.col(2), 0, X.col(0), zero, ones, zero,
+ X.col(1), -X.col(0), zero, zero, zero, ones;
+ // compute X - P
+ Eigen::MatrixXd xp(3*X.rows(), 3);
+ xp << X.col(0) - P.col(0), X.col(1) - P.col(1), X.col(2) - P.col(2);
+ // compute u
+ A = normal * A;
+ xp = normal * xp;
+ Eigen::RowVectorXd u;
+ // u = [alpha, beta, gamma, t0, t1, t2]
+ u = (A.transpose() * A).inverse() * -A.transpose() * xp;
+ // get t
+ t << u(3), u(4), u(5);
+ // compute M and R
+ Eigen::Matrix3d M;
+ M << 1, -u(2), u(1), u(2), 1, -u(0), -u(1), u(0), 1;
+ closest_rotation(M, R);
}
diff --git a/src/point_to_point_rigid_matching.cpp b/src/point_to_point_rigid_matching.cpp
index 079151f..4523e72 100644
--- a/src/point_to_point_rigid_matching.cpp
+++ b/src/point_to_point_rigid_matching.cpp
@@ -1,14 +1,22 @@
#include "point_to_point_rigid_matching.h"
-#include
+#include "closest_rotation.h"
void point_to_point_rigid_matching(
- const Eigen::MatrixXd & X,
- const Eigen::MatrixXd & P,
- Eigen::Matrix3d & R,
- Eigen::RowVector3d & t)
+ 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();
+ // closed form
+ Eigen::RowVector3d x = X.colwise().mean();
+ Eigen::RowVector3d p = P.colwise().mean();
+ Eigen::MatrixXd x_bar = X.rowwise() - x;
+ Eigen::MatrixXd p_bar = P.rowwise() - p;
+
+ Eigen::Matrix3d M = p_bar.transpose() * x_bar;
+ closest_rotation(M, R);
+
+ // p - (R * x^T)^T = p - x * R^T
+ t = p - x * R.transpose();
}
diff --git a/src/point_triangle_distance.cpp b/src/point_triangle_distance.cpp
index 6405100..72869a0 100644
--- a/src/point_triangle_distance.cpp
+++ b/src/point_triangle_distance.cpp
@@ -1,14 +1,49 @@
#include "point_triangle_distance.h"
+#include
void point_triangle_distance(
- const Eigen::RowVector3d & x,
- const Eigen::RowVector3d & a,
- const Eigen::RowVector3d & b,
- const Eigen::RowVector3d & c,
- double & d,
- Eigen::RowVector3d & p)
+ const Eigen::RowVector3d & x,
+ const Eigen::RowVector3d & a,
+ const Eigen::RowVector3d & b,
+ const Eigen::RowVector3d & c,
+ double & d,
+ Eigen::RowVector3d & p)
{
- // Replace with your code
- d = 0;
- p = a;
+ // calculate normal vector
+ Eigen::RowVector3d normal = (a - b).cross(a - c);
+ normal.normalize();
+
+ // project x on to triangle plane
+ Eigen::RowVector3d px = (x - a).dot(normal) * normal + x;
+
+ /*
+ 1 |6 / 3
+ --A-C---
+ 4 |/ 5
+ B
+ /|
+ /2| */
+ // if following value is positive, then px is in the triangle side of edge
+ double in_ab = (a - px).cross(a - b).dot(normal);
+ double in_bc = (b - px).cross(b - c).dot(normal);
+ double in_ca = (c - px).cross(c - a).dot(normal);
+
+ // find p
+ if (in_ab >= 0 && in_bc >= 0 && in_ca >= 0) {
+ p = px; // inside
+ } else if (in_ab < 0 && !in_ca < 0) {
+ p = a; // case 1
+ } else if (in_ab < 0 && in_bc < 0) {
+ p = b; // case 2
+ } else if (in_bc < 0 && in_ca < 0) {
+ p = c; // case 3
+ } else if (in_ab < 0) {
+ p = (a - px).dot(a - b) * (a - b) + a; // case 4
+ } else if (in_bc < 0) {
+ p = (b - px).dot(b - c) * (b - c) + b; // case 5
+ } else if (in_ca < 0) {
+ p = (c - px).dot(c - a) * (c - a) + c; // case 6
+ }
+
+ d = (x - p).norm();
}
diff --git a/src/random_points_on_mesh.cpp b/src/random_points_on_mesh.cpp
index 6e85d75..e820282 100644
--- a/src/random_points_on_mesh.cpp
+++ b/src/random_points_on_mesh.cpp
@@ -1,13 +1,58 @@
#include "random_points_on_mesh.h"
+#include
+#include
+
+
+int binary_find(Eigen::VectorXd lst, double val) {
+ int idx = 0;
+ if (lst.rows() <= 1) return idx;
+
+ int mid = lst.rows()/2;
+ if (lst(mid) < val) {
+ idx = mid + binary_find(lst.segment(mid, lst.rows()), val);
+ } else {
+ idx = binary_find(lst.head(mid), val);
+ }
+ return idx;
+}
+
void random_points_on_mesh(
- const int n,
- const Eigen::MatrixXd & V,
- const Eigen::MatrixXi & F,
- Eigen::MatrixXd & X)
+ const int n,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ Eigen::MatrixXd & X)
{
- // REPLACE WITH YOUR CODE:
- X.resize(n,3);
- for(int i = 0;i dis(0.0, 1.0);
+
+ X.resize(n, 3);
+ for (int i = 0; i < X.rows(); i++) {
+ // find random index idx
+ double gamma = dis(gen);
+ int idx = binary_find(csum, gamma);
+
+ // generate and configurate alpha, beta
+ double alpha = dis(gen);
+ double beta = dis(gen);
+ if (alpha + beta > 1) {
+ alpha = 1 - alpha;
+ beta = 1 - beta;
+ }
+
+ Eigen::VectorXd v1 = V.row(F(idx, 0));
+ Eigen::VectorXd v2 = V.row(F(idx, 1));
+ Eigen::VectorXd v3 = V.row(F(idx, 2));
+
+ X.row(i) = v1 + alpha * (v2 - v1) + beta * (v3 - v1);
+ }
+}