65 const VectorXf& x = points.col(0);
66 const VectorXf& y = points.col(1);
67 const VectorXf& z = points.col(2);
69 VectorXf point_means = points.colwise().mean();
71 VectorXf x_mean_free = x.array() - point_means(0);
72 VectorXf y_mean_free = y.array() - point_means(1);
73 VectorXf z_mean_free = z.array() - point_means(2);
76 A << (x.cwiseProduct(x_mean_free)).mean(), 2 * (x.cwiseProduct(y_mean_free)).mean(), 2 * (x.cwiseProduct(z_mean_free)).mean(),
77 0, (y.cwiseProduct(y_mean_free)).mean(), 2 * (y.cwiseProduct(z_mean_free)).mean(),
78 0, 0, (z.cwiseProduct(z_mean_free)).mean();
80 Matrix3f A_T = A.transpose();
84 VectorXf sq_sum = x.array().pow(2) + y.array().pow(2) + z.array().pow(2);
85 b << (sq_sum.cwiseProduct(x_mean_free)).mean(),
86 (sq_sum.cwiseProduct(y_mean_free)).mean(),
87 (sq_sum.cwiseProduct(z_mean_free)).mean();
89 Vector3f
center = A.ldlt().solve(b);
91 MatrixX3f tmp(points.rows(), 3);
92 tmp.col(0) = x.array() -
center(0);
93 tmp.col(1) = y.array() -
center(1);
94 tmp.col(2) = z.array() -
center(2);
96 float r = sqrt(tmp.array().pow(2).rowwise().sum().mean());
111 return Sphere(Vector3f(), 0.0f);
118 MatrixXf rr_eigen(np, 3);
119 VectorXf r0_eigen(3);
121 MatrixX3f dig_rr_eigen;
122 for (
int k = 0; k < np; k++) {
123 rr_eigen(k, 0) = rr[k][0];
124 rr_eigen(k, 1) = rr[k][1];
125 rr_eigen(k, 2) = rr[k][2];
128 if (rr_eigen.rows() < 0) {
129 std::cout <<
"Sphere::fit_sphere_to_points - No points were passed." << std::endl;
158 int report_interval = -1;
160 MatrixXf init_simplex;
161 VectorXf init_vals(4);
168 calculate_cm_ave_dist(rr, cm, R0);
170 init_simplex = make_initial_simplex(cm, simplex_size);
174 for (
int k = 0; k < 4; k++) {
175 init_vals[k] = fit_eval(
static_cast<VectorXf
>(init_simplex.row(k)), &user);
181 auto cost = [&user](
const VectorXf& x) ->
float {
182 return fit_eval(x, &user);
199 r0 = init_simplex.row(0);
200 R = opt_rad(r0, &user);
207bool Sphere::report_func(
int loop,
const VectorXf& fitpar,
double fval_lo,
double ,
double )
212 const VectorXf& r0 = fitpar;
214 std::cout <<
"loop: " << loop <<
"; r0: " << 1000 * r0[0] <<
", r1: " << 1000 * r0[1] <<
", r2: " << 1000 * r0[2] <<
"; fval: " << fval_lo << std::endl;
221void Sphere::calculate_cm_ave_dist(
const MatrixXf& rr, VectorXf& cm,
float& avep)
223 cm = rr.colwise().mean();
224 MatrixXf diff = rr.rowwise() - cm.transpose();
225 avep = diff.rowwise().norm().mean();
230MatrixXf Sphere::make_initial_simplex(
const VectorXf& pars,
float size)
235 int npar = pars.size();
237 MatrixXf simplex = MatrixXf::Zero(npar + 1, npar);
239 simplex.rowwise() += pars.transpose();
241 for (
int k = 1; k < npar + 1; k++) {
242 simplex(k, k - 1) += size;
250float Sphere::fit_eval(
const VectorXf& fitpar,
const void* user_data)
256 const FitUser* user =
static_cast<const FitUser*
>(user_data);
257 const VectorXf& r0 = fitpar;
261 MatrixXf diff = user->
rr.rowwise() - r0.transpose();
262 VectorXf one = diff.rowwise().norm();
264 float sum = one.sum();
265 float sum2 = one.dot(one);
267 F = sum2 - sum * sum / user->
rr.rows();
270 std::cout <<
"r0: " << 1000 * r0[0] <<
", r1: " << 1000 * r0[1] <<
", r2: " << 1000 * r0[2] <<
"; R: " << 1000 * sum / user->
rr.rows() <<
"; fval: " << F << std::endl;
277float Sphere::opt_rad(
const VectorXf& r0,
const FitUser* user)
279 MatrixXf diff = user->
rr.rowwise() - r0.transpose();
280 return diff.rowwise().norm().mean();
Best-fit sphere from a 3-D point cloud with closed-form and Nelder–Mead solvers.
Header-only Nelder–Mead simplex minimiser with pluggable cost and report callables.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
static bool simplex_minimize(Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &p, Eigen::Matrix< T, Eigen::Dynamic, 1 > &y, T ftol, T stol, CostFunc &&func, int max_eval, int &neval, int report, ReportFunc &&report_func)
Cost-function workspace for Sphere::fit_sphere_simplex: holds the nx3 point cloud and a verbose-repor...
static bool fit_sphere_to_points(const Eigen::MatrixXf &rr, float simplex_size, Eigen::VectorXf &r0, float &R)
static Sphere fit_sphere_simplex(const Eigen::MatrixX3f &points, double simplex_size=2e-2)
Eigen::Vector3f & center()
static Sphere fit_sphere(const Eigen::MatrixX3f &points)
Sphere(const Eigen::Vector3f ¢er, float radius)