From 06e749c91ede5f051a9ad82e6623552a0a79177f Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Thu, 12 Oct 2023 18:13:44 +0200 Subject: [PATCH 1/7] Zenith was the nadir in the init --- src/software/pipeline/main_panoramaInit.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/software/pipeline/main_panoramaInit.cpp b/src/software/pipeline/main_panoramaInit.cpp index 7873367c39..7202da00cd 100644 --- a/src/software/pipeline/main_panoramaInit.cpp +++ b/src/software/pipeline/main_panoramaInit.cpp @@ -1025,10 +1025,10 @@ int main(int argc, char* argv[]) const Eigen::AngleAxis Mroll(roll, Eigen::Vector3d::UnitZ()); const Eigen::AngleAxis Mimage(additionalAngle - M_PI_2, Eigen::Vector3d::UnitZ()); - const Eigen::Matrix3d cRo = Myaw.toRotationMatrix() * Mpitch.toRotationMatrix() * + const Eigen::Matrix3d oRc = Myaw.toRotationMatrix() * Mpitch.toRotationMatrix() * Mroll.toRotationMatrix() * Mimage.toRotationMatrix(); - rotations[rank] = cRo.transpose(); + rotations[rank] = oRc.transpose(); } if(sfmData.getViews().size() != rotations.size()) @@ -1041,17 +1041,18 @@ int main(int argc, char* argv[]) } else if(boost::algorithm::contains(initializeCameras, "horizontal")) { - constexpr double zenithPitch = -0.5 * boost::math::constants::pi(); + constexpr double zenithPitch = 0.5 * boost::math::constants::pi(); const Eigen::AngleAxis zenithMpitch(zenithPitch, Eigen::Vector3d::UnitX()); const Eigen::AngleAxis zenithMroll(additionalAngle, Eigen::Vector3d::UnitZ()); - const Eigen::Matrix3d zenithRo = zenithMpitch.toRotationMatrix() * zenithMroll.toRotationMatrix(); + const Eigen::Matrix3d oRzenith = zenithMpitch.toRotationMatrix() * zenithMroll.toRotationMatrix(); const bool withZenith = boost::algorithm::contains(initializeCameras, "zenith"); if(initializeCameras == "zenith+horizontal") { ALICEVISION_LOG_TRACE("Add zenith first"); - rotations[rotations.size()] = zenithRo.transpose(); + rotations[rotations.size()] = oRzenith.transpose(); } + const std::size_t nbHorizontalViews = sfmData.getViews().size() - int(withZenith); for(int x = 0; x < nbHorizontalViews; ++x) { @@ -1066,15 +1067,15 @@ int main(int argc, char* argv[]) const Eigen::AngleAxis Myaw(yaw, Eigen::Vector3d::UnitY()); const Eigen::AngleAxis Mroll(additionalAngle, Eigen::Vector3d::UnitZ()); - const Eigen::Matrix3d cRo = Myaw.toRotationMatrix() * Mroll.toRotationMatrix(); + const Eigen::Matrix3d oRc = Myaw.toRotationMatrix() * Mroll.toRotationMatrix(); ALICEVISION_LOG_TRACE("Add rotation: yaw=" << yaw); - rotations[rotations.size()] = cRo.transpose(); + rotations[rotations.size()] = oRc.transpose(); } if(initializeCameras == "horizontal+zenith") { ALICEVISION_LOG_TRACE("Add zenith"); - rotations[rotations.size()] = zenithRo.transpose(); + rotations[rotations.size()] = oRzenith.transpose(); } } else if(initializeCameras == "spherical" || (initializeCameras.empty() && !nbViewsPerLineString.empty())) @@ -1165,12 +1166,12 @@ int main(int argc, char* argv[]) const Eigen::AngleAxis Mpitch(pitch, Eigen::Vector3d::UnitX()); const Eigen::AngleAxis Mroll(roll + additionalAngle, Eigen::Vector3d::UnitZ()); - const Eigen::Matrix3d cRo = + const Eigen::Matrix3d oRc = Myaw.toRotationMatrix() * Mpitch.toRotationMatrix() * Mroll.toRotationMatrix(); ALICEVISION_LOG_TRACE("Add rotation: yaw=" << yaw << ", pitch=" << pitch << ", roll=" << roll << "."); - rotations[i++] = cRo.transpose(); + rotations[i++] = oRc.transpose(); } } } From c62955de625f8e8da8a550179ef9c54e240593df Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Mon, 2 Oct 2023 14:33:15 +0200 Subject: [PATCH 2/7] Fallback when camera motion is not distinctive enough --- src/aliceVision/sfm/utils/alignment.cpp | 39 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/aliceVision/sfm/utils/alignment.cpp b/src/aliceVision/sfm/utils/alignment.cpp index 50894b40f1..89f31e7c8b 100644 --- a/src/aliceVision/sfm/utils/alignment.cpp +++ b/src/aliceVision/sfm/utils/alignment.cpp @@ -20,6 +20,7 @@ #include #include +#include #include @@ -588,18 +589,16 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, //Warning, eigenvalues are not sorted ... Vec3 evalues = solver.eigenvalues().real(); Vec3 aevalues = evalues.cwiseAbs(); - IndexT minCol = 0; - double minVal = aevalues[0]; - if (aevalues[1] < minVal) - { - minVal = aevalues[1]; - minCol = 1; - } - if (aevalues[2] < minVal) - { - minVal = aevalues[2]; - minCol = 2; - } + + std::vector indices(evalues.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), [&](int i, int j) { return evalues[i] < evalues[j]; }); + int minCol = indices[0]; + + //Make sure we have a clear unique small eigen value + double ratio1 = evalues[indices[2]] / evalues[indices[0]]; + double ratio2 = evalues[indices[2]] / evalues[indices[1]]; + double unicity = ratio1 / ratio2; ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: eigenvalues: " << solver.eigenvalues()); ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: eigenvectors: " << solver.eigenvectors()); @@ -607,7 +606,13 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, // We assume that the X axis of all or majority of the cameras are on a plane. // The covariance is a flat ellipsoid and the min axis is our candidate Y axis. Eigen::Vector3d nullestSpace = solver.eigenvectors().col(minCol).real(); - const Eigen::Vector3d referenceAxis = Eigen::Vector3d::UnitY(); + Eigen::Vector3d referenceAxis = Eigen::Vector3d::UnitY(); + + if (unicity < 10.0) + { + ALICEVISION_LOG_DEBUG("Algorithm did not find a clear axis. Align with raw Y."); + nullestSpace = meanRy; + } // Compute the rotation which rotates nullestSpace onto unitY out_R = Matrix3d(Quaterniond().setFromTwoVectors(nullestSpace, referenceAxis)); @@ -655,6 +660,10 @@ void computeNewCoordinateSystemFromCameras(const sfmData::SfMData& sfmData, stddev += camCenterMean.transpose() * camCenterMean; } stddev /= nbCameras; + if (stddev < 1e-12) //If there is no translation change + { + stddev = 1.0; + } // Make sure the point cloud is centered and scaled to unit deviation for (Vec3::Index i = 0; i < vCamCenter.cols(); ++i) @@ -1108,6 +1117,10 @@ void computeNewCoordinateSystemAuto(const sfmData::SfMData& sfmData, double& out //By default, scale to get unit rms const double rms = sqrt(covCamBase.trace() / double(count)); out_S = 1.0 / rms; + if (rms < 1e-12) + { + out_S = 1.0; + } ALICEVISION_LOG_INFO("Initial point cloud scale: " << rms); From db031f8855d6fc83d178cec9f27461c83b004185 Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Mon, 16 Oct 2023 12:31:39 +0200 Subject: [PATCH 3/7] Very small negative values may give buggy result --- src/aliceVision/sfm/utils/alignment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aliceVision/sfm/utils/alignment.cpp b/src/aliceVision/sfm/utils/alignment.cpp index 89f31e7c8b..e64c8360d7 100644 --- a/src/aliceVision/sfm/utils/alignment.cpp +++ b/src/aliceVision/sfm/utils/alignment.cpp @@ -608,7 +608,7 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, Eigen::Vector3d nullestSpace = solver.eigenvectors().col(minCol).real(); Eigen::Vector3d referenceAxis = Eigen::Vector3d::UnitY(); - if (unicity < 10.0) + if (std::abs(unicity) < 10.0) { ALICEVISION_LOG_DEBUG("Algorithm did not find a clear axis. Align with raw Y."); nullestSpace = meanRy; From c50564b3a0ac85dea7e6e0afea6660ac020cebb4 Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Tue, 17 Oct 2023 15:37:22 +0200 Subject: [PATCH 4/7] check that maximal eigen values is large enough --- src/aliceVision/sfm/utils/alignment.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/aliceVision/sfm/utils/alignment.cpp b/src/aliceVision/sfm/utils/alignment.cpp index e64c8360d7..a2096ec20d 100644 --- a/src/aliceVision/sfm/utils/alignment.cpp +++ b/src/aliceVision/sfm/utils/alignment.cpp @@ -563,6 +563,7 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, meanRy /= validPoses; meanCameraCenter /= validPoses; + size_t count = 0; double rms = 0.0; // Compute covariance matrix of the rotation X component Eigen::Matrix3d C = Eigen::Matrix3d::Zero(); @@ -581,9 +582,16 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, const Eigen::Vector3d rX = p.rotation().transpose() * oriented_X; C += (rX - meanRx) * (rX - meanRx).transpose(); + + count++; } } + if (count > 1) + { + C = C / double(count - 1); + } + Eigen::EigenSolver solver(C, true); //Warning, eigenvalues are not sorted ... @@ -599,16 +607,19 @@ void computeNewCoordinateSystemFromCamerasXAxis(const sfmData::SfMData& sfmData, double ratio1 = evalues[indices[2]] / evalues[indices[0]]; double ratio2 = evalues[indices[2]] / evalues[indices[1]]; double unicity = ratio1 / ratio2; + double largest = std::abs(evalues[indices[2]]); ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: eigenvalues: " << solver.eigenvalues()); ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: eigenvectors: " << solver.eigenvectors()); + ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: unicity: " << unicity); + ALICEVISION_LOG_DEBUG("computeNewCoordinateSystemFromCamerasXAxis: largest eigen value: " << largest); // We assume that the X axis of all or majority of the cameras are on a plane. // The covariance is a flat ellipsoid and the min axis is our candidate Y axis. Eigen::Vector3d nullestSpace = solver.eigenvectors().col(minCol).real(); Eigen::Vector3d referenceAxis = Eigen::Vector3d::UnitY(); - if (std::abs(unicity) < 10.0) + if (std::abs(unicity) < 10.0 || largest < 1e-2) { ALICEVISION_LOG_DEBUG("Algorithm did not find a clear axis. Align with raw Y."); nullestSpace = meanRy; From 281a94cb49b9572d7643973aafd8690f9cc01b17 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Wed, 18 Oct 2023 18:05:52 +0200 Subject: [PATCH 5/7] [keyframe] fix intrinsics UID BodySerialNumber is used (in combination with LensSerialNumber) to compute the intrinsic UID. So we should not set a random value on each frame, to avoid the creation of one intrinsic per image. --- src/aliceVision/keyframe/KeyframeSelector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/aliceVision/keyframe/KeyframeSelector.cpp b/src/aliceVision/keyframe/KeyframeSelector.cpp index 0ca86832fe..32a72cafdb 100644 --- a/src/aliceVision/keyframe/KeyframeSelector.cpp +++ b/src/aliceVision/keyframe/KeyframeSelector.cpp @@ -647,7 +647,6 @@ bool KeyframeSelector::writeSelection(const std::vector& brands, oiio::ParamValueList metadata; metadata.push_back(oiio::ParamValue("Make", brands[id])); metadata.push_back(oiio::ParamValue("Model", models[id])); - metadata.push_back(oiio::ParamValue("Exif:BodySerialNumber", std::to_string(getRandomInt()))); metadata.push_back(oiio::ParamValue("Exif:FocalLength", mmFocals[id])); metadata.push_back(oiio::ParamValue("Exif:ImageUniqueID", std::to_string(getRandomInt()))); metadata.push_back(oiio::ParamValue("Orientation", orientation)); // Will not propagate for PNG outputs From f5db5fa08e5b75ef4ac459bc6facbb768581e663 Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Fri, 20 Oct 2023 11:41:55 +0200 Subject: [PATCH 6/7] Camera can now create anamorphic4 distortions --- src/aliceVision/camera/Pinhole.cpp | 1 + src/aliceVision/camera/camera.hpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/aliceVision/camera/Pinhole.cpp b/src/aliceVision/camera/Pinhole.cpp index 53bd948ce7..10d6ab2f54 100644 --- a/src/aliceVision/camera/Pinhole.cpp +++ b/src/aliceVision/camera/Pinhole.cpp @@ -333,6 +333,7 @@ EINTRINSIC Pinhole::getType() const case EDISTORTION::DISTORTION_FISHEYE1: return EINTRINSIC::PINHOLE_CAMERA_FISHEYE1; case EDISTORTION::DISTORTION_3DERADIAL4: return EINTRINSIC::PINHOLE_CAMERA_3DERADIAL4; case EDISTORTION::DISTORTION_3DECLASSICLD: return EINTRINSIC::PINHOLE_CAMERA_3DECLASSICLD; + case EDISTORTION::DISTORTION_3DEANAMORPHIC4: return EINTRINSIC::PINHOLE_CAMERA_3DEANAMORPHIC4; default: throw std::out_of_range("Invalid distortion model for pinhole camera."); } } diff --git a/src/aliceVision/camera/camera.hpp b/src/aliceVision/camera/camera.hpp index f037d50ab9..02f7000dc2 100644 --- a/src/aliceVision/camera/camera.hpp +++ b/src/aliceVision/camera/camera.hpp @@ -64,6 +64,9 @@ inline std::shared_ptr createDistortion(EDISTORTION distortionType, case EDISTORTION::DISTORTION_3DERADIAL4: distortion = std::make_shared(); break; + case EDISTORTION::DISTORTION_3DEANAMORPHIC4: + distortion = std::make_shared(); + break; default: break; } From debc15aab3201e050531daae9204880a1a8c7b72 Mon Sep 17 00:00:00 2001 From: Fabien Servant Date: Fri, 20 Oct 2023 14:13:02 +0200 Subject: [PATCH 7/7] [sfmDataIO] JsonIO: Do not disable distortion if the size is not good --- src/aliceVision/sfmDataIO/jsonIO.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/aliceVision/sfmDataIO/jsonIO.cpp b/src/aliceVision/sfmDataIO/jsonIO.cpp index bdc43a8505..4c90f0a96c 100644 --- a/src/aliceVision/sfmDataIO/jsonIO.cpp +++ b/src/aliceVision/sfmDataIO/jsonIO.cpp @@ -320,10 +320,6 @@ void loadIntrinsic(const Version & version, IndexT& intrinsicId, std::shared_ptr { distortionObject->setParameters(distortionParams); } - else - { - intrinsicWithDistoEnabled->setDistortionObject(nullptr); - } } std::shared_ptr undistortionObject = intrinsicWithDistoEnabled->getUndistortion(); @@ -343,10 +339,6 @@ void loadIntrinsic(const Version & version, IndexT& intrinsicId, std::shared_ptr loadMatrix("undistortionOffset", offset, intrinsicTree); undistortionObject->setOffset(offset); } - else - { - intrinsicWithDistoEnabled->setUndistortionObject(nullptr); - } } }