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 {
return fit_eval(x, &user); };
197 r0 = init_simplex.row(0);
198 R = opt_rad(r0, &user);
205bool Sphere::report_func(
int loop,
const VectorXf &fitpar,
double fval_lo,
double ,
double )
210 const VectorXf& r0 = fitpar;
212 std::cout <<
"loop: " << loop <<
"; r0: " << 1000*r0[0] <<
", r1: " << 1000*r0[1] <<
", r2: " << 1000*r0[2] <<
"; fval: " << fval_lo << std::endl;
219void Sphere::calculate_cm_ave_dist(
const MatrixXf &rr, VectorXf &cm,
float &avep)
221 cm = rr.colwise().mean();
222 MatrixXf diff = rr.rowwise() - cm.transpose();
223 avep = diff.rowwise().norm().mean();
228MatrixXf Sphere::make_initial_simplex(
const VectorXf &pars,
float size)
233 int npar = pars.size();
235 MatrixXf simplex = MatrixXf::Zero(npar+1,npar);
237 simplex.rowwise() += pars.transpose();
239 for (
int k = 1; k < npar+1; k++) {
240 simplex(k,k-1) += size;
248float Sphere::fit_eval(
const VectorXf &fitpar,
const void *user_data)
254 const FitUser* user =
static_cast<const FitUser*
>(user_data);
255 const VectorXf& r0 = fitpar;
259 MatrixXf diff = user->
rr.rowwise() - r0.transpose();
260 VectorXf one = diff.rowwise().norm();
262 float sum = one.sum();
263 float sum2 = one.dot(one);
265 F = sum2 - sum*sum/user->
rr.rows();
268 std::cout <<
"r0: " << 1000*r0[0] <<
", r1: " << 1000*r0[1] <<
", r2: " << 1000*r0[2] <<
"; R: " << 1000*sum/user->
rr.rows() <<
"; fval: "<<F<<std::endl;
275float Sphere::opt_rad(
const VectorXf &r0,
const FitUser* user)
277 MatrixXf diff = user->
rr.rowwise() - r0.transpose();
278 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)