From 1d88e19c32b142117147ef1f486ff03a7a7f7bca Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Aug 2025 11:15:31 +0200 Subject: [PATCH] Fix #145185: Crash while solving camera motion The crash happens in specific cases when doing euclidean resection in cases when first 3 3D estimates are correlated. While it is a bit cryptic on user level, what it could mean is: - Either there are overlapping markers - Or the optical system is highly out of calibration. Either of these cases is not the primary goal to support with camera solvers in Libmv for the time being, so while this change avoids the crash there is possibility to make algorithm more robustly handle the tracking data and potentially give better result. Such correlation via some intermediate steps leads to the algorithm attempting to perform SVD decomposition of a matrix with NaN values in it. The exact reason of the crash is not super clear as it happens deep in the JacobiSVD decomposition code in Eigen and caused by invalid index somewhere. It might be a bug in Eigen which doesn't do range checking, hoping that the math does not fail in cases like NaN and inf. Pull Request: https://projects.blender.org/blender/blender/pulls/145301 --- .../libmv/multiview/euclidean_resection.cc | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/intern/libmv/libmv/multiview/euclidean_resection.cc b/intern/libmv/libmv/multiview/euclidean_resection.cc index 249d7ebef3d..3dc8a3876a1 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection.cc +++ b/intern/libmv/libmv/multiview/euclidean_resection.cc @@ -377,7 +377,7 @@ static void SelectControlPoints(const Mat3X& X_world, } // Computes the barycentric coordinates for all real points -static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered, +static bool ComputeBarycentricCoordinates(const Mat3X& X_world_centered, const Mat34& X_control_points, Mat4X* alphas) { size_t num_points = X_world_centered.cols(); @@ -386,7 +386,21 @@ static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered, C2.col(c - 1) = X_control_points.col(c) - X_control_points.col(0); } - Mat3 C2inv = C2.inverse(); + // The selected basis might have correlated vectors causing inverse to produce + // undefined result which could lead to issues later on in SVD decomposition. + // + // Evidently, when built with MSVC it could lead to crash in SVD when the + // input contains NaN values: + // https://projects.blender.org/blender/blender/issues/145185 + // + // TODO(sergey): Look into choosing a different basis in these cases. + bool is_invertible; + Mat3 C2inv; + C2.computeInverseWithCheck(C2inv, is_invertible); + if (!is_invertible) { + return false; + } + Mat3X a = C2inv * X_world_centered; alphas->resize(4, num_points); @@ -395,6 +409,8 @@ static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered, for (size_t c = 0; c < num_points; c++) { (*alphas)(0, c) = 1.0 - alphas->col(c).sum(); } + + return true; } // Estimates the coordinates of all real points in the camera coordinate frame @@ -450,7 +466,9 @@ bool EuclideanResectionEPnP(const Mat2X& x_camera, // Compute the barycentric coordinates. Mat4X alphas(4, num_points); - ComputeBarycentricCoordinates(X_centered, X_control_points, &alphas); + if (!ComputeBarycentricCoordinates(X_centered, X_control_points, &alphas)) { + return false; + } // Estimates the M matrix with the barycentric coordinates Mat M(2 * num_points, 12);