53#include <Eigen/Geometry>
55#define _USE_MATH_DEFINES
107 Eigen::Vector3f& scales)
110 using FidMatrix = Eigen::Matrix<float, 3, 3, Eigen::RowMajor>;
111 FidMatrix head_fid, mri_fid;
112 bool head_fid_found[3] = {
false,
false,
false};
113 bool mri_fid_found[3] = {
false,
false,
false};
116 float nasion_weight = 5.0;
118 for (j = 0; j < 2; j++) {
120 FidMatrix& fid = (j == 0) ? head_fid : mri_fid;
121 bool* found = (j == 0) ? head_fid_found : mri_fid_found;
123 for (k = 0; k < d.
npoint; k++) {
127 fid.row(0) = Eigen::Map<const Eigen::RowVector3f>(d.
points[k].r);
131 fid.row(1) = Eigen::Map<const Eigen::RowVector3f>(d.
points[k].r);
135 fid.row(2) = Eigen::Map<const Eigen::RowVector3f>(d.
points[k].r);
142 for (k = 0; k < 3; k++) {
143 if (!head_fid_found[k]) {
144 qCritical(
"Some of the MEG fiducials were missing");
148 if (!mri_fid_found[k]) {
149 qCritical(
"Some of the MRI fiducials were missing");
156 qInfo(
"xscale = %.3f yscale = %.3f zscale = %.3f\n",scales[0],scales[1],scales[2]);
158 for (j = 0; j < 3; j++)
159 for (k = 0; k < 3; k++)
160 mri_fid(j,k) = mri_fid(j,k)*scales[k];
167 mri_fid.row(0).data(),mri_fid.row(1).data(),mri_fid.row(2).data()));
173 for (k = 0; k < head_dig.
nfids(); k++)
174 Eigen::Map<Eigen::Vector3f>(head_dig.
mri_fids[k].r) = mri_fid.row(k).transpose();
176 qInfo(
"After simple alignment : \n");
183 for (k = 0; k < niter; k++) {
184 if (
iterate_alignment_once(head_dig,nasion_weight,Eigen::Vector3f(mri_fid.row(1).transpose()),k == niter-1 && niter > 1) ==
FAIL)
188 qInfo(
"%d / %d iterations done. RMS dist = %7.1f mm\n",k,niter,
190 qInfo(
"After refinement :\n");
201 const Eigen::Matrix<float, 3, 3, Eigen::RowMajor>& mri_fid,
202 Eigen::Vector3f& scales)
205 float simplex_size = 2e-2;
206 Eigen::VectorXf r0(3);
209 scales[0] = scales[1] = scales[2] = 1.0;
211 Eigen::MatrixXf dig_rr(dig.
npoint, 3);
212 Eigen::MatrixXf head_rr(
np, 3);
215 for (k = 0, ndig = 0; k < dig.
npoint; k++) {
216 if (dig.
points[k].r[2] > 0) {
217 dig_rr.row(ndig++) = Eigen::Map<const Eigen::RowVector3f>(dig.
points[k].r);
225 qInfo(
"Polhemus : (%.1f %.1f %.1f) mm R = %.1f mm\n",1000*r0[0],1000*r0[1],1000*r0[2],1000*Rdig);
228 Eigen::Vector3f LR = mri_fid.row(2).transpose() - mri_fid.row(0).transpose();
229 Eigen::Vector3f LN = mri_fid.row(1).transpose() - mri_fid.row(0).transpose();
230 Eigen::Vector3f norm = LR.cross(LN);
233 for (k = 0, nhead = 0; k <
np; k++) {
234 Eigen::Vector3f diff_vec =
rr.row(k).transpose() - mri_fid.row(0).transpose();
235 if (diff_vec.dot(norm) > 0) {
236 head_rr.row(nhead++) =
rr.row(k);
244 qInfo(
"Scalp : (%.1f %.1f %.1f) mm R = %.1f mm\n",1000*r0[0],1000*r0[1],1000*r0[2],1000*Rscalp);
246 scales[0] = scales[1] = scales[2] = Rdig/Rscalp;
260 d.dist_valid =
false;
262 for (k = 0; k < d.npoint; k++) {
267 if (std::fabs(d.dist(k)) > maxdist &&
274 qInfo(
"%d points discarded (maxdist = %6.1f mm).\n",discarded,1000*maxdist);
282 bool do_all,
bool do_approx)
const
289 Q_ASSERT(dig.head_mri_t);
290 const FiffCoordTrans& t = (dig.head_mri_t_adj && !dig.head_mri_t_adj->isEmpty()) ? *dig.head_mri_t_adj : *dig.head_mri_t;
298 dig.dist.conservativeResize(dig.npoint);
299 if (dig.closest.size() == 0) {
303 dig.closest = Eigen::VectorXi::Constant(dig.npoint, -1);
306 dig.closest_point.setZero(dig.npoint,3);
307 Eigen::VectorXi closest(dig.npoint);
308 Eigen::VectorXf dists(dig.npoint);
310 for (k = 0, nactive = 0; k < dig.npoint; k++) {
311 if ((dig.active[k] && !dig.discard[k]) || do_all) {
312 point = dig.points.at(k);
313 rr.row(nactive) = Eigen::Map<const Eigen::RowVector3f>(
point.r);
316 closest[nactive] = dig.closest(k);
317 if (closest[nactive] < 0)
321 closest[nactive] = -1;
331 qInfo(
"Inside or outside for %d points...",nactive);
332 for (k = 0, nactive = 0; k < dig.npoint; k++) {
333 if ((dig.active[k] && !dig.discard[k]) || do_all) {
334 dig.dist(k) = dists[nactive];
335 dig.closest(k) = closest[nactive];
337 Eigen::Vector3f pt = Eigen::Map<const Eigen::Vector3f>(
rr.row(nactive).data());
339 dig.closest_point.row(k) = proj.transpose();
345 if (!do_approx &&
false) {
346 Eigen::Vector3f pt = Eigen::Map<const Eigen::Vector3f>(
rr.row(nactive).data());
348 dig.dist(k) = - std::fabs(dig.dist(k));
350 dig.dist(k) = std::fabs(dig.dist(k));
359 dig.dist_valid =
true;
368 const std::optional<Eigen::Vector3f>& nasion_mri,
374 Eigen::MatrixXf rr_head(dig.npoint, 3);
375 Eigen::MatrixXf rr_mri(dig.npoint, 3);
376 Eigen::VectorXf w = Eigen::VectorXf::Zero(dig.npoint);
380 float max_diff = 40e-3;
382 if (!dig.head_mri_t_adj) {
383 qCritical()<<
"Not adjusting the transformation";
391 for (k = 0, nactive = 0; k < dig.npoint; k++) {
392 if (dig.active[k] && !dig.discard[k]) {
393 point = dig.points.at(k);
394 rr_head.row(nactive) = Eigen::Map<const Eigen::RowVector3f>(
point.r);
395 rr_mri.row(nactive) = dig.closest_point.row(k);
401 w[nactive] = nasion_weight;
403 rr_mri.row(nactive) = nasion_mri->transpose();
404 rr_head.row(nactive) = nasion_mri->transpose();
405 Q_ASSERT(dig.head_mri_t || dig.head_mri_t_adj);
407 dig.head_mri_t_adj ? *dig.head_mri_t_adj : *dig.head_mri_t,
417 qCritical() <<
"Not enough points to do the alignment";
421 rr_head.topRows(nactive),
422 rr_mri.topRows(nactive),
424 max_diff)).isEmpty())
427 if (dig.head_mri_t_adj)
428 dig.head_mri_t_adj = std::make_unique<FiffCoordTrans>(t);
432 dig.dist_valid =
false;
446 for (k = 0, rms = 0.0, nactive = 0; k < dig.
npoint; k++)
448 rms = rms + dig.
dist(k)*dig.
dist(k);
452 rms = rms/(nactive-1);
465 for (k = 0; k < 3; k++) {
469 for (j = 0; j <
np; j++)
470 for (k = 0; k < 3; k++)
471 rr(j,k) =
rr(j,k)*scales[k];
479 Eigen::Vector3f mn =
rr.row(0).transpose();
480 Eigen::Vector3f mx = mn;
482 for (
int k = 1; k <
np; k++) {
483 Eigen::Vector3f r =
rr.row(k).transpose();
489 qInfo(
"%s:\n",tag.toUtf8().constData());
490 qInfo(
"\tx = %f ... %f mm\n",1000*mn[0],1000*mx[0]);
491 qInfo(
"\ty = %f ... %f mm\n",1000*mn[1],1000*mx[1]);
492 qInfo(
"\tz = %f ... %f mm\n",1000*mn[2],1000*mx[2]);
495 fov = std::max(mn.cwiseAbs().maxCoeff(), mx.cwiseAbs().maxCoeff());
506 if (name.startsWith(
"inflated") || name.startsWith(
"sphere") || name.startsWith(
"white"))
521 const int totalSize = ncolor *
np;
526 float curv_sum = 0.0f;
528 for (
int k = 0; k <
np; k++) {
529 const int base = k * ncolor;
530 curv_sum += std::fabs(
curv[k]);
532 for (
int j = 0; j < 3; j++)
539 for (
int k = 0; k <
np; k++) {
540 const int base = k * ncolor;
541 curv_sum += std::fabs(
curv[k]);
542 for (
int j = 0; j < 3; j++)
549 qInfo(
"Average curvature : %f\n",curv_sum/
np);
Sphere class declaration.
FiffDigitizerData class declaration.
FiffCoordTrans class declaration.
FiffStream class declaration.
#define FIFFV_POINT_CARDINAL
#define FIFFV_POINT_NASION
FiffDigPoint class declaration.
constexpr float NEG_CURV_COLOR
constexpr int SHOW_CURVATURE_OVERLAY
constexpr float POS_CURV_COLOR
constexpr int SHOW_CURVATURE_NONE
constexpr int SHOW_OVERLAY_HEAT
constexpr float EVEN_CURV_COLOR
MNEMorphMap class declaration.
MNEMshColorScaleDef class declaration.
MNEMshDisplaySurface class declaration.
MNEMshPicked class declaration.
MNESurface class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Coordinate transformation description.
static FiffCoordTrans fromCardinalPoints(int from, int to, const float *rL, const float *rN, const float *rR)
Digitization point description.
Digitization points container and description.
QList< FIFFLIB::FiffDigPoint > points
std::unique_ptr< FiffCoordTrans > head_mri_t_adj
QList< FIFFLIB::FiffDigPoint > mri_fids
void pickCardinalFiducials()
static bool fit_sphere_to_points(const Eigen::MatrixXf &rr, float simplex_size, Eigen::VectorXf &r0, float &R)
void get_head_scale(FIFFLIB::FiffDigitizerData &dig, const Eigen::Matrix< float, 3, 3, Eigen::RowMajor > &mri_fid, Eigen::Vector3f &scales)
float rms_digitizer_distance(FIFFLIB::FiffDigitizerData &dig) const
void decide_surface_extent(const QString &tag)
mneUserFreeFunc user_data_free
void scale(const Eigen::Vector3f &scales)
void calculate_digitizer_distances(FIFFLIB::FiffDigitizerData &dig, bool do_all, bool do_approx) const
int align_fiducials(FIFFLIB::FiffDigitizerData &head_dig, const FIFFLIB::FiffDigitizerData &mri_dig, int niter, int scale_head, float omit_dist, Eigen::Vector3f &scales)
void setup_curvature_colors()
Eigen::VectorXf vertex_colors
int discard_outlier_digitizer_points(FIFFLIB::FiffDigitizerData &d, float maxdist) const
int iterate_alignment_once(FIFFLIB::FiffDigitizerData &dig, int nasion_weight, const std::optional< Eigen::Vector3f > &nasion_mri, int last_step) const
void decide_curv_display(const QString &name)
double sum_solids(const Eigen::Vector3f &from) const
void find_closest_on_surface_approx(const PointsT &r, int np, Eigen::VectorXi &nearest_tri, Eigen::VectorXf &dist, int nstep) const
Eigen::Vector3f project_to_triangle(int tri, float p, float q) const
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > PointsT
Eigen::Map< const Eigen::Vector3f > point(int k) const
static FiffCoordTrans procrustesAlign(int from_frame, int to_frame, const Eigen::MatrixXf &fromp, const Eigen::MatrixXf &top, const Eigen::VectorXf &w, float max_diff)
Eigen::MatrixX3f apply_inverse_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const