From df4947220c74f86fceb7247f3904820228143bf4 Mon Sep 17 00:00:00 2001
From: "d.kilic" <d.kilic@fz-juelich.de>
Date: Mon, 27 Mar 2023 10:35:30 +0200
Subject: [PATCH] Gray out calib (3/N)

- Introduces `ExtrinsicParameters`-Struct
- Extract `ExtrinsicBox` from `Control`
---
 CMakeLists.txt                          |   6 +-
 include/control.h                       |  36 +-
 include/extrCalibration.h               |  51 +-
 include/extrinsicBox.h                  |  82 ++++
 include/extrinsicParameters.h           |  39 ++
 src/borderFilter.cpp                    |  22 +-
 src/control.cpp                         | 319 ++----------
 src/extrCalibration.cpp                 | 619 ++++++++++++------------
 src/extrinsicBox.cpp                    | 301 ++++++++++++
 src/imageItem.cpp                       |   7 +-
 src/petrack.cpp                         |   2 +-
 src/recognition.cpp                     |   5 +-
 src/trackerItem.cpp                     |  16 +-
 tests/unit_test/CMakeLists.txt          |   1 +
 tests/unit_test/tst_extrCalibration.cpp |  45 +-
 tests/unit_test/tst_extrinsicBox.cpp    | 115 +++++
 ui/control.ui                           | 334 +------------
 ui/extrinsicBox.ui                      | 354 ++++++++++++++
 18 files changed, 1318 insertions(+), 1036 deletions(-)
 create mode 100644 include/extrinsicBox.h
 create mode 100644 include/extrinsicParameters.h
 create mode 100644 src/extrinsicBox.cpp
 create mode 100644 tests/unit_test/tst_extrinsicBox.cpp
 create mode 100644 ui/extrinsicBox.ui

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 97ab9fcb7..dbb91fbf6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -390,7 +390,9 @@ target_sources(petrack_core PRIVATE
     include/filterBeforeBox.h
     include/intrinsicBox.h
     include/intrinsicCameraParams.h
-    )
+    include/extrinsicBox.h
+    include/extrinsicParameters.h
+)
 
 target_sources(petrack_core PRIVATE
     src/aboutDialog.cpp
@@ -456,6 +458,7 @@ target_sources(petrack_core PRIVATE
     src/intrinsicBox.cpp
     src/filterBeforeBox.cpp
     src/intrinsicCameraParams.cpp
+    src/extrinsicBox.cpp
     ui/about.ui
     ui/codeMarker.ui
     ui/colorMarker.ui
@@ -467,6 +470,7 @@ target_sources(petrack_core PRIVATE
     ui/moCapSelectionWidget.ui
     ui/filterBeforeBox.ui
     ui/intrinsicBox.ui
+    ui/extrinsicBox.ui
 )
 
 target_sources(petrack PRIVATE
diff --git a/include/control.h b/include/control.h
index 01078b60a..1d060350d 100644
--- a/include/control.h
+++ b/include/control.h
@@ -21,6 +21,7 @@
 
 #include "analysePlot.h"
 #include "colorPlot.h"
+#include "extrinsicParameters.h"
 #include "intrinsicCameraParams.h"
 #include "petrack.h"
 #include "recognition.h"
@@ -31,6 +32,7 @@
 class QGraphicsScene;
 class QDomElement;
 class IntrinsicBox;
+class ExtrinsicBox;
 class FilterBeforeBox;
 namespace Ui
 {
@@ -152,19 +154,7 @@ public:
     void   setCalibReprError(double d);
     void   imageSizeChanged(int width, int height, int borderDiff);
 
-    double getCalibExtrRot1();
-    void   setCalibExtrRot1(double d);
-    double getCalibExtrRot2();
-    void   setCalibExtrRot2(double d);
-    double getCalibExtrRot3();
-    void   setCalibExtrRot3(double d);
-    double getCalibExtrTrans1();
-    void   setCalibExtrTrans1(double d);
-    double getCalibExtrTrans2();
-    void   setCalibExtrTrans2(double d);
-    double getCalibExtrTrans3();
-    void   setCalibExtrTrans3(double d);
-    void   setEnabledExtrParams(bool enable);
+    const ExtrinsicParameters &getExtrinsicParameters() const;
 
     int    getCalibCoordDimension();
     bool   getCalibExtrCalibPointsShow();
@@ -242,7 +232,7 @@ public:
     double getCameraAltitude() const;
 
     void       setXml(QDomElement &elem);
-    void       getXml(QDomElement &elem);
+    void       getXml(const QDomElement &elem);
     bool       isLoading() const { return mMainWindow->isLoading(); }
     ColorPlot *getColorPlot() const;
     void       replotColorplot();
@@ -561,7 +551,6 @@ private slots:
     void on_coordAltitude_valueChanged(double d);
     void on_coordUnit_valueChanged(double d);
     void on_coordUseIntrinsic_stateChanged(int i);
-    void on_coordLoad3DCalibPoints_clicked();
 
     void setMeasuredAltitude();
 
@@ -587,22 +576,10 @@ private slots:
     void on_coord3DTransZ_valueChanged(int value);
     void on_coord3DAxeLen_valueChanged(int value);
 
-    void on_rot1_valueChanged(double arg1);
-    void on_rot2_valueChanged(double arg1);
-    void on_rot3_valueChanged(double arg1);
-    void on_trans1_valueChanged(double arg1);
-    void on_trans2_valueChanged(double arg1);
-    void on_trans3_valueChanged(double arg1);
-
     void on_coord3DSwapX_stateChanged(int arg1);
     void on_coord3DSwapY_stateChanged(int arg1);
     void on_coord3DSwapZ_stateChanged(int arg1);
 
-    void on_extrCalibSave_clicked();
-    void on_extrCalibFetch_clicked();
-    void on_extrCalibShowPoints_clicked();
-    void on_extrCalibShowError_clicked();
-
     void on_trackPathColorButton_clicked();
     void on_trackGroundPathColorButton_clicked();
     void on_moCapColorButton_clicked();
@@ -635,11 +612,12 @@ private:
     Ui::Control     *mUi;
     IntrinsicBox    *mIntr;
     FilterBeforeBox *mFilterBefore;
+    ExtrinsicBox    *mExtr;
     QGraphicsScene  *mScene;
     bool             mColorChanging;
     bool mIndexChanging; // shows, if the index of the color model is really changing; nor while constructor (initialer
-                         // durchlauf) and may be while loading xml file
-    bool mLoading;       // shows, if new project is just loading
+    // durchlauf) and may be while loading xml file
+    bool mLoading; // shows, if new project is just loading
 };
 
 #endif
diff --git a/include/extrCalibration.h b/include/extrCalibration.h
index 3f811de80..a32071a3e 100644
--- a/include/extrCalibration.h
+++ b/include/extrCalibration.h
@@ -19,11 +19,14 @@
 #ifndef EXTRCALIBRATION_H
 #define EXTRCALIBRATION_H
 
+#include "extrinsicParameters.h"
+
 #include <QDomElement>
 #include <QString>
 #include <array>
 #include <iostream>
 #include <opencv2/opencv.hpp>
+#include <optional>
 #include <vector>
 
 class Petrack;
@@ -165,30 +168,30 @@ private:
 public:
     ExtrCalibration(PersonStorage &storage);
     ~ExtrCalibration();
-    void                            setMainWindow(Petrack *mw);
-    bool                            isEmptyExtrCalibFile();
-    bool                            isSetExtrCalib();
-    void                            setExtrCalibFile(const QString &f);
-    QString                         getExtrCalibFile();
-    bool                            openExtrCalibFile();
-    bool                            loadExtrCalibFile();
-    bool                            saveExtrCalibPoints();
-    bool                            fetch2DPoints();
-    void                            calibExtrParams();
-    bool                            calcReprojectionError();
-    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; }
-    inline void                     set3DList(std::vector<cv::Point3f> list3D) { this->points3D = list3D; }
-    inline std::vector<cv::Point2f> get2DList() { return points2D; }
-    inline void                     set2DList(std::vector<cv::Point2f> list2D) { this->points2D = list2D; }
-    inline float                    getCamHeight() const { return camHeight; }
-    inline void                     setCamHeight(float cHeight) { this->camHeight = cHeight; }
-    inline ReprojectionError        getReprojectionError()
+    void                               setMainWindow(Petrack *mw);
+    bool                               isEmptyExtrCalibFile();
+    bool                               isSetExtrCalib();
+    void                               setExtrCalibFile(const QString &f);
+    QString                            getExtrCalibFile();
+    std::optional<ExtrinsicParameters> openExtrCalibFile();
+    std::optional<ExtrinsicParameters> loadExtrCalibFile();
+    bool                               saveExtrCalibPoints();
+    std::optional<ExtrinsicParameters> fetch2DPoints();
+    std::optional<ExtrinsicParameters> calibExtrParams();
+    bool                               calcReprojectionError();
+    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; }
+    inline void                        set3DList(std::vector<cv::Point3f> list3D) { this->points3D = list3D; }
+    inline std::vector<cv::Point2f>    get2DList() { return points2D; }
+    inline void                        set2DList(std::vector<cv::Point2f> list2D) { this->points2D = list2D; }
+    inline float                       getCamHeight() const { return camHeight; }
+    inline void                        setCamHeight(float cHeight) { this->camHeight = cHeight; }
+    inline ReprojectionError           getReprojectionError()
     {
         if(!reprojectionError.isValid())
         {
diff --git a/include/extrinsicBox.h b/include/extrinsicBox.h
new file mode 100644
index 000000000..fd50a615d
--- /dev/null
+++ b/include/extrinsicBox.h
@@ -0,0 +1,82 @@
+/*
+ * PeTrack - Software for tracking pedestrians movement in videos
+ * Copyright (C) 2023 Forschungszentrum Jülich GmbH, IAS-7
+ *
+ * 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/>.
+ */
+
+#ifndef EXTRINSICBOX_H
+#define EXTRINSICBOX_H
+
+#include "extrinsicParameters.h"
+
+#include <QGroupBox>
+
+namespace Ui
+{
+class extr;
+}
+class QDomElement;
+class ExtrCalibration;
+
+
+class ExtrinsicBox : public QGroupBox
+{
+    Q_OBJECT
+
+public:
+    explicit ExtrinsicBox(
+        QWidget              *parent,
+        Ui::extr             *ui,
+        ExtrCalibration      &extrCalib,
+        std::function<void()> updateCoordCallback);
+    explicit ExtrinsicBox(QWidget *parent, ExtrCalibration &extrCalib, std::function<void()> updateCoordCallback);
+    ExtrinsicBox(const ExtrinsicBox &other)            = delete;
+    ExtrinsicBox(ExtrinsicBox &&other)                 = delete;
+    ExtrinsicBox &operator=(const ExtrinsicBox &other) = delete;
+    ExtrinsicBox &operator=(ExtrinsicBox &&other)      = delete;
+    ~ExtrinsicBox() override;
+
+    void                       setEnabledExtrParams(bool enable);
+    const ExtrinsicParameters &getExtrinsicParameters() const;
+    void                       setExtrinsicParameters(const ExtrinsicParameters &params);
+
+    bool getXml(QDomElement &subSubElem);
+    void setXml(QDomElement &subElem) const;
+
+private slots:
+
+    void on_extrCalibFetch_clicked();
+    void on_coordLoad3DCalibPoints_clicked();
+
+    void on_rot1_valueChanged(double newVal);
+    void on_rot2_valueChanged(double newVal);
+    void on_rot3_valueChanged(double newVal);
+    void on_trans1_valueChanged(double newVal);
+    void on_trans2_valueChanged(double newVal);
+    void on_trans3_valueChanged(double newVal);
+
+
+    void on_extrCalibSave_clicked();
+    void on_extrCalibShowPoints_clicked();
+    void on_extrCalibShowError_clicked();
+
+private:
+    Ui::extr             *mUi;
+    ExtrCalibration      &mExtrCalibration;
+    ExtrinsicParameters   mParams;
+    std::function<void()> mUpdateCoordCallback;
+};
+
+#endif // EXTRINSICBOX_H
diff --git a/include/extrinsicParameters.h b/include/extrinsicParameters.h
new file mode 100644
index 000000000..689b8a9a2
--- /dev/null
+++ b/include/extrinsicParameters.h
@@ -0,0 +1,39 @@
+/*
+ * PeTrack - Software for tracking pedestrians movement in videos
+ * Copyright (C) 2023 Forschungszentrum Jülich GmbH, IAS-7
+ *
+ * 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/>.
+ */
+
+#ifndef EXTRINSICPARAMETERS_H
+#define EXTRINSICPARAMETERS_H
+
+struct ExtrinsicParameters
+{
+    double trans1 = 0;
+    double trans2 = 0;
+    double trans3 = -500;
+
+    double rot1 = 0;
+    double rot2 = 0;
+    double rot3 = 0;
+
+    friend bool operator==(const ExtrinsicParameters &lhs, const ExtrinsicParameters &rhs)
+    {
+        return lhs.rot1 == rhs.rot1 && lhs.rot2 == rhs.rot2 && lhs.rot3 == rhs.rot3 && lhs.trans1 == rhs.trans1 &&
+               lhs.trans2 == rhs.trans2 && lhs.trans3 == rhs.trans3;
+    }
+};
+
+#endif // EXTRINSICPARAMETERS_H
diff --git a/src/borderFilter.cpp b/src/borderFilter.cpp
index de1a98bc7..3417c3175 100644
--- a/src/borderFilter.cpp
+++ b/src/borderFilter.cpp
@@ -21,21 +21,21 @@
 
 BorderFilter::BorderFilter() : Filter()
 {
-    mSize.setMinimum(0.);
+    mSize.setMinimum(0);
     mSize.setMaximum(750);
-    mSize.setValue(0.);
+    mSize.setValue(0);
 
-    mRed.setMinimum(0.);
-    mRed.setMaximum(200.);
-    mRed.setValue(0.);
+    mRed.setMinimum(0);
+    mRed.setMaximum(200);
+    mRed.setValue(0);
 
-    mGreen.setMinimum(0.);
-    mGreen.setMaximum(200.);
-    mGreen.setValue(0.);
+    mGreen.setMinimum(0);
+    mGreen.setMaximum(200);
+    mGreen.setValue(0);
 
-    mBlue.setMinimum(0.);
-    mBlue.setMaximum(200.);
-    mBlue.setValue(0.);
+    mBlue.setMinimum(0);
+    mBlue.setMaximum(200);
+    mBlue.setValue(0);
 
     setOnCopy(false);
 }
diff --git a/src/control.cpp b/src/control.cpp
index 8c0061d70..f346430b2 100644
--- a/src/control.cpp
+++ b/src/control.cpp
@@ -26,6 +26,7 @@
 #include "colorMarkerWidget.h"
 #include "colorPlot.h"
 #include "colorRangeWidget.h"
+#include "extrinsicBox.h"
 #include "filterBeforeBox.h"
 #include "imageItem.h"
 #include "intrinsicBox.h"
@@ -120,10 +121,25 @@ Control::Control(
 
     ui->verticalLayout_13->insertWidget(1, mIntr);
 
+    mExtr = new ExtrinsicBox(
+        this,
+        *mMainWindow->getExtrCalibration(),
+        [this]()
+        {
+            if(!isLoading())
+            {
+                mMainWindow->updateCoord();
+                mScene->update();
+            }
+        });
+    mExtr->setObjectName(QString::fromUtf8("extr"));
+    ui->verticalLayout_13->insertWidget(2, mExtr);
+
     // integrate new widgets in tabbing order
-    ui->calib->setFocusProxy(ui->rot1);
+    ui->calib->setFocusProxy(ui->coordShow);
     QWidget::setTabOrder(mFilterBefore, mIntr);
-    QWidget::setTabOrder(mIntr, ui->calib);
+    QWidget::setTabOrder(mIntr, mExtr);
+    QWidget::setTabOrder(mExtr, ui->calib);
 
     connect(mIntr, &IntrinsicBox::paramsChanged, this, &Control::on_intrinsicParamsChanged);
 
@@ -652,64 +668,9 @@ void Control::imageSizeChanged(int width, int height, int borderDiff)
     mIntr->imageSizeChanged(width, height, borderDiff);
 }
 
-double Control::getCalibExtrRot1()
-{
-    return mUi->rot1->value();
-}
-
-void Control::setCalibExtrRot1(double d)
-{
-    mUi->rot1->setValue(d);
-}
-
-double Control::getCalibExtrRot2()
-{
-    return mUi->rot2->value();
-}
-
-void Control::setCalibExtrRot2(double d)
-{
-    mUi->rot2->setValue(d);
-}
-
-double Control::getCalibExtrRot3()
-{
-    return mUi->rot3->value();
-}
-
-void Control::setCalibExtrRot3(double d)
-{
-    mUi->rot3->setValue(d);
-}
-
-double Control::getCalibExtrTrans1()
-{
-    return mUi->trans1->value();
-}
-
-void Control::setCalibExtrTrans1(double d)
-{
-    mUi->trans1->setValue(d);
-}
-
-double Control::getCalibExtrTrans2()
-{
-    return mUi->trans2->value();
-}
-
-void Control::setCalibExtrTrans2(double d)
-{
-    mUi->trans2->setValue(d);
-}
-
-double Control::getCalibExtrTrans3()
-{
-    return mUi->trans3->value();
-}
-
-void Control::setCalibExtrTrans3(double d)
+const ExtrinsicParameters &Control::getExtrinsicParameters() const
 {
-    mUi->trans3->setValue(d);
+    return mExtr->getExtrinsicParameters();
 }
 
 
@@ -778,16 +739,6 @@ void Control::setCalibGridScale(int i)
     mUi->gridScale->setValue(i);
 }
 
-void Control::setEnabledExtrParams(bool enable)
-{
-    mUi->rot1->setEnabled(enable);
-    mUi->rot2->setEnabled(enable);
-    mUi->rot3->setEnabled(enable);
-    mUi->trans1->setEnabled(enable);
-    mUi->trans2->setEnabled(enable);
-    mUi->trans3->setEnabled(enable);
-}
-
 void Control::setGridMinMaxTranslation(int minx, int maxx, int miny, int maxy)
 {
     mUi->grid3DTransX->setMinimum(minx);
@@ -1929,53 +1880,6 @@ void Control::on_intrinsicParamsChanged(IntrinsicCameraParams params)
 
 
 //---------------------------------------
-void Control::on_rot1_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
-
-void Control::on_rot2_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
-
-void Control::on_rot3_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
-
-void Control::on_trans1_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
-
-void Control::on_trans2_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
-
-void Control::on_trans3_valueChanged(double /*arg1*/)
-{
-    if(!isLoading())
-    {
-        mMainWindow->updateCoord();
-    }
-}
 
 void Control::on_extCalibPointsShow_stateChanged(int /*arg1*/)
 {
@@ -1985,65 +1889,6 @@ void Control::on_extCalibPointsShow_stateChanged(int /*arg1*/)
     }
 }
 
-void Control::on_extrCalibShowError_clicked()
-{
-    QString      out;
-    QDialog      msgBox;
-    QGridLayout *layout = new QGridLayout();
-    msgBox.setLayout(layout);
-    QLabel *tableView = new QLabel(&msgBox);
-    layout->addWidget(tableView, 1, 1);
-    QLabel *titel = new QLabel(&msgBox);
-    titel->setText("<b>Reprojection error for extrinsic calibration:</b>");
-    layout->addWidget(titel, 0, 1);
-
-    if(!mMainWindow->getExtrCalibration()->getReprojectionError().isValid())
-    {
-        out = QString("No File for extrinsic calibration found!");
-        tableView->setText(out);
-    }
-    else
-    {
-        out                    = QString("<table>"
-                                         "<tr><th></th>"
-                                         "<th>average   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>"
-                                         "<th>std. deviation                          &nbsp;</th>"
-                                         "<th>variance  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>"
-                                         "<th>max       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th></tr>"
-                                         "<tr><td>Point   height: &nbsp;&nbsp;            </td><td> %0 cm</td><td> %1 cm</td><td> %2 "
-                                         "cm</td><td> %3 cm</td></tr>"
-                                         "<tr><td>Default height: <small>[%12 cm]</small> </td><td> %4 cm</td><td> %5 cm</td><td> %6 "
-                                         "cm</td><td> %7 cm</td></tr>"
-                                         "<tr><td>Pixel    error: &nbsp;&nbsp;            </td><td> %8 px</td><td> %9 px</td><td> %10 "
-                                         "px</td><td> %11 px</td></tr>"
-                                         "</table>");
-        const auto &reproError = mMainWindow->getExtrCalibration()->getReprojectionError().getData();
-        for(double value : reproError)
-        {
-            if(value < 0)
-            {
-                out = out.arg("-");
-            }
-            else
-            {
-                out = out.arg(value);
-            }
-        }
-        tableView->setText(out);
-    }
-
-    msgBox.setWindowTitle("PeTrack");
-    QIcon   icon     = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
-    QLabel *infoIcon = new QLabel(&msgBox);
-    int     iconSize = msgBox.style()->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, &msgBox);
-    infoIcon->setPixmap(icon.pixmap(iconSize, iconSize));
-    layout->addWidget(infoIcon, 0, 0);
-    QDialogButtonBox *ok = new QDialogButtonBox(QDialogButtonBox::Ok);
-    layout->addWidget(ok, 2, 1);
-    connect(ok, &QDialogButtonBox::clicked, &msgBox, &QDialog::close);
-    msgBox.setFixedSize(msgBox.sizeHint());
-    msgBox.exec();
-}
 
 void Control::on_extVanishPointsShow_stateChanged(int /*arg1*/)
 {
@@ -2052,73 +1897,7 @@ void Control::on_extVanishPointsShow_stateChanged(int /*arg1*/)
         mScene->update();
     }
 }
-void Control::on_coordLoad3DCalibPoints_clicked()
-{
-    mMainWindow->getExtrCalibration()->openExtrCalibFile();
-
-    mMainWindow->updateCoord();
-    mScene->update();
-}
-
-void Control::on_extrCalibSave_clicked()
-{
-    mMainWindow->getExtrCalibration()->saveExtrCalibPoints();
-}
-
-void Control::on_extrCalibFetch_clicked()
-{
-    mMainWindow->getExtrCalibration()->fetch2DPoints();
-}
-
-void Control::on_extrCalibShowPoints_clicked()
-{
-    QString     out_str;
-    QTextStream out(&out_str);
 
-    unsigned int i;
-
-    out << "<table><tr><th>Nr.</th><th>3D.x</th><th>3D.y</th><th>3D.z</th><th>2D.x</th><th>2D.y</th></tr>" << Qt::endl;
-
-
-    for(i = 0; i < std::max(
-                       mMainWindow->getExtrCalibration()->get3DList().size(),
-                       mMainWindow->getExtrCalibration()->get2DList().size());
-        ++i)
-    {
-        out << "<tr>";
-        if(i < mMainWindow->getExtrCalibration()->get3DList().size())
-        {
-            out << "<td>[" << QString::number(i + 1, 'i', 0) << "]: </td><td>"
-                << QString::number(mMainWindow->getExtrCalibration()->get3DList().at(i).x, 'f', 1) << "</td><td>"
-                << QString::number(mMainWindow->getExtrCalibration()->get3DList().at(i).y, 'f', 1) << "</td><td>"
-                << QString::number(mMainWindow->getExtrCalibration()->get3DList().at(i).z, 'f', 1) << "</td><td>";
-        }
-        else
-        {
-            out << "<td>-</td><td>-</td><td>-</td>";
-        }
-        if(i < mMainWindow->getExtrCalibration()->get2DList().size())
-        {
-            out << QString::number(mMainWindow->getExtrCalibration()->get2DList().at(i).x, 'f', 3) << "</td><td>"
-                << QString::number(mMainWindow->getExtrCalibration()->get2DList().at(i).y, 'f', 3) << "</td>";
-        }
-        else
-        {
-            out << "<td>-</td><td>-</td>";
-        }
-        out << "</tr>" << Qt::endl;
-    }
-    out << "</table>" << Qt::endl;
-
-    QMessageBox msgBox;
-    msgBox.setWindowTitle("PeTrack");
-    msgBox.setIcon(QMessageBox::Information);
-    msgBox.setText("Currently loaded point correspondences<br />for extrinsic calibration:");
-    msgBox.setInformativeText(out_str);
-    msgBox.setStandardButtons(QMessageBox::Ok);
-    msgBox.setDefaultButton(QMessageBox::Ok);
-    msgBox.exec();
-}
 
 //---------------------------------------
 void Control::on_gridTab_currentChanged(int /*index*/)
@@ -2193,13 +1972,13 @@ void Control::on_coordTab_currentChanged(int index)
 {
     if(index == 1)
     {
-        setEnabledExtrParams(false);
+        mExtr->setEnabledExtrParams(false);
         mUi->trackShowGroundPosition->setEnabled(false);
         mUi->trackShowGroundPath->setEnabled(false);
     }
     else
     {
-        setEnabledExtrParams(true);
+        mExtr->setEnabledExtrParams(true);
         mUi->trackShowGroundPosition->setEnabled(true);
         mUi->trackShowGroundPath->setEnabled(true);
     }
@@ -2378,14 +2157,8 @@ void Control::setXml(QDomElement &elem)
     // PATTERN and INTRINSIC_PARAMETERS elements
     mIntr->setXml(subElem);
 
-    subSubElem = (elem.ownerDocument()).createElement("EXTRINSIC_PARAMETERS");
-
-    subSubElem.setAttribute("EXTR_ROT_1", mUi->rot1->value());
-    subSubElem.setAttribute("EXTR_ROT_2", mUi->rot2->value());
-    subSubElem.setAttribute("EXTR_ROT_3", mUi->rot3->value());
-    subSubElem.setAttribute("EXTR_TRANS_1", mUi->trans1->value());
-    subSubElem.setAttribute("EXTR_TRANS_2", mUi->trans2->value());
-    subSubElem.setAttribute("EXTR_TRANS_3", mUi->trans3->value());
+    subSubElem = (subElem.ownerDocument()).createElement("EXTRINSIC_PARAMETERS");
+    mExtr->setXml(subSubElem);
 
     subSubElem.setAttribute("SHOW_CALIB_POINTS", mUi->extCalibPointsShow->isChecked());
 
@@ -2688,7 +2461,7 @@ void Control::setXml(QDomElement &elem)
 }
 
 // read data from xml node
-void Control::getXml(QDomElement &elem)
+void Control::getXml(const QDomElement &elem)
 {
     QDomElement subElem, subSubElem, subSubSubElem;
 
@@ -2711,6 +2484,10 @@ void Control::getXml(QDomElement &elem)
                 {
                     // intentionally left blank
                 }
+                else if(mExtr->getXml(subSubElem))
+                {
+                    // intentionally left blank
+                }
                 else if(subSubElem.tagName() == "BORDER")
                 {
                     if(subSubElem.hasAttribute("COLOR"))
@@ -2742,30 +2519,6 @@ void Control::getXml(QDomElement &elem)
                 }
                 else if(subSubElem.tagName() == "EXTRINSIC_PARAMETERS")
                 {
-                    if(subSubElem.hasAttribute("EXTR_ROT_1"))
-                    {
-                        mUi->rot1->setValue(subSubElem.attribute("EXTR_ROT_1").toDouble());
-                    }
-                    if(subSubElem.hasAttribute("EXTR_ROT_2"))
-                    {
-                        mUi->rot2->setValue(subSubElem.attribute("EXTR_ROT_2").toDouble());
-                    }
-                    if(subSubElem.hasAttribute("EXTR_ROT_3"))
-                    {
-                        mUi->rot3->setValue(subSubElem.attribute("EXTR_ROT_3").toDouble());
-                    }
-                    if(subSubElem.hasAttribute("EXTR_TRANS_1"))
-                    {
-                        mUi->trans1->setValue(subSubElem.attribute("EXTR_TRANS_1").toDouble());
-                    }
-                    if(subSubElem.hasAttribute("EXTR_TRANS_2"))
-                    {
-                        mUi->trans2->setValue(subSubElem.attribute("EXTR_TRANS_2").toDouble());
-                    }
-                    if(subSubElem.hasAttribute("EXTR_TRANS_3"))
-                    {
-                        mUi->trans3->setValue(subSubElem.attribute("EXTR_TRANS_3").toDouble());
-                    }
                     if(subSubElem.hasAttribute("SHOW_CALIB_POINTS"))
                     {
                         mUi->extCalibPointsShow->setCheckState(
@@ -2779,19 +2532,7 @@ void Control::getXml(QDomElement &elem)
                     else
                     {
                         mUi->coordTab->setCurrentIndex(1); //  = 2D
-                        setEnabledExtrParams(false);
-                    }
-                    if(subSubElem.hasAttribute("EXTERNAL_CALIB_FILE"))
-                    {
-                        if(getExistingFile(
-                               QString::fromStdString(subSubElem.attribute("EXTERNAL_CALIB_FILE").toStdString()),
-                               mMainWindow->getProFileName()) != "")
-                        {
-                            mMainWindow->getExtrCalibration()->setExtrCalibFile(getExistingFile(
-                                QString::fromStdString(subSubElem.attribute("EXTERNAL_CALIB_FILE").toStdString()),
-                                mMainWindow->getProFileName()));
-                            mMainWindow->getExtrCalibration()->loadExtrCalibFile();
-                        }
+                        mExtr->setEnabledExtrParams(false);
                     }
 
                     if(subSubElem.hasAttribute("SHOW"))
diff --git a/src/extrCalibration.cpp b/src/extrCalibration.cpp
index 2706e6f1f..badbc37fe 100644
--- a/src/extrCalibration.cpp
+++ b/src/extrCalibration.cpp
@@ -75,7 +75,7 @@ QString ExtrCalibration::getExtrCalibFile()
     }
 }
 
-bool ExtrCalibration::openExtrCalibFile()
+std::optional<ExtrinsicParameters> ExtrCalibration::openExtrCalibFile()
 {
     if(mMainWindow)
     {
@@ -97,7 +97,7 @@ bool ExtrCalibration::openExtrCalibFile()
             return loadExtrCalibFile();
         }
     }
-    return false;
+    return std::nullopt;
 }
 
 // following function copied from OpenCV
@@ -152,195 +152,190 @@ static bool isPlanarObjectPoints(cv::InputArray _objectPoints, double threshold
  *
  * @return
  */
-bool ExtrCalibration::loadExtrCalibFile()
+std::optional<ExtrinsicParameters> ExtrCalibration::loadExtrCalibFile()
 {
-    bool all_ok = true;
+    if(mExtrCalibFile.isEmpty())
+    {
+        return std::nullopt;
+    }
 
-    if(!mExtrCalibFile.isEmpty())
+    if(mExtrCalibFile.right(4) != ".3dc" && mExtrCalibFile.right(4) != ".txt")
     {
-        if(mExtrCalibFile.right(4) == ".3dc" || mExtrCalibFile.right(4) == ".txt")
-        {
-            QFile file(mExtrCalibFile);
-            if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
-            {
-                PCritical(
-                    mMainWindow,
-                    QObject::tr("Petrack"),
-                    QObject::tr("Error: Cannot open %1:\n%2.").arg(mExtrCalibFile, file.errorString()));
-                return false;
-            }
+        PWarning(nullptr, "Unsupported File Type", "Unsupported file extension (supported: .3dc, .txt)");
+        return std::nullopt;
+    }
+
+    QFile file(mExtrCalibFile);
+    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
+        PCritical(
+            mMainWindow,
+            QObject::tr("Petrack"),
+            QObject::tr("Error: Cannot open %1:\n%2.").arg(mExtrCalibFile, file.errorString()));
+        return std::nullopt;
+    }
+
+    SPDLOG_INFO("Reading 3D calibration data from {} ...", mExtrCalibFile);
+
+    std::vector<cv::Point3f> points3D_tmp;
+    std::vector<cv::Point2f> points2D_tmp;
 
-            SPDLOG_INFO("Reading 3D calibration data from {} ...", mExtrCalibFile);
+    QTextStream in(&file);
+    QString     line;
+    int         line_counter = 0, counter;
+    float       x, y, z, px, py;
+    float       zahl;
+    bool        with_2D_data = false, with_3D_data = false, end_loop = false;
 
-            std::vector<cv::Point3f> points3D_tmp;
-            std::vector<cv::Point2f> points2D_tmp;
+    // Exit loop when reaching the end of the file
+    while(!in.atEnd())
+    {
+        // Neue Zeile einlesen
+        line = in.readLine();
+        ++line_counter;
+
+        // Kommentare ueberlesen
+        if(line.startsWith("#", Qt::CaseInsensitive) || line.startsWith(";;", Qt::CaseInsensitive) ||
+           line.startsWith("//", Qt::CaseInsensitive) || line.startsWith("!", Qt::CaseInsensitive))
+        {
+            continue;
+        }
 
-            QTextStream in(&file);
-            QString     line;
-            int         line_counter = 0, counter;
-            float       x, y, z, px, py;
-            float       zahl;
-            bool        with_2D_data = false, with_3D_data = false, end_loop = false;
+        QTextStream stream(&line);
+        counter  = 0;
+        end_loop = false;
 
-            // Exit loop when reaching the end of the file
-            while(!in.atEnd())
+        while(!stream.atEnd() && !end_loop)
+        {
+            stream >> zahl;
+            ++counter;
+
+            switch(counter)
             {
-                // Neue Zeile einlesen
-                line = in.readLine();
-                ++line_counter;
-
-                // Kommentare ueberlesen
-                if(line.startsWith("#", Qt::CaseInsensitive) || line.startsWith(";;", Qt::CaseInsensitive) ||
-                   line.startsWith("//", Qt::CaseInsensitive) || line.startsWith("!", Qt::CaseInsensitive))
-                {
-                    continue;
-                }
-
-                QTextStream stream(&line);
-                counter  = 0;
-                end_loop = false;
-
-                while(!stream.atEnd() && !end_loop)
-                {
-                    stream >> zahl;
-                    ++counter;
-
-                    switch(counter)
+                case 1:
+                    x = zahl;
+                    if(!with_3D_data)
                     {
-                        case 1:
-                            x = zahl;
-                            if(!with_3D_data)
-                            {
-                                points3D_tmp.clear();
-                                with_3D_data = true;
-                            }
-                            break;
-                        case 2:
-                            y = zahl;
-                            break;
-                        case 3:
-                            z = zahl;
-                            break;
-                        case 4:
-                            px = zahl;
-                            if(!with_2D_data)
-                            {
-                                points2D_tmp.clear();
-                                with_2D_data = true;
-                            }
-                            break;
-                        case 5:
-                            py = zahl;
-                            break;
-                        default:
-                            end_loop = true;
+                        points3D_tmp.clear();
+                        with_3D_data = true;
                     }
-                }
-                if(counter == 1)
-                {
-                    SPDLOG_INFO("Optional number of points in line {} ignored.", line_counter);
-                }
-                else if(counter != 3 && counter != 5)
-                {
-                    SPDLOG_INFO("Something wrong in line {} ({})! Ignored. (counter={})", line_counter, line, counter);
-                }
-
-                // 3D daten abspeichern
-                if(with_3D_data && (counter == 3 || counter == 5))
-                {
-                    points3D_tmp.push_back(cv::Point3f(x, y, z));
-                }
-                // 2D daten abspeichern
-                if(with_2D_data && counter == 5)
-                {
-                    points2D_tmp.push_back(cv::Point2f(px, py));
-                }
-            }
-            // Check if there are more than 4 points for calibration in the file
-            if(points3D_tmp.size() < 4)
-            {
-                PCritical(
-                    mMainWindow,
-                    QObject::tr("PeTrack"),
-                    QObject::tr("Error: Not enough points given: %1 (minimum 4 (coplanar) or 6 (not coplanar) "
-                                "needed!). Please check your extrinsic "
-                                "calibration file!")
-                        .arg(points3D_tmp.size()));
-                all_ok = false;
-            }
-            else if(!isPlanarObjectPoints(points3D_tmp) && points3D_tmp.size() < 6)
-            {
-                // Non-planar points use DLT - we need at least 6 points; not only 4
-                PCritical(
-                    mMainWindow,
-                    QObject::tr("PeTrack"),
-                    QObject::tr("Error: Not enough points given: %1 (minimum 4 (coplanar) or 6 (not coplanar) "
-                                "needed!). Please check your extrinsic "
-                                "calibration file!")
-                        .arg(points3D_tmp.size()));
-                all_ok = false;
-            }
-            // Check if 2D points delivered and if the number of 2D and 3D points agree
-            else if(points2D_tmp.size() > 0 && points2D_tmp.size() != points3D_tmp.size())
-            {
-                PCritical(
-                    mMainWindow,
-                    QObject::tr("PeTrack"),
-                    QObject::tr(
-                        "Error: Unsupported File Format in: %1 (number of 3D (%2) and 2D (%3) points disagree!)")
-                        .arg(mExtrCalibFile)
-                        .arg(points3D_tmp.size())
-                        .arg(points2D_tmp.size()));
-                all_ok = false;
-            }
-            // Check if number of loaded 3D points agree with stored 2D points
-            else if(!with_2D_data && points2D.size() > 0 && points3D_tmp.size() != points2D.size())
-            {
-                // ask if stored 2D points should be deleted?
-                int result = PWarning(
-                    mMainWindow,
-                    QObject::tr("PeTrack"),
-                    QObject::tr("Number of 3D points (%1) disagree with number of stored 2D points (%2)!<br />The 2D "
-                                "points will be deleted! You have to fetch new ones from the image!")
-                        .arg(points3D_tmp.size())
-                        .arg(points2D.size()),
-                    PMessageBox::StandardButton::Ok | PMessageBox::StandardButton::Abort);
-                if(result != PMessageBox::StandardButton::Ok)
-                {
-                    all_ok = false;
-                }
-                else
-                {
-                    points2D.clear();
-                }
-            }
-            if(all_ok)
-            {
-                if(with_3D_data)
-                {
-                    points3D = points3D_tmp;
-                }
-                if(with_2D_data)
-                {
-                    points2D = points2D_tmp;
-                }
+                    break;
+                case 2:
+                    y = zahl;
+                    break;
+                case 3:
+                    z = zahl;
+                    break;
+                case 4:
+                    px = zahl;
+                    if(!with_2D_data)
+                    {
+                        points2D_tmp.clear();
+                        with_2D_data = true;
+                    }
+                    break;
+                case 5:
+                    py = zahl;
+                    break;
+                default:
+                    end_loop = true;
             }
         }
+        if(counter == 1)
+        {
+            SPDLOG_INFO("Optional number of points in line {} ignored.", line_counter);
+        }
+        else if(counter != 3 && counter != 5)
+        {
+            SPDLOG_INFO("Something wrong in line {} ({})! Ignored. (counter={})", line_counter, line, counter);
+        }
+
+        // 3D daten abspeichern
+        if(with_3D_data && (counter == 3 || counter == 5))
+        {
+            points3D_tmp.push_back(cv::Point3f(x, y, z));
+        }
+        // 2D daten abspeichern
+        if(with_2D_data && counter == 5)
+        {
+            points2D_tmp.push_back(cv::Point2f(px, py));
+        }
+    }
+    // Check if there are more than 4 points for calibration in the file
+    if(points3D_tmp.size() < 4)
+    {
+        PCritical(
+            mMainWindow,
+            QObject::tr("PeTrack"),
+            QObject::tr("Error: Not enough points given: %1 (minimum 4 (coplanar) or 6 (not coplanar) "
+                        "needed!). Please check your extrinsic "
+                        "calibration file!")
+                .arg(points3D_tmp.size()));
+        return std::nullopt;
+    }
+
+    // Non-planar points use DLT - we need at least 6 points; not only 4
+    if(!isPlanarObjectPoints(points3D_tmp) && points3D_tmp.size() < 6)
+    {
+        PCritical(
+            mMainWindow,
+            QObject::tr("PeTrack"),
+            QObject::tr("Error: Not enough points given: %1 (minimum 4 (coplanar) or 6 (not coplanar) "
+                        "needed!). Please check your extrinsic "
+                        "calibration file!")
+                .arg(points3D_tmp.size()));
+        return std::nullopt;
+    }
+
+    // Check if 2D points delivered and if the number of 2D and 3D points agree
+    if(points2D_tmp.size() > 0 && points2D_tmp.size() != points3D_tmp.size())
+    {
+        PCritical(
+            mMainWindow,
+            QObject::tr("PeTrack"),
+            QObject::tr("Error: Unsupported File Format in: %1 (number of 3D (%2) and 2D (%3) points disagree!)")
+                .arg(mExtrCalibFile)
+                .arg(points3D_tmp.size())
+                .arg(points2D_tmp.size()));
+        return std::nullopt;
+    }
+
+    // Check if number of loaded 3D points agree with stored 2D points
+    if(!with_2D_data && points2D.size() > 0 && points3D_tmp.size() != points2D.size())
+    {
+        // ask if stored 2D points should be deleted?
+        int result = PWarning(
+            mMainWindow,
+            QObject::tr("PeTrack"),
+            QObject::tr("Number of 3D points (%1) disagree with number of stored 2D points (%2)!<br />The 2D "
+                        "points will be deleted! You have to fetch new ones from the image!")
+                .arg(points3D_tmp.size())
+                .arg(points2D.size()),
+            PMessageBox::StandardButton::Ok | PMessageBox::StandardButton::Abort);
+        if(result != PMessageBox::StandardButton::Ok)
+        {
+            return std::nullopt;
+        }
         else
         {
-            SPDLOG_WARN("unsupported file extension (supported: .3dc, .txt)");
+            points2D.clear();
         }
     }
-    else
+
+    if(with_3D_data)
     {
-        // no calib_file
-        all_ok = false;
+        points3D = points3D_tmp;
     }
-    if(all_ok && !mMainWindow->isLoading())
+    if(with_2D_data)
     {
-        calibExtrParams();
+        points2D = points2D_tmp;
     }
-    return all_ok;
+
+    if(!mMainWindow->isLoading())
+    {
+        return calibExtrParams();
+    }
+    return std::nullopt;
 }
 
 /**
@@ -350,49 +345,37 @@ bool ExtrCalibration::loadExtrCalibFile()
  *
  * @return true if calibration did take place
  */
-bool ExtrCalibration::fetch2DPoints()
+std::optional<ExtrinsicParameters> ExtrCalibration::fetch2DPoints()
 {
-    bool all_ok = true;
     if(!mMainWindow->getTracker() || mPersonStorage.nbPersons() < 4)
     {
         PCritical(
             mMainWindow,
             QObject::tr("Petrack"),
             QObject::tr("Error: At minimum four 3D calibration points needed for 3D calibration."));
-        all_ok = false;
+        return std::nullopt;
     }
-    else
-    {
-        size_t sz_2d = mPersonStorage.nbPersons();
 
-        if(points3D.size() > 0 && sz_2d != points3D.size())
-        {
-            PCritical(
-                mMainWindow,
-                QObject::tr("Petrack"),
-                QObject::tr("Count of 2D-Points (%1) and 3D-Points (%2) disagree").arg(sz_2d).arg(points3D.size()));
-            all_ok = false;
-        }
-        // debout << "Marked 2D-Image-Points: " << endl;
-        if(all_ok)
-        {
-            points2D.clear();
+    size_t sz_2d = mPersonStorage.nbPersons();
 
-            for(int i = 0; i < static_cast<int>(sz_2d); i++)
-            {
-                // debout << "[" << i << "]: (" << mMainWindow->getTracker()->at(i).at(0).x() << ", " <<
-                // mMainWindow->getTracker()->at(i).at(0).y() << ")" << endl;
-                //  Info: Tracker->TrackPerson->TrackPoint->Vec2F
-                points2D.push_back(cv::Point2f(mPersonStorage.at(i).at(0).x(), mPersonStorage.at(i).at(0).y()));
-            }
-        }
+    if(points3D.size() > 0 && sz_2d != points3D.size())
+    {
+        PCritical(
+            mMainWindow,
+            QObject::tr("Petrack"),
+            QObject::tr("Count of 2D-Points (%1) and 3D-Points (%2) disagree").arg(sz_2d).arg(points3D.size()));
+        return std::nullopt;
     }
-    if(all_ok)
+
+    points2D.clear();
+    for(int i = 0; i < static_cast<int>(sz_2d); i++)
     {
-        mPersonStorage.clear();
-        calibExtrParams();
+        //  Info: Tracker->TrackPerson->TrackPoint->Vec2F
+        points2D.push_back(cv::Point2f(mPersonStorage.at(i).at(0).x(), mPersonStorage.at(i).at(0).y()));
     }
-    return all_ok;
+
+    mPersonStorage.clear();
+    return calibExtrParams();
 }
 
 /**
@@ -483,123 +466,122 @@ bool ExtrCalibration::isSetExtrCalib()
 /**
  * @brief Extrinsic calibration with help of cv::solvePnP
  */
-void ExtrCalibration::calibExtrParams()
+std::optional<ExtrinsicParameters> ExtrCalibration::calibExtrParams()
 {
-    if(!points3D.empty() && !points2D.empty() && points2D.size() == points3D.size())
+    if(points3D.empty() || points2D.empty() || points2D.size() != points3D.size())
     {
-        int bS = mMainWindow->getImageBorderSize();
-        /* Create Camera-Matrix form Camera-Params in the Petrack-GUI */
-        cv::Mat camMat = mControlWidget->getIntrinsicCameraParams().cameraMatrix;
-        camMat.at<double>(0, 2) -= bS;
-        camMat.at<double>(1, 2) -= bS;
-
-        cv::Mat distMat = cv::Mat::zeros(cv::Size(8, 1), CV_64F);
-
-        /* Create Mat-objects of point correspondences */
-        cv::Mat op(points3D);
-        cv::Mat ip(points2D);
-
-        /* Mat-objects for result rotation and translation vectors */
-        cv::Mat rvec(3, 1, CV_64F), /*,0),*/ tvec(3, 1, CV_64F); //,0);
-
-        // Solve the PnP-Problem to calibrate the camera to its environment
-
-        cv::solvePnP(op, ip, camMat, distMat, rvec, tvec, false, cv::SOLVEPNP_ITERATIVE);
-
-        cv::Mat rot_mat(3, 3, CV_64F); //, 0);
-        // Transform the rotation vector into a rotation matrix with opencvs rodrigues method
-        Rodrigues(rvec, rot_mat);
-
-        rotation_matrix[0] = rot_mat.at<double>(0, 0);
-        rotation_matrix[1] = rot_mat.at<double>(0, 1);
-        rotation_matrix[2] = rot_mat.at<double>(0, 2);
-        rotation_matrix[3] = rot_mat.at<double>(1, 0);
-        rotation_matrix[4] = rot_mat.at<double>(1, 1);
-        rotation_matrix[5] = rot_mat.at<double>(1, 2);
-        rotation_matrix[6] = rot_mat.at<double>(2, 0);
-        rotation_matrix[7] = rot_mat.at<double>(2, 1);
-        rotation_matrix[8] = rot_mat.at<double>(2, 2);
-
-        translation_vector[0] = tvec.at<double>(0, 0);
-        translation_vector[1] = tvec.at<double>(0, 1);
-        translation_vector[2] = tvec.at<double>(0, 2);
-
-        translation_vector2[0] = rotation_matrix[0] * translation_vector[0] +
-                                 rotation_matrix[3] * translation_vector[1] +
-                                 rotation_matrix[6] * translation_vector[2];
-        translation_vector2[1] = rotation_matrix[1] * translation_vector[0] +
-                                 rotation_matrix[4] * translation_vector[1] +
-                                 rotation_matrix[7] * translation_vector[2];
-        translation_vector2[2] = rotation_matrix[2] * translation_vector[0] +
-                                 rotation_matrix[5] * translation_vector[1] +
-                                 rotation_matrix[8] * translation_vector[2];
-
-        SPDLOG_INFO("-.- ESTIMATED ROTATION -.-");
-        for(size_t p = 0; p < 3; p++)
-        {
-            SPDLOG_INFO("{}, {}, {}", rotation_matrix[p * 3], rotation_matrix[p * 3 + 1], rotation_matrix[p * 3] + 2);
-        }
-        SPDLOG_INFO("-.- ESTIMATED TRANSLATION -.-");
-        SPDLOG_INFO("{}, {}, {}", translation_vector[0], translation_vector[1], translation_vector[2]);
+        QString msg = QString{"Invalid point correspondences for camera calibration\n"
+                              "2D points: %1, 3D points %2"}
+                          .arg(points2D.size())
+                          .arg(points3D.size());
+        PWarning(nullptr, "Invalid point correspondences", msg);
+        return std::nullopt;
+    }
 
-        SPDLOG_INFO("-.- Translation vector -.-");
-        SPDLOG_INFO("{}, {}, {}", translation_vector2[0], translation_vector2[1], translation_vector2[2]);
+    int bS = mMainWindow->getImageBorderSize();
+    /* Create Camera-Matrix form Camera-Params in the Petrack-GUI */
+    cv::Mat camMat = mControlWidget->getIntrinsicCameraParams().cameraMatrix;
+    camMat.at<double>(0, 2) -= bS;
+    camMat.at<double>(1, 2) -= bS;
 
-        SPDLOG_INFO("-.- Rotation vector -.-");
-        SPDLOG_INFO("{}, {}, {}", rvec.at<double>(0, 0), rvec.at<double>(1, 0), rvec.at<double>(2, 0));
+    cv::Mat distMat = cv::Mat::zeros(cv::Size(8, 1), CV_64F);
 
-        camHeight = translation_vector2[2] < 0 ? -translation_vector2[2] : translation_vector2[2];
+    /* Create Mat-objects of point correspondences */
+    cv::Mat op(points3D);
+    cv::Mat ip(points2D);
 
-        mControlWidget->setCalibExtrRot1(rvec.at<double>(0, 0));
-        mControlWidget->setCalibExtrRot2(rvec.at<double>(1, 0));
-        mControlWidget->setCalibExtrRot3(rvec.at<double>(2, 0));
+    /* Mat-objects for result rotation and translation vectors */
+    cv::Mat rvec(3, 1, CV_64F), /*,0),*/ tvec(3, 1, CV_64F); //,0);
 
-        mControlWidget->setCalibExtrTrans1(translation_vector2[0]);
-        mControlWidget->setCalibExtrTrans2(translation_vector2[1]);
-        mControlWidget->setCalibExtrTrans3(translation_vector2[2]);
+    // Solve the PnP-Problem to calibrate the camera to its environment
+    cv::solvePnP(op, ip, camMat, distMat, rvec, tvec, false, cv::SOLVEPNP_ITERATIVE);
 
-        if(!calcReprojectionError())
-        {
-            SPDLOG_WARN("Extrinsic calibration not possible! Please select other 2D/3D points!");
-            mControlWidget->setCalibExtrRot1(0);
-            mControlWidget->setCalibExtrRot2(0);
-            mControlWidget->setCalibExtrRot3(0);
+    cv::Mat rot_mat(3, 3, CV_64F); //, 0);
+    // Transform the rotation vector into a rotation matrix with opencvs rodrigues method
+    Rodrigues(rvec, rot_mat);
 
-            translation_vector2[0] = 0;
-            translation_vector2[1] = 0;
-            translation_vector2[2] = 0;
+    rotation_matrix[0] = rot_mat.at<double>(0, 0);
+    rotation_matrix[1] = rot_mat.at<double>(0, 1);
+    rotation_matrix[2] = rot_mat.at<double>(0, 2);
+    rotation_matrix[3] = rot_mat.at<double>(1, 0);
+    rotation_matrix[4] = rot_mat.at<double>(1, 1);
+    rotation_matrix[5] = rot_mat.at<double>(1, 2);
+    rotation_matrix[6] = rot_mat.at<double>(2, 0);
+    rotation_matrix[7] = rot_mat.at<double>(2, 1);
+    rotation_matrix[8] = rot_mat.at<double>(2, 2);
+
+    translation_vector[0] = tvec.at<double>(0, 0);
+    translation_vector[1] = tvec.at<double>(0, 1);
+    translation_vector[2] = tvec.at<double>(0, 2);
+
+    translation_vector2[0] = rotation_matrix[0] * translation_vector[0] + rotation_matrix[3] * translation_vector[1] +
+                             rotation_matrix[6] * translation_vector[2];
+    translation_vector2[1] = rotation_matrix[1] * translation_vector[0] + rotation_matrix[4] * translation_vector[1] +
+                             rotation_matrix[7] * translation_vector[2];
+    translation_vector2[2] = rotation_matrix[2] * translation_vector[0] + rotation_matrix[5] * translation_vector[1] +
+                             rotation_matrix[8] * translation_vector[2];
+
+    SPDLOG_INFO("-.- ESTIMATED ROTATION -.-");
+    for(size_t p = 0; p < 3; p++)
+    {
+        SPDLOG_INFO("{}, {}, {}", rotation_matrix[p * 3], rotation_matrix[p * 3 + 1], rotation_matrix[p * 3] + 2);
+    }
+    SPDLOG_INFO("-.- ESTIMATED TRANSLATION -.-");
+    SPDLOG_INFO("{}, {}, {}", translation_vector[0], translation_vector[1], translation_vector[2]);
 
-            rotation_matrix[0] = 0;
-            rotation_matrix[1] = 0;
-            rotation_matrix[2] = 0;
+    SPDLOG_INFO("-.- Translation vector -.-");
+    SPDLOG_INFO("{}, {}, {}", translation_vector2[0], translation_vector2[1], translation_vector2[2]);
 
-            mControlWidget->setCalibExtrTrans1(translation_vector2[0]);
-            mControlWidget->setCalibExtrTrans2(translation_vector2[1]);
-            mControlWidget->setCalibExtrTrans3(translation_vector2[2]);
+    SPDLOG_INFO("-.- Rotation vector -.-");
+    SPDLOG_INFO("{}, {}, {}", rvec.at<double>(0, 0), rvec.at<double>(1, 0), rvec.at<double>(2, 0));
 
-            reprojectionError = ReprojectionError{};
+    camHeight = translation_vector2[2] < 0 ? -translation_vector2[2] : translation_vector2[2];
 
-            PCritical(
-                mMainWindow,
-                QObject::tr("Petrack"),
-                QObject::tr("Error: Could not calculate extrinsic calibration. Please select other 2D/3D point "
-                            "correspondences for extrinsic calibration!"));
+    ExtrinsicParameters results;
 
-            isExtCalib = false;
+    results.rot1 = rvec.at<double>(0, 0);
+    results.rot2 = rvec.at<double>(1, 0);
+    results.rot3 = rvec.at<double>(2, 0);
 
-            return;
-        }
+    results.trans1 = translation_vector2[0];
+    results.trans2 = translation_vector2[1];
+    results.trans3 = translation_vector2[2];
 
-        isExtCalib = true;
-
-        SPDLOG_INFO("End of extern calibration!");
-    }
-    else
+    if(!calcReprojectionError())
     {
-        std::cerr << "# Warning: invalid point correspondences for camera calibration." << std::endl;
-        std::cerr << "# 2D points:" << points2D.size() << ", 3D points: " << points3D.size() << std::endl;
+        SPDLOG_WARN("Extrinsic calibration not possible! Please select other 2D/3D points!");
+        results.rot1 = 0;
+        results.rot2 = 0;
+        results.rot3 = 0;
+
+        translation_vector2[0] = 0;
+        translation_vector2[1] = 0;
+        translation_vector2[2] = 0;
+
+        rotation_matrix[0] = 0;
+        rotation_matrix[1] = 0;
+        rotation_matrix[2] = 0;
+
+        results.trans1 = translation_vector2[0];
+        results.trans2 = translation_vector2[1];
+        results.trans3 = translation_vector2[2];
+
+        reprojectionError = ReprojectionError{};
+
+        PCritical(
+            mMainWindow,
+            QObject::tr("Petrack"),
+            QObject::tr("Error: Could not calculate extrinsic calibration. Please select other 2D/3D point "
+                        "correspondences for extrinsic calibration!"));
+
+        isExtCalib = false;
+        return results;
     }
+
+    isExtCalib = true;
+    SPDLOG_INFO("End of extern calibration!");
     mMainWindow->getScene()->update();
+    return results;
 }
 
 /**
@@ -779,11 +761,12 @@ cv::Point2f ExtrCalibration::getImagePoint(cv::Point3f p3d)
     // ToDo: use projectPoints();
     int bS = mMainWindow->getImage() ? mMainWindow->getImageBorderSize() : 0;
 
-    double rvec_array[3], translation_vector[3];
+    double      rvec_array[3], translation_vector[3];
+    const auto &extrParams = mControlWidget->getExtrinsicParameters();
 
-    rvec_array[0] = mControlWidget->getCalibExtrRot1();
-    rvec_array[1] = mControlWidget->getCalibExtrRot2();
-    rvec_array[2] = mControlWidget->getCalibExtrRot3();
+    rvec_array[0] = extrParams.rot1;
+    rvec_array[1] = extrParams.rot2;
+    rvec_array[2] = extrParams.rot3;
 
     cv::Mat rvec(3, 1, CV_64F, rvec_array), rot_inv;
     cv::Mat rot_mat(3, 3, CV_64F), e(3, 3, CV_64F);
@@ -795,15 +778,12 @@ cv::Point2f ExtrCalibration::getImagePoint(cv::Point3f p3d)
 
     e = rot_inv * rot_mat;
 
-    translation_vector[0] = rot_mat.at<double>(0, 0) * mControlWidget->getCalibExtrTrans1() +
-                            rot_mat.at<double>(0, 1) * mControlWidget->getCalibExtrTrans2() +
-                            rot_mat.at<double>(0, 2) * mControlWidget->getCalibExtrTrans3();
-    translation_vector[1] = rot_mat.at<double>(1, 0) * mControlWidget->getCalibExtrTrans1() +
-                            rot_mat.at<double>(1, 1) * mControlWidget->getCalibExtrTrans2() +
-                            rot_mat.at<double>(1, 2) * mControlWidget->getCalibExtrTrans3();
-    translation_vector[2] = rot_mat.at<double>(2, 0) * mControlWidget->getCalibExtrTrans1() +
-                            rot_mat.at<double>(2, 1) * mControlWidget->getCalibExtrTrans2() +
-                            rot_mat.at<double>(2, 2) * mControlWidget->getCalibExtrTrans3();
+    translation_vector[0] = rot_mat.at<double>(0, 0) * extrParams.trans1 +
+                            rot_mat.at<double>(0, 1) * extrParams.trans2 + rot_mat.at<double>(0, 2) * extrParams.trans3;
+    translation_vector[1] = rot_mat.at<double>(1, 0) * extrParams.trans1 +
+                            rot_mat.at<double>(1, 1) * extrParams.trans2 + rot_mat.at<double>(1, 2) * extrParams.trans3;
+    translation_vector[2] = rot_mat.at<double>(2, 0) * extrParams.trans1 +
+                            rot_mat.at<double>(2, 1) * extrParams.trans2 + rot_mat.at<double>(2, 2) * extrParams.trans3;
 
     cv::Point3f point3D;
 
@@ -846,8 +826,8 @@ 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());
+    const auto            &extrParams = mControlWidget->getExtrinsicParameters();
+    const auto             rvec       = cv::Vec3d(extrParams.rot1, extrParams.rot2, extrParams.rot3);
     Rodrigues(rvec, rotMat);
 
     auto      rotInv   = rotMat.inv(cv::DECOMP_LU);
@@ -871,18 +851,13 @@ cv::Point3f ExtrCalibration::get3DPoint(const cv::Point2f &p2d, double h) const
     // Transform the rotation vector into a rotation matrix with opencvs rodrigues method
     cv::Matx<double, 3, 3> rot_inv;
     cv::Matx<double, 3, 3> rot_mat(3, 3, CV_64F);
-    const cv::Mat          rvec =
-        (cv::Mat_<double>(3, 1) << mControlWidget->getCalibExtrRot1(),
-         mControlWidget->getCalibExtrRot2(),
-         mControlWidget->getCalibExtrRot3());
+    const auto            &extrParams = mControlWidget->getExtrinsicParameters();
+    const cv::Mat          rvec       = (cv::Mat_<double>(3, 1) << extrParams.rot1, extrParams.rot2, extrParams.rot3);
     Rodrigues(rvec, rot_mat);
     rot_inv = rot_mat.inv(cv::DECOMP_LU, nullptr);
 
     // Create translation vector
-    cv::Vec3d translation{
-        mControlWidget->getCalibExtrTrans1(),
-        mControlWidget->getCalibExtrTrans2(),
-        mControlWidget->getCalibExtrTrans3()};
+    cv::Vec3d translation{extrParams.trans1, extrParams.trans2, extrParams.trans3};
 
     const auto camMat = mControlWidget->getIntrinsicCameraParams();
     const auto fx     = camMat.getFx();
diff --git a/src/extrinsicBox.cpp b/src/extrinsicBox.cpp
new file mode 100644
index 000000000..7d78de8b3
--- /dev/null
+++ b/src/extrinsicBox.cpp
@@ -0,0 +1,301 @@
+/*
+ * PeTrack - Software for tracking pedestrians movement in videos
+ * Copyright (C) 2023 Forschungszentrum Jülich GmbH, IAS-7
+ *
+ * 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 "extrinsicBox.h"
+
+#include "extrCalibration.h"
+#include "helper.h"
+#include "ui_extrinsicBox.h"
+
+#include <QDialogButtonBox>
+#include <QDomElement>
+#include <QMessageBox>
+#include <QStyle>
+#include <utility>
+
+ExtrinsicBox::ExtrinsicBox(
+    QWidget              *parent,
+    Ui::extr             *ui,
+    ExtrCalibration      &extrCalib,
+    std::function<void()> updateCoordCallback) :
+    QGroupBox(parent), mUi(ui), mExtrCalibration(extrCalib), mUpdateCoordCallback(std::move(updateCoordCallback))
+{
+    mUi->setupUi(this);
+    setFocusProxy(mUi->rot1);
+    // use default values from struct as default for UI
+    setExtrinsicParameters(mParams);
+}
+
+ExtrinsicBox::ExtrinsicBox(QWidget *parent, ExtrCalibration &extrCalib, std::function<void()> updateCoordCallback) :
+    ExtrinsicBox(parent, new Ui::extr, extrCalib, std::move(updateCoordCallback))
+{
+}
+
+void ExtrinsicBox::setEnabledExtrParams(bool enable)
+{
+    mUi->rot1->setEnabled(enable);
+    mUi->rot2->setEnabled(enable);
+    mUi->rot3->setEnabled(enable);
+    mUi->trans1->setEnabled(enable);
+    mUi->trans2->setEnabled(enable);
+    mUi->trans3->setEnabled(enable);
+}
+
+const ExtrinsicParameters &ExtrinsicBox::getExtrinsicParameters() const
+{
+    return mParams;
+}
+
+void ExtrinsicBox::setExtrinsicParameters(const ExtrinsicParameters &params)
+{
+    setValue(mUi->trans1, params.trans1);
+    setValue(mUi->trans2, params.trans2);
+    setValue(mUi->trans3, params.trans3);
+    setValue(mUi->rot1, params.rot1);
+    setValue(mUi->rot2, params.rot2);
+    setValue(mUi->rot3, params.rot3);
+}
+
+void ExtrinsicBox::on_extrCalibFetch_clicked()
+{
+    auto newCalib = mExtrCalibration.fetch2DPoints();
+    if(newCalib)
+    {
+        setExtrinsicParameters(*newCalib);
+    }
+}
+
+void ExtrinsicBox::on_coordLoad3DCalibPoints_clicked()
+{
+    auto newCalib = mExtrCalibration.openExtrCalibFile();
+    if(newCalib)
+    {
+        setExtrinsicParameters(*newCalib);
+    }
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_rot1_valueChanged(double newVal)
+{
+    mParams.rot1 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_rot2_valueChanged(double newVal)
+{
+    mParams.rot2 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_rot3_valueChanged(double newVal)
+{
+    mParams.rot3 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_trans1_valueChanged(double newVal)
+{
+    mParams.trans1 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_trans2_valueChanged(double newVal)
+{
+    mParams.trans2 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_trans3_valueChanged(double newVal)
+{
+    mParams.trans3 = newVal;
+    mUpdateCoordCallback();
+}
+
+void ExtrinsicBox::on_extrCalibSave_clicked()
+{
+    mExtrCalibration.saveExtrCalibPoints();
+}
+
+void ExtrinsicBox::on_extrCalibShowError_clicked()
+{
+    QString      out;
+    QDialog      msgBox;
+    QGridLayout *layout = new QGridLayout();
+    msgBox.setLayout(layout);
+    QLabel *tableView = new QLabel(&msgBox);
+    layout->addWidget(tableView, 1, 1);
+    QLabel *titel = new QLabel(&msgBox);
+    titel->setText("<b>Reprojection error for extrinsic calibration:</b>");
+    layout->addWidget(titel, 0, 1);
+
+    if(!mExtrCalibration.getReprojectionError().isValid())
+    {
+        out = QString("No File for extrinsic calibration found!");
+        tableView->setText(out);
+    }
+    else
+    {
+        out                    = QString("<table>"
+                                         "<tr><th></th>"
+                                         "<th>average   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>"
+                                         "<th>std. deviation                          &nbsp;</th>"
+                                         "<th>variance  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>"
+                                         "<th>max       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th></tr>"
+                                         "<tr><td>Point   height: &nbsp;&nbsp;            </td><td> %0 cm</td><td> %1 cm</td><td> %2 "
+                                         "cm</td><td> %3 cm</td></tr>"
+                                         "<tr><td>Default height: <small>[%12 cm]</small> </td><td> %4 cm</td><td> %5 cm</td><td> %6 "
+                                         "cm</td><td> %7 cm</td></tr>"
+                                         "<tr><td>Pixel    error: &nbsp;&nbsp;            </td><td> %8 px</td><td> %9 px</td><td> %10 "
+                                         "px</td><td> %11 px</td></tr>"
+                                         "</table>");
+        const auto &reproError = mExtrCalibration.getReprojectionError().getData();
+        for(double value : reproError)
+        {
+            if(value < 0)
+            {
+                out = out.arg("-");
+            }
+            else
+            {
+                out = out.arg(value);
+            }
+        }
+        tableView->setText(out);
+    }
+
+    msgBox.setWindowTitle("PeTrack");
+    QIcon   icon     = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
+    QLabel *infoIcon = new QLabel(&msgBox);
+    int     iconSize = msgBox.style()->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, &msgBox);
+    infoIcon->setPixmap(icon.pixmap(iconSize, iconSize));
+    layout->addWidget(infoIcon, 0, 0);
+    QDialogButtonBox *ok = new QDialogButtonBox(QDialogButtonBox::Ok);
+    layout->addWidget(ok, 2, 1);
+    connect(ok, &QDialogButtonBox::clicked, &msgBox, &QDialog::close);
+    msgBox.setFixedSize(msgBox.sizeHint());
+    msgBox.exec();
+}
+
+void ExtrinsicBox::on_extrCalibShowPoints_clicked()
+{
+    QString     out_str;
+    QTextStream out(&out_str);
+
+    unsigned int i;
+
+    out << "<table><tr><th>Nr.</th><th>3D.x</th><th>3D.y</th><th>3D.z</th><th>2D.x</th><th>2D.y</th></tr>" << Qt::endl;
+
+
+    for(i = 0; i < std::max(mExtrCalibration.get3DList().size(), mExtrCalibration.get2DList().size()); ++i)
+    {
+        out << "<tr>";
+        if(i < mExtrCalibration.get3DList().size())
+        {
+            out << "<td>[" << QString::number(i + 1, 'i', 0) << "]: </td><td>"
+                << QString::number(mExtrCalibration.get3DList().at(i).x, 'f', 1) << "</td><td>"
+                << QString::number(mExtrCalibration.get3DList().at(i).y, 'f', 1) << "</td><td>"
+                << QString::number(mExtrCalibration.get3DList().at(i).z, 'f', 1) << "</td><td>";
+        }
+        else
+        {
+            out << "<td>-</td><td>-</td><td>-</td>";
+        }
+        if(i < mExtrCalibration.get2DList().size())
+        {
+            out << QString::number(mExtrCalibration.get2DList().at(i).x, 'f', 3) << "</td><td>"
+                << QString::number(mExtrCalibration.get2DList().at(i).y, 'f', 3) << "</td>";
+        }
+        else
+        {
+            out << "<td>-</td><td>-</td>";
+        }
+        out << "</tr>" << Qt::endl;
+    }
+    out << "</table>" << Qt::endl;
+
+    QMessageBox msgBox;
+    msgBox.setWindowTitle("PeTrack");
+    msgBox.setIcon(QMessageBox::Information);
+    msgBox.setText("Currently loaded point correspondences<br />for extrinsic calibration:");
+    msgBox.setInformativeText(out_str);
+    msgBox.setStandardButtons(QMessageBox::Ok);
+    msgBox.setDefaultButton(QMessageBox::Ok);
+    msgBox.exec();
+}
+
+/// returns whether the all attributes were consumed
+bool ExtrinsicBox::getXml(QDomElement &subSubElem)
+{
+    if(subSubElem.tagName() == "EXTRINSIC_PARAMETERS")
+    {
+        ExtrinsicParameters params;
+        if(subSubElem.hasAttribute("EXTR_ROT_1"))
+        {
+            params.rot1 = subSubElem.attribute("EXTR_ROT_1").toDouble();
+        }
+        if(subSubElem.hasAttribute("EXTR_ROT_2"))
+        {
+            params.rot2 = subSubElem.attribute("EXTR_ROT_2").toDouble();
+        }
+        if(subSubElem.hasAttribute("EXTR_ROT_3"))
+        {
+            params.rot3 = subSubElem.attribute("EXTR_ROT_3").toDouble();
+        }
+        if(subSubElem.hasAttribute("EXTR_TRANS_1"))
+        {
+            params.trans1 = subSubElem.attribute("EXTR_TRANS_1").toDouble();
+        }
+        if(subSubElem.hasAttribute("EXTR_TRANS_2"))
+        {
+            params.trans2 = subSubElem.attribute("EXTR_TRANS_2").toDouble();
+        }
+        if(subSubElem.hasAttribute("EXTR_TRANS_3"))
+        {
+            params.trans3 = subSubElem.attribute("EXTR_TRANS_3").toDouble();
+        }
+        setExtrinsicParameters(params);
+
+        if(subSubElem.hasAttribute("EXTERNAL_CALIB_FILE"))
+        {
+            if(getExistingFile(QString::fromStdString(subSubElem.attribute("EXTERNAL_CALIB_FILE").toStdString())) != "")
+            {
+                mExtrCalibration.setExtrCalibFile(
+                    getExistingFile(QString::fromStdString(subSubElem.attribute("EXTERNAL_CALIB_FILE").toStdString())));
+                // mMainWindow->isLoading() is true; doesn't perform calibration -> ignore return
+                mExtrCalibration.loadExtrCalibFile();
+            }
+        }
+    }
+    return false;
+}
+
+void ExtrinsicBox::setXml(QDomElement &subSubElem) const
+{
+    subSubElem.setAttribute("EXTR_ROT_1", mUi->rot1->value());
+    subSubElem.setAttribute("EXTR_ROT_2", mUi->rot2->value());
+    subSubElem.setAttribute("EXTR_ROT_3", mUi->rot3->value());
+    subSubElem.setAttribute("EXTR_TRANS_1", mUi->trans1->value());
+    subSubElem.setAttribute("EXTR_TRANS_2", mUi->trans2->value());
+    subSubElem.setAttribute("EXTR_TRANS_3", mUi->trans3->value());
+}
+
+
+ExtrinsicBox::~ExtrinsicBox()
+{
+    delete mUi;
+}
diff --git a/src/imageItem.cpp b/src/imageItem.cpp
index 3999f23ad..83fe57481 100644
--- a/src/imageItem.cpp
+++ b/src/imageItem.cpp
@@ -146,10 +146,11 @@ QPointF ImageItem::getCmPerPixel(float px, float py, float h)
 ///*
 double ImageItem::getAngleToGround(float px, float py, float height)
 {
+    const auto &extrParams = mControlWidget->getExtrinsicParameters();
     cv::Point3f cam(
-        -mControlWidget->getCalibCoord3DTransX() - mControlWidget->getCalibExtrTrans1(),
-        -mControlWidget->getCalibCoord3DTransY() - mControlWidget->getCalibExtrTrans2(),
-        -mControlWidget->getCalibCoord3DTransZ() - mControlWidget->getCalibExtrTrans3());
+        -mControlWidget->getCalibCoord3DTransX() - extrParams.trans1,
+        -mControlWidget->getCalibCoord3DTransY() - extrParams.trans2,
+        -mControlWidget->getCalibCoord3DTransZ() - extrParams.trans3);
 
     cv::Point3f posInImage = mMainWindow->getExtrCalibration()->get3DPoint(
         cv::Point2f(px - mMainWindow->getImageBorderSize(), py - mMainWindow->getImageBorderSize()), height);
diff --git a/src/petrack.cpp b/src/petrack.cpp
index 02beaff12..ac259d06c 100644
--- a/src/petrack.cpp
+++ b/src/petrack.cpp
@@ -2646,7 +2646,7 @@ void Petrack::importTracker(QString dest) // default = ""
                 tPoint.setSp(
                     x,
                     y,
-                    -mControlWidget->getCalibExtrTrans3() -
+                    -mControlWidget->getExtrinsicParameters().trans3 -
                         z); // fuer den Abstand zur Kamera in z-Richtung wie bei einer Stereokamera
 
                 // Neue ID ? ==> letzte Person beendet ==> abspeichern
diff --git a/src/recognition.cpp b/src/recognition.cpp
index 63a5062f5..e5a12b6d2 100644
--- a/src/recognition.cpp
+++ b/src/recognition.cpp
@@ -163,9 +163,10 @@ void setColorParameter(const QColor &fromColor, const QColor &toColor, bool inve
 Vec2F autoCorrectColorMarker(const Vec2F &boxImageCentre, Control *controlWidget)
 {
     Petrack    *mainWindow = controlWidget->getMainWindow();
+    auto        extrParams = controlWidget->getExtrinsicParameters();
     cv::Point2f tp         = mainWindow->getExtrCalibration()->getImagePoint(cv::Point3f(
-        -controlWidget->getCalibCoord3DTransX() - controlWidget->getCalibExtrTrans1(),
-        -controlWidget->getCalibCoord3DTransY() - controlWidget->getCalibExtrTrans2(),
+        -controlWidget->getCalibCoord3DTransX() - extrParams.trans1,
+        -controlWidget->getCalibCoord3DTransY() - extrParams.trans2,
         0));
     Vec2F       pixUnderCam(tp.x, tp.y); // CvPoint
     Vec2F       boxImageCentreWithBorder = boxImageCentre;
diff --git a/src/trackerItem.cpp b/src/trackerItem.cpp
index bca4d97da..beabb5558 100644
--- a/src/trackerItem.cpp
+++ b/src/trackerItem.cpp
@@ -558,7 +558,7 @@ void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
                                     rect,
                                     Qt::AlignHCenter,
                                     QString("-\n%2").arg(
-                                        -mControlWidget->getCalibExtrTrans3() - tp.sp().z(), 6, 'f', 1));
+                                        -mControlWidget->getExtrinsicParameters().trans3 - tp.sp().z(), 6, 'f', 1));
                             }
                             else
                             {
@@ -577,7 +577,8 @@ void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
                                     Qt::AlignHCenter,
                                     QString("%1\n%2")
                                         .arg(height, 6, 'f', 1)
-                                        .arg(-mControlWidget->getCalibExtrTrans3() - tp.sp().z(), 6, 'f', 1));
+                                        .arg(
+                                            -mControlWidget->getExtrinsicParameters().trans3 - tp.sp().z(), 6, 'f', 1));
                             }
                             else
                             {
@@ -634,7 +635,8 @@ void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
                             if(tp.sp().z() > 0)
                             {
                                 p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(
-                                    cv::Point2f(tp.x(), tp.y()), -mControlWidget->getCalibExtrTrans3() - tp.sp().z());
+                                    cv::Point2f(tp.x(), tp.y()),
+                                    -mControlWidget->getExtrinsicParameters().trans3 - tp.sp().z());
                             }
                             else
                             {
@@ -676,7 +678,8 @@ void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
                             if(tp.sp().z() > 0)
                             {
                                 p3d_height = mMainWindow->getExtrCalibration()->get3DPoint(
-                                    cv::Point2f(tp.x(), tp.y()), -mControlWidget->getCalibExtrTrans3() - tp.sp().z());
+                                    cv::Point2f(tp.x(), tp.y()),
+                                    -mControlWidget->getExtrinsicParameters().trans3 - tp.sp().z());
                             }
                             else
                             {
@@ -775,10 +778,11 @@ void TrackerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
                                     {
                                         p3d_height_p1 = mMainWindow->getExtrCalibration()->get3DPoint(
                                             cv::Point2f(person.at(j - 1).x(), person.at(j - 1).y()),
-                                            -mControlWidget->getCalibExtrTrans3() - person.at(j - 1).sp().z());
+                                            -mControlWidget->getExtrinsicParameters().trans3 -
+                                                person.at(j - 1).sp().z());
                                         p3d_height_p2 = mMainWindow->getExtrCalibration()->get3DPoint(
                                             cv::Point2f(person.at(j).x(), person.at(j).y()),
-                                            -mControlWidget->getCalibExtrTrans3() - person.at(j).sp().z());
+                                            -mControlWidget->getExtrinsicParameters().trans3 - person.at(j).sp().z());
                                     }
                                     else
                                     {
diff --git a/tests/unit_test/CMakeLists.txt b/tests/unit_test/CMakeLists.txt
index 2ec2351cb..af74b8370 100644
--- a/tests/unit_test/CMakeLists.txt
+++ b/tests/unit_test/CMakeLists.txt
@@ -15,4 +15,5 @@ target_sources(petrack_tests PRIVATE
     tst_filter.cpp
     tst_intrinsicBox.cpp
     util.h
+    tst_extrinsicBox.cpp
 )
diff --git a/tests/unit_test/tst_extrCalibration.cpp b/tests/unit_test/tst_extrCalibration.cpp
index 2ed83b12b..44b6c09e0 100644
--- a/tests/unit_test/tst_extrCalibration.cpp
+++ b/tests/unit_test/tst_extrCalibration.cpp
@@ -19,21 +19,29 @@
 #include "extrCalibration.h"
 #include "petrack.h"
 
+#include <QDomDocument>
 #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;
+constexpr float VEC_MARGIN = 0.01f;
 
 TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
 {
     Petrack  petrack{"Unknown"};
-    auto     calib   = petrack.getExtrCalibration();
+    auto    *calib   = petrack.getExtrCalibration();
     Control *control = petrack.getControlWidget();
 
-    control->setCalibExtrRot1(0);
-    control->setCalibExtrRot2(0);
-    control->setCalibExtrRot3(0);
+    const QString testConfig{
+        R"(<CONTROL>
+                <CALIBRATION>
+                    <EXTRINSIC_PARAMETERS EXTR_ROT_1="%1" EXTR_ROT_2="%2" EXTR_ROT_3="%3" EXTR_TRANS_1="0" EXTR_TRANS_2="0" EXTR_TRANS_3="0" />
+                </CALIBRATION>
+            </CONTROL>)"};
+
+    QDomDocument doc;
+    doc.setContent(testConfig.arg("0", "0", "0"));
+    control->getXml(doc.documentElement());
 
     SECTION("Identity Coordinate System")
     {
@@ -49,7 +57,8 @@ TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
     SECTION("Rotated around z-axis")
     {
         // rotate 90 degrees
-        control->setCalibExtrRot3(PI / 2);
+        doc.setContent(testConfig.arg("0", "0", QString::number(PI / 2)));
+        control->getXml(doc.documentElement());
         REQUIRE(
             cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(0, -1, 0)) ==
             Approx(0).margin(VEC_MARGIN));
@@ -67,7 +76,8 @@ TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
             Approx(0).margin(VEC_MARGIN));
 
         // negative rotation
-        control->setCalibExtrRot3(-PI);
+        doc.setContent(testConfig.arg("0", "0", QString::number(-PI)));
+        control->getXml(doc.documentElement());
         REQUIRE(
             cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(-1, 0, 0)) ==
             Approx(0).margin(VEC_MARGIN));
@@ -80,9 +90,8 @@ TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
     SECTION("Wild rotation")
     {
         // vector (1, 1, 1) with length pi/2
-        control->setCalibExtrRot1(0.9067);
-        control->setCalibExtrRot2(0.9067);
-        control->setCalibExtrRot3(0.9067);
+        doc.setContent(testConfig.arg("0.9067", "0.9067", "0.9067"));
+        control->getXml(doc.documentElement());
 
         REQUIRE(
             cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 1, 1)) - cv::Vec3d(1, 1, 1)) ==
@@ -98,9 +107,14 @@ TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
 
         SECTION("Translation should not matter")
         {
-            control->setCalibExtrTrans1(10);
-            control->setCalibExtrTrans2(-20);
-            control->setCalibExtrTrans3(-500);
+            const QString testConfig{
+                R"(<CONTROL>
+                        <CALIBRATION>
+                            <EXTRINSIC_PARAMETERS EXTR_ROT_1="%1" EXTR_ROT_2="%2" EXTR_ROT_3="%3" EXTR_TRANS_1="10" EXTR_TRANS_2="-20" EXTR_TRANS_3="-500" />
+                        </CALIBRATION>
+                    </CONTROL>)"};
+            doc.setContent(testConfig.arg("0.9067", "0.9067", "0.9067"));
+            control->getXml(doc.documentElement());
             REQUIRE(
                 cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 0, 0)) - cv::Vec3d(0.33, -0.24, 0.91)) ==
                 Approx(0).margin(VEC_MARGIN));
@@ -113,9 +127,8 @@ TEST_CASE("src/extrCalibration/camToWorldRotation", "[extrCalibration]")
 
     SECTION("Another Wild Rotation")
     {
-        control->setCalibExtrRot1(0.5);
-        control->setCalibExtrRot2(-2);
-        control->setCalibExtrRot3(1.1);
+        doc.setContent(testConfig.arg("0.5", "-2", "1.1"));
+        control->getXml(doc.documentElement());
 
         REQUIRE(
             cv::norm(calib->camToWorldRotation(cv::Vec3d(1, 1, 1)) - cv::Vec3d(0.2, -0.63, -1.6)) ==
diff --git a/tests/unit_test/tst_extrinsicBox.cpp b/tests/unit_test/tst_extrinsicBox.cpp
new file mode 100644
index 000000000..fd5d1cb9f
--- /dev/null
+++ b/tests/unit_test/tst_extrinsicBox.cpp
@@ -0,0 +1,115 @@
+/*
+ * PeTrack - Software for tracking pedestrians movement in videos
+ * Copyright (C) 2023 Forschungszentrum Jülich GmbH, IAS-7
+ *
+ * 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://cdwww.gnu.org/licenses/>.
+ */
+
+#include "extrCalibration.h"
+#include "extrinsicBox.h"
+#include "personStorage.h"
+#include "petrack.h"
+#include "ui_extrinsicBox.h"
+
+#include <QDomElement>
+#include <catch2/catch.hpp>
+
+TEST_CASE("ExtrinsicBox: display of values in UI")
+{
+    Petrack         petrack{"Unkown"};
+    Autosave        autosave(petrack);
+    PersonStorage   storage(petrack, autosave);
+    ExtrCalibration calib(storage);
+    Ui::extr       *ui = new Ui::extr();
+    ExtrinsicBox    extrBox(nullptr, ui, calib, []() {});
+
+    ExtrinsicParameters params;
+    params.rot1   = 0.5;
+    params.rot2   = 0.2;
+    params.rot3   = -0.5;
+    params.trans1 = 234;
+    params.trans2 = 420;
+    params.trans3 = 699;
+
+    WHEN("We change the values of the extrinsic parameters")
+    {
+        extrBox.setExtrinsicParameters(params);
+
+        THEN("The values are displayed accordingly")
+        {
+            CHECK(ui->rot1->value() == params.rot1);
+            CHECK(ui->rot2->value() == params.rot2);
+            CHECK(ui->rot3->value() == params.rot3);
+            CHECK(ui->trans1->value() == params.trans1);
+            CHECK(ui->trans2->value() == params.trans2);
+            CHECK(ui->trans3->value() == params.trans3);
+        }
+    }
+
+    WHEN("We change the values in the UI")
+    {
+        ui->rot1->setValue(params.rot1);
+        ui->rot2->setValue(params.rot2);
+        ui->rot3->setValue(params.rot3);
+        ui->trans1->setValue(params.trans1);
+        ui->trans2->setValue(params.trans2);
+        ui->trans3->setValue(params.trans3);
+
+        THEN("The changes are propagated accordingly")
+        {
+            CHECK(extrBox.getExtrinsicParameters() == params);
+        }
+    }
+}
+
+TEST_CASE("ExtrinsicBox: reading/writing xml")
+{
+    Petrack         petrack{"Unkown"};
+    Autosave        autosave(petrack);
+    PersonStorage   storage(petrack, autosave);
+    ExtrCalibration calib(storage);
+    ExtrinsicBox    extrBox(nullptr, calib, []() {});
+
+    WHEN("We change the extrinsic parameters")
+    {
+        ExtrinsicParameters params;
+        params.rot1   = 0.5;
+        params.rot2   = 0.2;
+        params.rot3   = -0.5;
+        params.trans1 = 234;
+        params.trans2 = 420;
+        params.trans3 = 699;
+
+        extrBox.setExtrinsicParameters(params);
+
+        AND_WHEN("We save that state into an xml-document")
+        {
+            QDomDocument doc;
+            QDomElement  elem = doc.createElement("EXTRINSIC_PARAMETERS");
+            extrBox.setXml(elem);
+
+            THEN("We can read that state in again")
+            {
+                Petrack         petrack{"Unkown"};
+                Autosave        autosave(petrack);
+                PersonStorage   storage(petrack, autosave);
+                ExtrCalibration calib(storage);
+                ExtrinsicBox    extrBox(nullptr, calib, []() {});
+
+                extrBox.getXml(elem);
+                CHECK(extrBox.getExtrinsicParameters() == params);
+            }
+        }
+    }
+}
diff --git a/ui/control.ui b/ui/control.ui
index a502857e4..d484430ee 100644
--- a/ui/control.ui
+++ b/ui/control.ui
@@ -139,8 +139,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>477</width>
-            <height>619</height>
+            <width>494</width>
+            <height>555</height>
            </rect>
           </property>
           <property name="sizePolicy">
@@ -150,325 +150,6 @@
            </sizepolicy>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_13">
-           <item>
-            <widget class="QGroupBox" name="extr">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="minimumSize">
-              <size>
-               <width>300</width>
-               <height>0</height>
-              </size>
-             </property>
-             <property name="maximumSize">
-              <size>
-               <width>16777215</width>
-               <height>16777215</height>
-              </size>
-             </property>
-             <property name="title">
-              <string>extrinsic parameters</string>
-             </property>
-             <layout class="QVBoxLayout" name="verticalLayout_7">
-              <property name="leftMargin">
-               <number>5</number>
-              </property>
-              <property name="topMargin">
-               <number>5</number>
-              </property>
-              <property name="rightMargin">
-               <number>5</number>
-              </property>
-              <property name="bottomMargin">
-               <number>5</number>
-              </property>
-              <item>
-               <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,0,0,0">
-                <item row="0" column="0">
-                 <widget class="QLabel" name="label_58">
-                  <property name="toolTip">
-                   <string>Translate the coordinate system in x-direction.</string>
-                  </property>
-                  <property name="text">
-                   <string>rotation:</string>
-                  </property>
-                  <property name="alignment">
-                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="0">
-                 <widget class="QLabel" name="label_59">
-                  <property name="toolTip">
-                   <string>Translate the coordinate system in x-direction.</string>
-                  </property>
-                  <property name="text">
-                   <string>translation:</string>
-                  </property>
-                  <property name="alignment">
-                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="1">
-                 <widget class="PDoubleSpinBox" name="trans1">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-10000.000000000000000</double>
-                  </property>
-                  <property name="maximum">
-                   <double>10000.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.100000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item row="0" column="1">
-                 <widget class="PDoubleSpinBox" name="rot1">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-100.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.001000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="2">
-                 <widget class="PDoubleSpinBox" name="trans2">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-10000.000000000000000</double>
-                  </property>
-                  <property name="maximum">
-                   <double>10000.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.100000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="3">
-                 <widget class="PDoubleSpinBox" name="trans3">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-10000.000000000000000</double>
-                  </property>
-                  <property name="maximum">
-                   <double>10000.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.100000000000000</double>
-                  </property>
-                  <property name="value">
-                   <double>-500.000000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item row="0" column="3">
-                 <widget class="PDoubleSpinBox" name="rot3">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-100.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.001000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-                <item row="0" column="2">
-                 <widget class="PDoubleSpinBox" name="rot2">
-                  <property name="decimals">
-                   <number>3</number>
-                  </property>
-                  <property name="minimum">
-                   <double>-100.000000000000000</double>
-                  </property>
-                  <property name="singleStep">
-                   <double>0.001000000000000</double>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-              <item>
-               <layout class="QHBoxLayout" name="horizontalLayout_10">
-                <item>
-                 <widget class="QLabel" name="label_62">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="text">
-                   <string>3D/2D Points:</string>
-                  </property>
-                  <property name="alignment">
-                   <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="coordLoad3DCalibPoints">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="minimumSize">
-                   <size>
-                    <width>30</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>40</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="toolTip">
-                   <string>Load 3D points to corresponding 2D image points</string>
-                  </property>
-                  <property name="text">
-                   <string>load</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="extrCalibFetch">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="minimumSize">
-                   <size>
-                    <width>30</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>40</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="toolTip">
-                   <string>Fetch marked 2D Points to loaded 3D points</string>
-                  </property>
-                  <property name="text">
-                   <string>fetch</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="extrCalibSave">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="minimumSize">
-                   <size>
-                    <width>30</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>40</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="toolTip">
-                   <string>Save 3D and/or 2D points to extrinisc calib file</string>
-                  </property>
-                  <property name="text">
-                   <string>save</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="extrCalibShowPoints">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="minimumSize">
-                   <size>
-                    <width>30</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>40</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="toolTip">
-                   <string>Show the saved 2D/3D point correspondences in the file</string>
-                  </property>
-                  <property name="text">
-                   <string>show</string>
-                  </property>
-                 </widget>
-                </item>
-                <item>
-                 <widget class="QPushButton" name="extrCalibShowError">
-                  <property name="sizePolicy">
-                   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                   </sizepolicy>
-                  </property>
-                  <property name="minimumSize">
-                   <size>
-                    <width>30</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="maximumSize">
-                   <size>
-                    <width>40</width>
-                    <height>18</height>
-                   </size>
-                  </property>
-                  <property name="toolTip">
-                   <string>Show the reprojection error of extrinsic calibration</string>
-                  </property>
-                  <property name="text">
-                   <string>error</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-             </layout>
-            </widget>
-           </item>
            <item>
             <widget class="QGroupBox" name="align_2">
              <property name="sizePolicy">
@@ -6465,17 +6146,6 @@
   </customwidget>
  </customwidgets>
  <tabstops>
-  <tabstop>rot1</tabstop>
-  <tabstop>rot2</tabstop>
-  <tabstop>rot3</tabstop>
-  <tabstop>trans1</tabstop>
-  <tabstop>trans2</tabstop>
-  <tabstop>trans3</tabstop>
-  <tabstop>coordLoad3DCalibPoints</tabstop>
-  <tabstop>extrCalibFetch</tabstop>
-  <tabstop>extrCalibSave</tabstop>
-  <tabstop>extrCalibShowPoints</tabstop>
-  <tabstop>extrCalibShowError</tabstop>
   <tabstop>coordShow</tabstop>
   <tabstop>coordFix</tabstop>
   <tabstop>coordTab</tabstop>
diff --git a/ui/extrinsicBox.ui b/ui/extrinsicBox.ui
new file mode 100644
index 000000000..6b7c1d14f
--- /dev/null
+++ b/ui/extrinsicBox.ui
@@ -0,0 +1,354 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>extr</class>
+ <widget class="QGroupBox" name="extr">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>322</width>
+    <height>106</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>300</width>
+    <height>0</height>
+   </size>
+  </property>
+  <property name="maximumSize">
+   <size>
+    <width>16777215</width>
+    <height>16777215</height>
+   </size>
+  </property>
+  <property name="focusPolicy">
+   <enum>Qt::TabFocus</enum>
+  </property>
+  <property name="title">
+   <string>extrinsic parameters</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_7">
+   <property name="leftMargin">
+    <number>5</number>
+   </property>
+   <property name="topMargin">
+    <number>5</number>
+   </property>
+   <property name="rightMargin">
+    <number>5</number>
+   </property>
+   <property name="bottomMargin">
+    <number>5</number>
+   </property>
+   <item>
+    <layout class="QGridLayout" name="gridLayout_6" columnstretch="0,0,0,0">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_58">
+       <property name="toolTip">
+        <string>Translate the coordinate system in x-direction.</string>
+       </property>
+       <property name="text">
+        <string>rotation:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_59">
+       <property name="toolTip">
+        <string>Translate the coordinate system in x-direction.</string>
+       </property>
+       <property name="text">
+        <string>translation:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="PDoubleSpinBox" name="trans1">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-10000.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>10000.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.100000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="PDoubleSpinBox" name="rot1">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-100.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.001000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="PDoubleSpinBox" name="trans2">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-10000.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>10000.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.100000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="PDoubleSpinBox" name="trans3">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-10000.000000000000000</double>
+       </property>
+       <property name="maximum">
+        <double>10000.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.100000000000000</double>
+       </property>
+       <property name="value">
+        <double>-500.000000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="PDoubleSpinBox" name="rot3">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-100.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.001000000000000</double>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="PDoubleSpinBox" name="rot2">
+       <property name="decimals">
+        <number>3</number>
+       </property>
+       <property name="minimum">
+        <double>-100.000000000000000</double>
+       </property>
+       <property name="singleStep">
+        <double>0.001000000000000</double>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_10">
+     <item>
+      <widget class="QLabel" name="label_62">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="text">
+        <string>3D/2D Points:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="coordLoad3DCalibPoints">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>30</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>40</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="toolTip">
+        <string>Load 3D points to corresponding 2D image points</string>
+       </property>
+       <property name="text">
+        <string>load</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="extrCalibFetch">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>30</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>40</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="toolTip">
+        <string>Fetch marked 2D Points to loaded 3D points</string>
+       </property>
+       <property name="text">
+        <string>fetch</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="extrCalibSave">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>30</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>40</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="toolTip">
+        <string>Save 3D and/or 2D points to extrinisc calib file</string>
+       </property>
+       <property name="text">
+        <string>save</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="extrCalibShowPoints">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>30</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>40</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="toolTip">
+        <string>Show the saved 2D/3D point correspondences in the file</string>
+       </property>
+       <property name="text">
+        <string>show</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="extrCalibShowError">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>30</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>40</width>
+         <height>18</height>
+        </size>
+       </property>
+       <property name="toolTip">
+        <string>Show the reprojection error of extrinsic calibration</string>
+       </property>
+       <property name="text">
+        <string>error</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>PDoubleSpinBox</class>
+   <extends>QDoubleSpinBox</extends>
+   <header>pdoublespinbox.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>rot1</tabstop>
+  <tabstop>rot2</tabstop>
+  <tabstop>rot3</tabstop>
+  <tabstop>trans1</tabstop>
+  <tabstop>trans2</tabstop>
+  <tabstop>trans3</tabstop>
+  <tabstop>coordLoad3DCalibPoints</tabstop>
+  <tabstop>extrCalibFetch</tabstop>
+  <tabstop>extrCalibSave</tabstop>
+  <tabstop>extrCalibShowPoints</tabstop>
+  <tabstop>extrCalibShowError</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
-- 
GitLab