From 6494e3abb54ee9701df6ff27cfb0a7fa1409dded Mon Sep 17 00:00:00 2001 From: "Arens, Tobias" <t.arens@fz-juelich.de> Date: Mon, 12 Sep 2022 09:51:04 +0200 Subject: [PATCH] Resolve "Add method for vector rotation for converting to world coordinate system" --- include/extrCalibration.h | 1 + src/extrCalibration.cpp | 21 ++++ tests/unit_test/CMakeLists.txt | 1 + tests/unit_test/tst_extrCalibration.cpp | 130 ++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 tests/unit_test/tst_extrCalibration.cpp diff --git a/include/extrCalibration.h b/include/extrCalibration.h index 86183ad10..c2c29cba3 100644 --- a/include/extrCalibration.h +++ b/include/extrCalibration.h @@ -181,6 +181,7 @@ public: virtual cv::Point2f getImagePoint(cv::Point3f p3d); cv::Point3f get3DPoint(const cv::Point2f &p2d, double h) const; cv::Point3f transformRT(cv::Point3f p); + cv::Vec3d camToWorldRotation(const cv::Vec3d &vec) const; bool isOutsideImage(cv::Point2f p2d); inline bool isOutsideImage(cv::Point3f p3d) { return isOutsideImage(getImagePoint(p3d)); } inline std::vector<cv::Point3f> get3DList() { return points3D; } diff --git a/src/extrCalibration.cpp b/src/extrCalibration.cpp index f256bcad4..5e96b3dc1 100644 --- a/src/extrCalibration.cpp +++ b/src/extrCalibration.cpp @@ -895,6 +895,27 @@ cv::Point2f ExtrCalibration::getImagePoint(cv::Point3f p3d) return point2D; } +/** + * @brief Rotate a given vector from camera coordinate system to world coordinate system + * + * When the world coordinate system is not aligned to the camera-system, + * some direction dependent calculations (like head orientation) have to be rotated to be correctly exported. + * + * @param camVec the Vector to be rotated matching the camera coordinate system. + * @return the rotated vector. + */ +cv::Vec3d ExtrCalibration::camToWorldRotation(const cv::Vec3d &camVec) const +{ + // Transform the rotation vector into a rotation matrix with opencvs rodrigues method + cv::Matx<double, 3, 3> rotMat(3, 3, CV_64F); + const auto rvec = cv::Vec3d( + mControlWidget->getCalibExtrRot1(), mControlWidget->getCalibExtrRot2(), mControlWidget->getCalibExtrRot3()); + Rodrigues(rvec, rotMat); + + auto rotInv = rotMat.inv(cv::DECOMP_LU); + cv::Vec3d worldVec = rotInv * camVec; + return worldVec; +} /** * @brief Tranforms a 2D point into a 3D point with given height. diff --git a/tests/unit_test/CMakeLists.txt b/tests/unit_test/CMakeLists.txt index 30e66a31d..e814ff93b 100644 --- a/tests/unit_test/CMakeLists.txt +++ b/tests/unit_test/CMakeLists.txt @@ -11,4 +11,5 @@ target_sources(petrack_tests PRIVATE tst_codeMarkerWidget.cpp tst_helper.cpp tst_petrack.cpp + tst_extrCalibration.cpp ) diff --git a/tests/unit_test/tst_extrCalibration.cpp b/tests/unit_test/tst_extrCalibration.cpp new file mode 100644 index 000000000..16f6c298c --- /dev/null +++ b/tests/unit_test/tst_extrCalibration.cpp @@ -0,0 +1,130 @@ +/* + * PeTrack - Software for tracking pedestrians movement in videos + * Copyright (C) 2010-2022 Forschungszentrum Jülich GmbH, + * Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand, + * Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +#include "control.h" +#include "extrCalibration.h" +#include "petrack.h" + +#include <catch2/catch.hpp> + + +// use margin for absolute difference, as epsilon would be relative which is useless when comparing to 0 +constexpr float VEC_MARGIN = 0.01; + +TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]") +{ + Petrack petrack{}; + auto calib = petrack.getExtrCalibration(); + Control *control = petrack.getControlWidget(); + + control->setCalibExtrRot1(0); + control->setCalibExtrRot2(0); + control->setCalibExtrRot3(0); + + SECTION("Identity Coordinate System") + { + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(1, 0, 0)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 2, 3)) - cv::Vec3d(1, 2, 3)) == + Approx(0).margin(VEC_MARGIN)); + } + + SECTION("Rotated around z-axis") + { + // rotate 90 degrees + control->setCalibExtrRot3(PI / 2); + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(0, -1, 0)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(0, 1, 0)) - cv::Vec3d(1, 0, 0)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 2, 3)) - cv::Vec3d(2, -1, 3)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(-5, 5, -2)) - cv::Vec3d(5, 5, -2)) == + Approx(0).margin(VEC_MARGIN)); + + // negative rotation + control->setCalibExtrRot3(-PI); + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(-1, 0, 0)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 2, -3)) - cv::Vec3d(-1, -2, -3)) == + Approx(0).margin(VEC_MARGIN)); + } + + SECTION("Wild rotation") + { + // vector (1, 1, 1) with length pi/2 + control->setCalibExtrRot1(0.9067); + control->setCalibExtrRot2(0.9067); + control->setCalibExtrRot3(0.9067); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 1, 1)) - cv::Vec3d(1, 1, 1)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(0.33, -0.24, 0.91)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 2, 3)) - cv::Vec3d(1.42, 3.15, 1.42)) == + Approx(0).margin(VEC_MARGIN)); + + SECTION("Translation should not matter") + { + control->setCalibExtrTrans1(10); + control->setCalibExtrTrans2(-20); + control->setCalibExtrTrans3(-500); + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(0.33, -0.24, 0.91)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 2, 3)) - cv::Vec3d(1.42, 3.15, 1.42)) == + Approx(0).margin(VEC_MARGIN)); + } + } + + SECTION("Another Wild Rotation") + { + control->setCalibExtrRot1(0.5); + control->setCalibExtrRot2(-2); + control->setCalibExtrRot3(1.1); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 1, 1)) - cv::Vec3d(0.2, -0.63, -1.6)) == + Approx(0).margin(VEC_MARGIN)); + + REQUIRE( + cv::norm(calib->camToWorldRotation(cv::Vec3d(1, -2, 3)) - cv::Vec3d(1.69, -3.33, 0.27)) == + Approx(0).margin(VEC_MARGIN)); + } +} -- GitLab