diff --git a/include/codeMarkerWidget.h b/include/codeMarkerWidget.h
index 6e1fad9556908819e2fb589d99bd3dcb0a80d375..8fc06b18b4a4db7b2f6cf82db1405dc9231edadd 100644
--- a/include/codeMarkerWidget.h
+++ b/include/codeMarkerWidget.h
@@ -28,14 +28,14 @@
 
 #include "petrack.h"
 #include "codeMarkerItem.h"
-
+#include "recognition.h"
 
 class CodeMarkerWidget: public QWidget, public Ui::CodeMarker
 {
     Q_OBJECT
 
 public:
-    CodeMarkerWidget(QWidget *parent = nullptr);
+    CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& opt);
 
     // store data in xml node
     void setXml(QDomElement &elem);
@@ -43,153 +43,27 @@ public:
     // read data from xml node
     void getXml(QDomElement &elem);
 
+    reco::ArucoCodeParams packDetectorParams();
+
 
 private slots:
 
-    void on_showDetectedCandidates_stateChanged(int i)
-    {
-
-        mMainWindow->getCodeMarkerItem()->setVisible(i);
-        if( !mMainWindow->isLoading() )
-            mMainWindow->getScene()->update();
-    }
-
-    void on_moreInfosButton_clicked()
-    {
-        QDesktopServices::openUrl(QUrl("http://docs.opencv.org/trunk/d1/dcd/structcv_1_1aruco_1_1DetectorParameters.html#details", QUrl::TolerantMode));
-        QDesktopServices::openUrl(QUrl("http://docs.opencv.org/3.1.0/d5/dae/tutorial_aruco_detection.html", QUrl::TolerantMode));
-    }
-    void on_dictList_currentIndexChanged(int /*index*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_minMarkerPerimeter_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_maxMarkerPerimeter_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_adaptiveThreshWinSizeMin_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_adaptiveThreshWinSizeMax_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_adaptiveThreshWinSizeStep_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_adaptiveThreshConstant_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_polygonalApproxAccuracyRate_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_minCornerDistance_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_minDistanceToBorder_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_minMarkerDistance_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_doCornerRefinement_clicked()
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_cornerRefinementWinSize_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_cornerRefinementMaxIterations_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_cornerRefinementMinAccuracy_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_markerBorderBits_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_perspectiveRemovePixelPerCell_valueChanged(int /*i*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_perspectiveRemoveIgnoredMarginPerCell_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_maxErroneousBitsInBorderRate_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_errorCorrectionRate_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
-    void on_minOtsuStdDev_valueChanged(double /*val*/)
-    {
-        mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
-        if( !mMainWindow->isLoading() )
-            mMainWindow->updateImage();
-    }
+    void on_showDetectedCandidates_stateChanged(int i);
 
+    void on_moreInfosButton_clicked();
+    void on_dictList_currentIndexChanged(int /*index*/);
 
+private:
+    void notifyChanged();
+    void sendDetectorParams(reco::ArucoCodeParams params);
+
+private slots:
+    void readDetectorParams();
+    void readDictListIndex();
 
 private:
     Petrack *mMainWindow;
+    reco::CodeMarkerOptions &mCodeMarkerOpt;
 };
 
 #endif
diff --git a/include/recognition.h b/include/recognition.h
index 629fe0a558aac14ec89511903900f62cc182f732..4076c237b830f61e2057c3a302238d2cec32772e 100644
--- a/include/recognition.h
+++ b/include/recognition.h
@@ -32,6 +32,7 @@ class QRect;
 class BackgroundFilter;
 class Control;
 class ImageItem;
+class CodeMarkerItem;
 
 namespace reco {
     /**
@@ -50,12 +51,71 @@ namespace reco {
         Code = 6,
     };
 
+    struct ArucoCodeParams {
+        double minMarkerPerimeter = 5;
+        double maxMarkerPerimeter = 15;
+        double minCornerDistance = 0.05;
+        double minMarkerDistance = 0.05;
+        int adaptiveThreshWinSizeMin = 3;
+        int adaptiveThreshWinSizeMax = 27;
+        int adaptiveThreshWinSizeStep = 10;
+        int adaptiveThreshConstant = 7;
+        double polygonalApproxAccuracyRate = 0.03;
+        int minDistanceToBorder = 3;
+        bool doCornerRefinement = false;
+        int cornerRefinementWinSize = 5;
+        int cornerRefinementMaxIterations = 30;
+        double cornerRefinementMinAccuracy = 0.1;
+        int markerBorderBits = 1;
+        int perspectiveRemovePixelPerCell = 4;
+        double perspectiveRemoveIgnoredMarginPerCell = 0.13;
+        double maxErroneousBitsInBorderRate = 0.35;
+        double minOtsuStdDev = 5;
+        double errorCorrectionRate = 0.6;
+
+        friend inline constexpr bool operator==(const ArucoCodeParams & lhs, const ArucoCodeParams & rhs) noexcept
+        {
+            return (lhs.minMarkerPerimeter == rhs.minMarkerPerimeter) && ((lhs.maxMarkerPerimeter == rhs.maxMarkerPerimeter) && ((lhs.minCornerDistance == rhs.minCornerDistance) && ((lhs.minMarkerDistance == rhs.minMarkerDistance) && ((lhs.adaptiveThreshWinSizeMin == rhs.adaptiveThreshWinSizeMin) && ((lhs.adaptiveThreshWinSizeMax == rhs.adaptiveThreshWinSizeMax) && ((lhs.adaptiveThreshWinSizeStep == rhs.adaptiveThreshWinSizeStep) && ((lhs.adaptiveThreshConstant == rhs.adaptiveThreshConstant) && ((lhs.polygonalApproxAccuracyRate == rhs.polygonalApproxAccuracyRate) && ((lhs.minDistanceToBorder == rhs.minDistanceToBorder) && ((static_cast<int>(lhs.doCornerRefinement) == static_cast<int>(rhs.doCornerRefinement)) && ((lhs.cornerRefinementWinSize == rhs.cornerRefinementWinSize) && ((lhs.cornerRefinementMaxIterations == rhs.cornerRefinementMaxIterations) && ((lhs.cornerRefinementMinAccuracy == rhs.cornerRefinementMinAccuracy) && ((lhs.markerBorderBits == rhs.markerBorderBits) && ((lhs.perspectiveRemovePixelPerCell == rhs.perspectiveRemovePixelPerCell) && ((lhs.perspectiveRemoveIgnoredMarginPerCell == rhs.perspectiveRemoveIgnoredMarginPerCell) && ((lhs.maxErroneousBitsInBorderRate == rhs.maxErroneousBitsInBorderRate) && ((lhs.minOtsuStdDev == rhs.minOtsuStdDev) && (lhs.errorCorrectionRate == rhs.errorCorrectionRate)))))))))))))))))));
+        }
+        friend inline constexpr bool operator!=(const ArucoCodeParams& lhs, const ArucoCodeParams& rhs)
+        {
+            return !(lhs == rhs);
+        }
+    };
+
+
+    struct CodeMarkerOptions : public QObject{
+        Q_OBJECT
+
+    public:
+        CodeMarkerItem *codeMarkerItem;
+        int indexOfMarkerDict = 16;
+
+        ArucoCodeParams detectorParams;
+
+        Control *controlWidget;
+        Vec2F offsetCropRect2Roi = Vec2F{0,0};
+
+    public:
+        ArucoCodeParams getDetectorParams() const {return detectorParams;}
+        int getIndexOfMarkerDict() const {return indexOfMarkerDict;}
+
+    public:
+        void userChangedDetectorParams(ArucoCodeParams params);
+        void userChangedIndexOfMarkerDict(int idx);
+
+    signals:
+        void detectorParamsChanged();
+        void indexOfMarkerDictChanged();
+    };
+
     class Recognizer : public QObject
     {
         Q_OBJECT
 
     private:
         // TODO add options for each marker type
+        CodeMarkerOptions mCodeMarkerOptions;
 
         // default multicolor marker (until 11/2016 hermes marker)
         RecognitionMethod mRecoMethod = RecognitionMethod::MultiColor;
@@ -63,6 +123,7 @@ namespace reco {
         QList<TrackPoint> getMarkerPos(cv::Mat &img, QRect &roi, Control *controlWidget, int borderSize, BackgroundFilter *bgFilter);
 
         RecognitionMethod getRecoMethod() const {return mRecoMethod;}
+        CodeMarkerOptions& getCodeMarkerOptions() {return mCodeMarkerOptions;}
 
     public slots:
         void userChangedRecoMethod(RecognitionMethod method)
@@ -130,6 +191,7 @@ namespace reco {
             bool     autoCorrect         = false;   ///< should perspective correction be performed
             bool autoCorrectOnlyExport   = false;   ///< should perspective correction only be performed when exporting trajectories
             RecognitionMethod method = RecognitionMethod::Code; ///< Used recognition method; could be called from findMulticolorMarker
+            CodeMarkerOptions& codeOpt;
         };
 
         std::vector<ColorBlob> findColorBlob(const ColorBlobDetectionParams &options);
@@ -138,7 +200,7 @@ namespace reco {
         void refineWithBlackDot(std::vector<ColorBlob>& blobs, const cv::Mat& img, QList<TrackPoint>& crossList, const BlackDotOptions& options);
         void refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img, QList<TrackPoint> &crossList, ArucoOptions& options);
 
-        void findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *controlWidget, RecognitionMethod recoMethod, Vec2F offsetCropRect2Roi=Vec2F{0,0});
+        void findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, RecognitionMethod recoMethod, const CodeMarkerOptions &opt);
         cv::Ptr<cv::aruco::Dictionary> getDictMip36h12();
     }
 }
diff --git a/src/codeMarkerWidget.cpp b/src/codeMarkerWidget.cpp
index 1ea23126830f81c382ec7204c8f090fbdc05bf92..741ff4e203cf1279320f794d783024b3b2b729f4 100644
--- a/src/codeMarkerWidget.cpp
+++ b/src/codeMarkerWidget.cpp
@@ -18,10 +18,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <opencv2/core/version.hpp>
+
 #include "codeMarkerWidget.h"
+#include "recognition.h"
 
-CodeMarkerWidget::CodeMarkerWidget(QWidget *parent)
-    : QWidget(parent)
+CodeMarkerWidget::CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& codeMarkerOpt)
+    : QWidget(parent), mCodeMarkerOpt(codeMarkerOpt)
 {
     mMainWindow = (class Petrack*) parent;
 
@@ -50,8 +53,45 @@ CodeMarkerWidget::CodeMarkerWidget(QWidget *parent)
     dictList->addItem("DICT_ARUCO_ORGINAL"); // 16
     dictList->addItem("DICT_mip_36h12");//17
 
-    dictList->setCurrentIndex(16);
+    connect(&mCodeMarkerOpt, &reco::CodeMarkerOptions::detectorParamsChanged, this, &CodeMarkerWidget::readDetectorParams);
+    connect(&mCodeMarkerOpt, &reco::CodeMarkerOptions::indexOfMarkerDictChanged, this, &CodeMarkerWidget::readDictListIndex);
+
+    // get default values from Options
+    readDetectorParams();
+    readDictListIndex();
+
+
+    // NOTE: No parameter validation done here
+    // Can result in crash, when invalid params are chosen (e.g. min larger than max)
+    auto changedParams = [&](){
+        sendDetectorParams(packDetectorParams());
+        notifyChanged();
+    };
+
+    connect(minMarkerPerimeter, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(maxMarkerPerimeter, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
 
+    connect(adaptiveThreshWinSizeMin, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(adaptiveThreshWinSizeMax, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(adaptiveThreshWinSizeStep, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(adaptiveThreshConstant, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+
+    connect(polygonalApproxAccuracyRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(minCornerDistance, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(minDistanceToBorder, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(minMarkerDistance, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+
+    connect(doCornerRefinement, &QGroupBox::clicked, changedParams);
+    connect(cornerRefinementWinSize, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(cornerRefinementMaxIterations, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(cornerRefinementMinAccuracy, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+
+    connect(markerBorderBits, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(perspectiveRemovePixelPerCell, QOverload<int>::of(&QSpinBox::valueChanged), changedParams);
+    connect(perspectiveRemoveIgnoredMarginPerCell, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(maxErroneousBitsInBorderRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(errorCorrectionRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
+    connect(minOtsuStdDev, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams);
 }
 
 //<COLOR_MARKER>
@@ -155,10 +195,94 @@ void CodeMarkerWidget::getXml(QDomElement &elem)
                 errorCorrectionRate->setValue(subElem.attribute("ERROR_CORRECTION_RATE").toDouble());
             if (subElem.hasAttribute("SHOW_DETECTED_CANDIDATES"))
                 showDetectedCandidates->setCheckState(subElem.attribute("SHOW_DETECTED_CANDIDATES").toInt() ? Qt::Checked : Qt::Unchecked);
-
-
         }
     }
 }
 
+reco::ArucoCodeParams CodeMarkerWidget::packDetectorParams()
+{
+    reco::ArucoCodeParams params;
+    params.adaptiveThreshConstant = adaptiveThreshConstant->value();
+    params.adaptiveThreshWinSizeMax = adaptiveThreshWinSizeMax->value();
+    params.adaptiveThreshWinSizeMin = adaptiveThreshWinSizeMin->value();
+    params.adaptiveThreshWinSizeStep = adaptiveThreshWinSizeStep->value();
+    params.cornerRefinementMaxIterations = cornerRefinementMaxIterations->value();
+    params.cornerRefinementMinAccuracy = cornerRefinementMinAccuracy->value();
+    params.cornerRefinementWinSize = cornerRefinementWinSize->value();
+    params.doCornerRefinement = doCornerRefinement->isChecked();
+    params.errorCorrectionRate = errorCorrectionRate->value();
+    params.markerBorderBits = markerBorderBits->value();
+    params.maxErroneousBitsInBorderRate = maxErroneousBitsInBorderRate->value();
+    params.minDistanceToBorder = minDistanceToBorder->value();
+    params.minMarkerDistance = minMarkerDistance->value();
+    params.minMarkerPerimeter = minMarkerPerimeter->value();
+    params.minOtsuStdDev = minOtsuStdDev->value();
+    params.perspectiveRemoveIgnoredMarginPerCell = perspectiveRemoveIgnoredMarginPerCell->value();
+    params.perspectiveRemovePixelPerCell = perspectiveRemovePixelPerCell->value();
+    params.polygonalApproxAccuracyRate = polygonalApproxAccuracyRate->value();
+
+    return params;
+}
+
+void CodeMarkerWidget::on_showDetectedCandidates_stateChanged(int i)
+{
+    mMainWindow->getCodeMarkerItem()->setVisible(i);
+    if( !mMainWindow->isLoading() )
+        mMainWindow->getScene()->update();
+}
+
+void CodeMarkerWidget::on_moreInfosButton_clicked()
+{
+#define CV_NUMERIC_VERSION CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION)
+    QDesktopServices::openUrl(QUrl("http://docs.opencv.org/" CV_NUMERIC_VERSION "/d1/dcd/structcv_1_1aruco_1_1DetectorParameters.html#details", QUrl::TolerantMode));
+    QDesktopServices::openUrl(QUrl("http://docs.opencv.org/" CV_NUMERIC_VERSION "/d5/dae/tutorial_aruco_detection.html", QUrl::TolerantMode));
+}
+
+void CodeMarkerWidget::on_dictList_currentIndexChanged(int i)
+{
+    mCodeMarkerOpt.userChangedIndexOfMarkerDict(i);
+    notifyChanged();
+}
+
+
+void CodeMarkerWidget::notifyChanged()
+{
+    mMainWindow->setRecognitionChanged(true);// flag indicates that changes of recognition parameters happens
+    if( !mMainWindow->isLoading() )
+        mMainWindow->updateImage();
+}
+
+void CodeMarkerWidget::readDetectorParams()
+{
+    auto params = mCodeMarkerOpt.getDetectorParams();
+    adaptiveThreshConstant->setValue(params.adaptiveThreshConstant);
+    adaptiveThreshWinSizeMax->setValue(params.adaptiveThreshWinSizeMax);
+    adaptiveThreshWinSizeMin->setValue(params.adaptiveThreshWinSizeMin);
+    adaptiveThreshWinSizeStep->setValue(params.adaptiveThreshWinSizeStep);
+    cornerRefinementMaxIterations->setValue(params.cornerRefinementMaxIterations);
+    cornerRefinementMinAccuracy->setValue(params.cornerRefinementMinAccuracy);
+    cornerRefinementWinSize->setValue(params.cornerRefinementWinSize);
+    doCornerRefinement->setChecked(params.doCornerRefinement);
+    errorCorrectionRate->setValue(params.errorCorrectionRate);
+    markerBorderBits->setValue(params.markerBorderBits);
+    maxErroneousBitsInBorderRate->setValue(params.maxErroneousBitsInBorderRate);
+    minDistanceToBorder->setValue(params.minDistanceToBorder);
+    minMarkerDistance->setValue(params.minMarkerDistance);
+    minMarkerPerimeter->setValue(params.minMarkerPerimeter);
+    minOtsuStdDev->setValue(params.minOtsuStdDev);
+    perspectiveRemoveIgnoredMarginPerCell->setValue(params.perspectiveRemoveIgnoredMarginPerCell);
+    perspectiveRemovePixelPerCell->setValue(params.perspectiveRemovePixelPerCell);
+    polygonalApproxAccuracyRate->setValue(params.polygonalApproxAccuracyRate);
+}
+
+void CodeMarkerWidget::readDictListIndex()
+{
+    dictList->setCurrentIndex(mCodeMarkerOpt.getIndexOfMarkerDict());
+}
+
+void CodeMarkerWidget::sendDetectorParams(reco::ArucoCodeParams params)
+{
+    mCodeMarkerOpt.userChangedDetectorParams(params);
+}
+
 #include "moc_codeMarkerWidget.cpp"
diff --git a/src/petrack.cpp b/src/petrack.cpp
index 1a1ef1cb55c99383f4c164b4270490e73e259c1d..3c82cb8286f726b7e5e6e8da24b49a008bff02d7 100644
--- a/src/petrack.cpp
+++ b/src/petrack.cpp
@@ -125,7 +125,7 @@ Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPa
     mColorMarkerWidget->setWindowFlags(Qt::Window);
     mColorMarkerWidget->setWindowTitle("Color marker parameter");
 
-    mCodeMarkerWidget = new CodeMarkerWidget(this);
+    mCodeMarkerWidget = new CodeMarkerWidget(this, mReco.getCodeMarkerOptions());
     mCodeMarkerWidget->setWindowFlags(Qt::Window);
     mCodeMarkerWidget->setWindowTitle("Code marker parameter");
 
@@ -268,6 +268,10 @@ Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPa
     createMenus();
     createStatusBar();
 
+    // TODO delete once we get Options to be value only (i.e. no Pointer/Ref anymore)
+    mReco.getCodeMarkerOptions().controlWidget = mControlWidget;
+    mReco.getCodeMarkerOptions().codeMarkerItem = mCodeMarkerItem;
+
     mSeqFileName = QDir::currentPath(); //fuer allerersten Aufruf des Programms
     readSettings();
 
diff --git a/src/recognition.cpp b/src/recognition.cpp
index 133afb22efc73e4fbe179376ef71289fac9add45..023f3d47ce3e613f7de9b0f48b1c5b5c3c67f06a 100644
--- a/src/recognition.cpp
+++ b/src/recognition.cpp
@@ -559,6 +559,7 @@ void detail::refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img,
     bool autoCorrect = options.autoCorrect;
     bool autoCorrectOnlyExport = options.autoCorrectOnlyExport;
 
+    CodeMarkerOptions& codeOpt = options.codeOpt;
     for(ColorBlob& blob : blobs)
     {
         // cropRect has coordinates of rechtangele around color blob with respect to lower left corner (as in the beginning of useBlackDot)
@@ -579,7 +580,10 @@ void detail::refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img,
 
         if (subImg.empty())
             continue;
-        findCodeMarker(subImg, crossList, controlWidget, options.method, offsetCropRect2Roi);
+        // TODO: Use Reference to actual codeMarkerOptions in MulticolorMarkerOptions
+        // NOTE: For now, add as parameter of findMulticolorMarker
+        codeOpt.offsetCropRect2Roi = offsetCropRect2Roi;
+        findCodeMarker(subImg, crossList, options.method, codeOpt);
 
         // The next three statements each:
         // - set the offset of subImg with regards to ROI //(ROI to original image is archieved later in the code for all methods)
@@ -632,6 +636,7 @@ void detail::refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img,
             crossList.back() = crossList.back() + (Vec2F(cropRect.x, cropRect.y) + moveDir);
         }
     }
+    codeOpt.offsetCropRect2Roi = Vec2F{0,0};
 }
 
 /**
@@ -647,7 +652,7 @@ void detail::refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img,
  * @param ignoreWithoutMarker (is ignored->overwritten by cmWidget->ignoreWithoutDot->isChecked())
  * @param offset
  */
-void findMultiColorMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *controlWidget, bool ignoreWithoutMarker, Vec2F &offset, RecognitionMethod method)
+void findMultiColorMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *controlWidget, bool ignoreWithoutMarker, Vec2F &offset, RecognitionMethod method, CodeMarkerOptions& codeOpt)
 {
     Petrack *mainWindow = controlWidget->getMainWindow();
     MultiColorMarkerItem* cmItem = mainWindow->getMultiColorMarkerItem();
@@ -723,12 +728,14 @@ void findMultiColorMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *c
             refineWithBlackDot(blobs, img, crossList, options);
         }else if (useCodeMarker)
         {
-            ArucoOptions options;
-            options.autoCorrect = autoCorrect;
-            options.autoCorrectOnlyExport = autoCorrectOnlyExport;
-            options.ignoreWithoutMarker = ignoreWithoutMarker;
-            options.controlWidget = controlWidget;
-            options.method = method;
+            ArucoOptions options{
+                controlWidget,
+                ignoreWithoutMarker,
+                autoCorrect,
+                autoCorrectOnlyExport,
+                method,
+                codeOpt
+            };
 
             // adds to crosslist
             refineWithAruco(blobs, img, crossList, options);
@@ -855,14 +862,14 @@ void findColorMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *contro
  * @param crossList[out] list of detected TrackPoints
  * @param controlWidget
  */
-void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *controlWidget, RecognitionMethod recoMethod, Vec2F offsetCropRect2Roi /*=(0,0)*/)
+void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, RecognitionMethod recoMethod, const CodeMarkerOptions& opt)
 {
-    CodeMarkerItem* codeMarkerItem = controlWidget->getMainWindow()->getCodeMarkerItem();
-    CodeMarkerWidget* codeMarkerWidget = controlWidget->getMainWindow()->getCodeMarkerWidget();
+    CodeMarkerItem *codeMarkerItem = opt.codeMarkerItem;
+    const auto& par = opt.detectorParams;
 
-    cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(codeMarkerWidget->dictList->currentIndex()));
+    cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(opt.indexOfMarkerDict));
 
-    if (codeMarkerWidget->dictList->currentIndex() == 17) //for usage of DICT_mip_36h12 as it is not predifined in opencv
+    if (opt.indexOfMarkerDict == 17) //for usage of DICT_mip_36h12 as it is not predifined in opencv
     {
         dictionary = detail::getDictMip36h12();
     }
@@ -871,11 +878,11 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control
 
     double minMarkerPerimeterRate = 0.03, maxMarkerPerimeterRate = 4, minCornerDistanceRate = 0.05, minMarkerDistanceRate = 0.05;
 
-    Petrack *mainWindow = controlWidget->getMainWindow();
+    Petrack *mainWindow = opt.controlWidget->getMainWindow();
 
     int bS = mainWindow->getImageBorderSize();
 
-    if (controlWidget->getCalibCoordDimension() == 0) // 3D
+    if (opt.controlWidget->getCalibCoordDimension() == 0) // 3D
     {
         if (recoMethod == RecognitionMethod::Code)  // for usage of codemarker with CodeMarker-function (-> without MulticolorMarker)
         {
@@ -883,18 +890,18 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control
                        myRound(mainWindow->getRecoRoiItem()->rect().y()),
                        myRound(mainWindow->getRecoRoiItem()->rect().width()),
                        myRound(mainWindow->getRecoRoiItem()->rect().height()));
-            QPointF p1 = mainWindow->getImageItem()->getCmPerPixel(rect.x(),rect.y(),controlWidget->mapDefaultHeight->value()),
-                    p2 = mainWindow->getImageItem()->getCmPerPixel(rect.x()+rect.width(),rect.y(),controlWidget->mapDefaultHeight->value()),
-                    p3 = mainWindow->getImageItem()->getCmPerPixel(rect.x(),rect.y()+rect.height(),controlWidget->mapDefaultHeight->value()),
-                    p4 = mainWindow->getImageItem()->getCmPerPixel(rect.x()+rect.width(),rect.y()+rect.height(),controlWidget->mapDefaultHeight->value());
+            QPointF p1 = mainWindow->getImageItem()->getCmPerPixel(rect.x(),rect.y(),opt.controlWidget->mapDefaultHeight->value()),
+                    p2 = mainWindow->getImageItem()->getCmPerPixel(rect.x()+rect.width(),rect.y(),opt.controlWidget->mapDefaultHeight->value()),
+                    p3 = mainWindow->getImageItem()->getCmPerPixel(rect.x(),rect.y()+rect.height(),opt.controlWidget->mapDefaultHeight->value()),
+                    p4 = mainWindow->getImageItem()->getCmPerPixel(rect.x()+rect.width(),rect.y()+rect.height(),opt.controlWidget->mapDefaultHeight->value());
 
             double cmPerPixel_min = std::min(std::min(std::min(p1.x(), p1.y()), std::min(p2.x(), p2.y())),
                                              std::min(std::min(p3.x(), p3.y()), std::min(p4.x(), p4.y())));
             double cmPerPixel_max = std::max(std::max(std::max(p1.x(), p1.y()), std::max(p2.x(), p2.y())),
                                              std::max(std::max(p3.x(), p3.y()), std::max(p4.x(), p4.y())));
 
-            minMarkerPerimeterRate = (codeMarkerWidget->minMarkerPerimeter->value()*4./cmPerPixel_max)/std::max(rect.width(),rect.height());
-            maxMarkerPerimeterRate = (codeMarkerWidget->maxMarkerPerimeter->value()*4./cmPerPixel_min)/std::max(rect.width(),rect.height());
+            minMarkerPerimeterRate = (par.minMarkerPerimeter*4./cmPerPixel_max)/std::max(rect.width(),rect.height());
+            maxMarkerPerimeterRate = (par.maxMarkerPerimeter*4./cmPerPixel_min)/std::max(rect.width(),rect.height());
         } else if (recoMethod == RecognitionMethod::MultiColor)   // for usage of codemarker with MulticolorMarker
         {
             QRect rect(0,0, img.rows, img.cols);
@@ -904,44 +911,44 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control
             maxMarkerPerimeterRate = 4.;
         }
 
-        minCornerDistanceRate = codeMarkerWidget->minCornerDistance->value();
-        minMarkerDistanceRate = codeMarkerWidget->minMarkerDistance->value();
+        minCornerDistanceRate = par.minCornerDistance;
+        minMarkerDistanceRate = par.minMarkerDistance;
 
     }
     else // 2D
     {
         double cmPerPixel = mainWindow->getImageItem()->getCmPerPixel();
-        minMarkerPerimeterRate = (codeMarkerWidget->minMarkerPerimeter->value()*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS);
-        maxMarkerPerimeterRate = (codeMarkerWidget->maxMarkerPerimeter->value()*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS);
+        minMarkerPerimeterRate = (par.minMarkerPerimeter*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS);
+        maxMarkerPerimeterRate = (par.maxMarkerPerimeter*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS);
 
-        minCornerDistanceRate = codeMarkerWidget->minCornerDistance->value();
-        minMarkerDistanceRate = codeMarkerWidget->minMarkerDistance->value();
+        minCornerDistanceRate = par.minCornerDistance;
+        minMarkerDistanceRate = par.minMarkerDistance;
     }
 
-    detectorParams->adaptiveThreshWinSizeMin              = codeMarkerWidget->adaptiveThreshWinSizeMin->value();
-    detectorParams->adaptiveThreshWinSizeMax              = codeMarkerWidget->adaptiveThreshWinSizeMax->value();
-    detectorParams->adaptiveThreshWinSizeStep             = codeMarkerWidget->adaptiveThreshWinSizeStep->value();
-    detectorParams->adaptiveThreshConstant                = codeMarkerWidget->adaptiveThreshConstant->value();
+    detectorParams->adaptiveThreshWinSizeMin              = par.adaptiveThreshWinSizeMin;
+    detectorParams->adaptiveThreshWinSizeMax              = par.adaptiveThreshWinSizeMax;
+    detectorParams->adaptiveThreshWinSizeStep             = par.adaptiveThreshWinSizeStep;
+    detectorParams->adaptiveThreshConstant                = par.adaptiveThreshConstant;
     detectorParams->minMarkerPerimeterRate                = minMarkerPerimeterRate;
     detectorParams->maxMarkerPerimeterRate                = maxMarkerPerimeterRate;
-    detectorParams->polygonalApproxAccuracyRate           = codeMarkerWidget->polygonalApproxAccuracyRate->value();
+    detectorParams->polygonalApproxAccuracyRate           = par.polygonalApproxAccuracyRate;
     detectorParams->minCornerDistanceRate                 = minCornerDistanceRate;
-    detectorParams->minDistanceToBorder                   = codeMarkerWidget->minDistanceToBorder->value();
+    detectorParams->minDistanceToBorder                   = par.minDistanceToBorder;
     detectorParams->minMarkerDistanceRate                 = minMarkerDistanceRate;
     // No refinement is default value
     // TODO Check if this is the best MEthod for our usecase
-    if(codeMarkerWidget->doCornerRefinement->isChecked()){
+    if(par.doCornerRefinement){
         detectorParams->cornerRefinementMethod            = cv::aruco::CornerRefineMethod::CORNER_REFINE_SUBPIX;
     }
-    detectorParams->cornerRefinementWinSize               = codeMarkerWidget->cornerRefinementWinSize->value();
-    detectorParams->cornerRefinementMaxIterations         = codeMarkerWidget->cornerRefinementMaxIterations->value();
-    detectorParams->cornerRefinementMinAccuracy           = codeMarkerWidget->cornerRefinementMinAccuracy->value();
-    detectorParams->markerBorderBits                      = codeMarkerWidget->markerBorderBits->value();
-    detectorParams->perspectiveRemovePixelPerCell         = codeMarkerWidget->perspectiveRemovePixelPerCell->value();
-    detectorParams->perspectiveRemoveIgnoredMarginPerCell = codeMarkerWidget->perspectiveRemoveIgnoredMarginPerCell->value();
-    detectorParams->maxErroneousBitsInBorderRate          = codeMarkerWidget->maxErroneousBitsInBorderRate->value();
-    detectorParams->minOtsuStdDev                         = codeMarkerWidget->minOtsuStdDev->value();
-    detectorParams->errorCorrectionRate                   = codeMarkerWidget->errorCorrectionRate->value();
+    detectorParams->cornerRefinementWinSize               = par.cornerRefinementWinSize;
+    detectorParams->cornerRefinementMaxIterations         = par.cornerRefinementMaxIterations;
+    detectorParams->cornerRefinementMinAccuracy           = par.cornerRefinementMinAccuracy;
+    detectorParams->markerBorderBits                      = par.markerBorderBits;
+    detectorParams->perspectiveRemovePixelPerCell         = par.perspectiveRemovePixelPerCell;
+    detectorParams->perspectiveRemoveIgnoredMarginPerCell = par.perspectiveRemoveIgnoredMarginPerCell;
+    detectorParams->maxErroneousBitsInBorderRate          = par.maxErroneousBitsInBorderRate;
+    detectorParams->minOtsuStdDev                         = par.minOtsuStdDev;
+    detectorParams->errorCorrectionRate                   = par.errorCorrectionRate;
 
     std::vector<int> ids;
     std::vector<std::vector<cv::Point2f> > corners, rejected;
@@ -951,8 +958,8 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control
 
     cv::aruco::detectMarkers(img, dictionary, corners, ids, detectorParams, rejected);
 
-    codeMarkerItem->addDetectedMarkers(corners,ids, offsetCropRect2Roi);
-    codeMarkerItem->addRejectedMarkers(rejected, offsetCropRect2Roi);
+    codeMarkerItem->addDetectedMarkers(corners,ids, opt.offsetCropRect2Roi);
+    codeMarkerItem->addRejectedMarkers(rejected, opt.offsetCropRect2Roi);
 
     // detected code markers
     for(size_t i = 0; i<ids.size(); i++)
@@ -1100,13 +1107,13 @@ QList<TrackPoint> Recognizer::getMarkerPos(cv::Mat &img, QRect &roi, Control *co
 
     switch (mRecoMethod) {
         case RecognitionMethod::MultiColor:
-            findMultiColorMarker(tImg, crossList, controlWidget, ignoreWithoutMarker, v, mRecoMethod);
+            findMultiColorMarker(tImg, crossList, controlWidget, ignoreWithoutMarker, v, mRecoMethod, mCodeMarkerOptions);
             break;
         case RecognitionMethod::Color:
             findColorMarker(tImg, crossList, controlWidget);
             break;
         case RecognitionMethod::Code:
-            findCodeMarker(tImg, crossList, controlWidget, mRecoMethod);
+            findCodeMarker(tImg, crossList, mRecoMethod, mCodeMarkerOptions);
             break;
         case RecognitionMethod::Casern: [[fallthrough]];
         case RecognitionMethod::Hermes: [[fallthrough]];
@@ -1142,6 +1149,21 @@ QList<TrackPoint> Recognizer::getMarkerPos(cv::Mat &img, QRect &roi, Control *co
     return crossList;
 }
 
+void CodeMarkerOptions::userChangedDetectorParams(ArucoCodeParams params)
+{
+    if(params != detectorParams){
+        detectorParams = params;
+        emit detectorParamsChanged();
+    }
+}
+
+void CodeMarkerOptions::userChangedIndexOfMarkerDict(int idx)
+{
+    if(idx != indexOfMarkerDict){
+        indexOfMarkerDict = idx;
+        emit indexOfMarkerDictChanged();
+    }
+}
 
 /**
  * @brief getMip36h12Dict() overrides current dictionary with dictionary from 'aruco_mip_36h12_dict'