diff --git a/include/codeMarkerItem.h b/include/codeMarkerItem.h index bd5b8307451a8e110629231871627fe4d7b3f318..1263cce759d98134985a420917e7647b1155e0a1 100644 --- a/include/codeMarkerItem.h +++ b/include/codeMarkerItem.h @@ -28,6 +28,10 @@ class Petrack; class Control; class Tracker; +namespace reco { + class CodeMarkerOptions; +} + struct OffsetMarker { std::vector<cv::Point2f> corners; @@ -40,6 +44,7 @@ class CodeMarkerItem : public QGraphicsItem { private: Petrack *mMainWindow; + const reco::CodeMarkerOptions &mArucoOptions; const QColor mRejectedColor = QColor(255,0,0); // red const QColor mCornerColor = QColor(0,0,255); // blue const QColor mAcceptedColor = QColor(0,255,0); // green @@ -49,7 +54,7 @@ private: Vec2F mUlc; // upper left corner to draw public: - CodeMarkerItem(QWidget *wParent, QGraphicsItem * parent = nullptr); + CodeMarkerItem(QWidget *wParent, const reco::CodeMarkerOptions &options, QGraphicsItem * parent = nullptr); QRectF boundingRect() const override; void setRect(Vec2F& v); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; diff --git a/include/codeMarkerWidget.h b/include/codeMarkerWidget.h index 8fc06b18b4a4db7b2f6cf82db1405dc9231edadd..658a18568b0f38fd62ad8f59e8ccdbfde2b7c943 100644 --- a/include/codeMarkerWidget.h +++ b/include/codeMarkerWidget.h @@ -24,18 +24,23 @@ #include <QtWidgets> #include <opencv2/aruco.hpp> -#include "ui_codeMarker.h" + #include "petrack.h" #include "codeMarkerItem.h" #include "recognition.h" +namespace Ui{ + class CodeMarker; +} + + -class CodeMarkerWidget: public QWidget, public Ui::CodeMarker +class CodeMarkerWidget: public QWidget { Q_OBJECT public: - CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& opt); + CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& opt, Ui::CodeMarker *mUi); // store data in xml node void setXml(QDomElement &elem); @@ -43,8 +48,7 @@ public: // read data from xml node void getXml(QDomElement &elem); - reco::ArucoCodeParams packDetectorParams(); - + bool showDetectedCandidates(); private slots: @@ -62,8 +66,12 @@ private slots: void readDictListIndex(); private: + Ui::CodeMarker *mUi; + Petrack *mMainWindow; reco::CodeMarkerOptions &mCodeMarkerOpt; }; +reco::ArucoCodeParams packDetectorParams(const Ui::CodeMarker *ui); + #endif diff --git a/include/recognition.h b/include/recognition.h index 4076c237b830f61e2057c3a302238d2cec32772e..3a190d05f460b05814d3cc71e3b9395c52bea2d8 100644 --- a/include/recognition.h +++ b/include/recognition.h @@ -51,7 +51,7 @@ namespace reco { Code = 6, }; - struct ArucoCodeParams { + class ArucoCodeParams { double minMarkerPerimeter = 5; double maxMarkerPerimeter = 15; double minCornerDistance = 0.05; @@ -73,6 +73,8 @@ namespace reco { double minOtsuStdDev = 5; double errorCorrectionRate = 0.6; + public: + 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))))))))))))))))))); @@ -81,13 +83,53 @@ namespace reco { { return !(lhs == rhs); } + double getMinMarkerPerimeter() const; + void setMinMarkerPerimeter(double newMinMarkerPerimeter); + double getMaxMarkerPerimeter() const; + void setMaxMarkerPerimeter(double newMaxMarkerPerimeter); + double getMinCornerDistance() const; + void setMinCornerDistance(double newMinCornerDistance); + double getMinMarkerDistance() const; + void setMinMarkerDistance(double newMinMarkerDistance); + int getAdaptiveThreshWinSizeMin() const; + void setAdaptiveThreshWinSizeMin(int newAdaptiveThreshWinSizeMin); + int getAdaptiveThreshWinSizeMax() const; + void setAdaptiveThreshWinSizeMax(int newAdaptiveThreshWinSizeMax); + int getAdaptiveThreshWinSizeStep() const; + void setAdaptiveThreshWinSizeStep(int newAdaptiveThreshWinSizeStep); + int getAdaptiveThreshConstant() const; + void setAdaptiveThreshConstant(int newAdaptiveThreshConstant); + double getPolygonalApproxAccuracyRate() const; + void setPolygonalApproxAccuracyRate(double newPolygonalApproxAccuracyRate); + int getMinDistanceToBorder() const; + void setMinDistanceToBorder(int newMinDistanceToBorder); + bool getDoCornerRefinement() const; + void setDoCornerRefinement(bool newDoCornerRefinement); + int getCornerRefinementWinSize() const; + void setCornerRefinementWinSize(int newCornerRefinementWinSize); + int getCornerRefinementMaxIterations() const; + void setCornerRefinementMaxIterations(int newCornerRefinementMaxIterations); + double getCornerRefinementMinAccuracy() const; + void setCornerRefinementMinAccuracy(double newCornerRefinementMinAccuracy); + int getMarkerBorderBits() const; + void setMarkerBorderBits(int newMarkerBorderBits); + int getPerspectiveRemovePixelPerCell() const; + void setPerspectiveRemovePixelPerCell(int newPerspectiveRemovePixelPerCell); + double getPerspectiveRemoveIgnoredMarginPerCell() const; + void setPerspectiveRemoveIgnoredMarginPerCell(double newPerspectiveRemoveIgnoredMarginPerCell); + double getMaxErroneousBitsInBorderRate() const; + void setMaxErroneousBitsInBorderRate(double newMaxErroneousBitsInBorderRate); + double getMinOtsuStdDev() const; + void setMinOtsuStdDev(double newMinOtsuStdDev); + double getErrorCorrectionRate() const; + void setErrorCorrectionRate(double newErrorCorrectionRate); }; - struct CodeMarkerOptions : public QObject{ + class CodeMarkerOptions : public QObject{ Q_OBJECT - public: + private: CodeMarkerItem *codeMarkerItem; int indexOfMarkerDict = 16; @@ -97,12 +139,22 @@ namespace reco { Vec2F offsetCropRect2Roi = Vec2F{0,0}; public: + // TODO: Remove getter and setter for pointers; + // cannot properly set these in constructor because of + // bidirectional dependecies + CodeMarkerItem *getCodeMarkerItem() const {return codeMarkerItem;} + Control *getControlWidget() const {return controlWidget;} ArucoCodeParams getDetectorParams() const {return detectorParams;} int getIndexOfMarkerDict() const {return indexOfMarkerDict;} public: - void userChangedDetectorParams(ArucoCodeParams params); - void userChangedIndexOfMarkerDict(int idx); + void setCodeMarkerItem(CodeMarkerItem *item) {codeMarkerItem = item;} + void setControlWidget(Control *control) {controlWidget = control;} + void setDetectorParams(ArucoCodeParams params); + void setIndexOfMarkerDict(int idx); + + const Vec2F &getOffsetCropRect2Roi() const; + void setOffsetCropRect2Roi(const Vec2F &newOffsetCropRect2Roi); signals: void detectorParamsChanged(); diff --git a/src/codeMarkerItem.cpp b/src/codeMarkerItem.cpp index c959e4ead4d74a1b836c3709c2f630ac91642c01..ba27927ee8b75dae682429ed27eb9d2256b5e4d8 100644 --- a/src/codeMarkerItem.cpp +++ b/src/codeMarkerItem.cpp @@ -29,9 +29,9 @@ // in x und y gleichermassen skaliertes koordinatensystem, // da von einer vorherigen intrinsischen kamerakalibrierung ausgegenagen wird, -// so dass pixel quadratisch -CodeMarkerItem::CodeMarkerItem(QWidget *wParent, QGraphicsItem * parent) - : QGraphicsItem(parent) +// so dass pixel quadratisch +CodeMarkerItem::CodeMarkerItem(QWidget *wParent, const reco::CodeMarkerOptions &options, QGraphicsItem * parent) + : QGraphicsItem(parent), mArucoOptions(options) { mMainWindow = (class Petrack*) wParent; } @@ -73,7 +73,7 @@ void CodeMarkerItem::setRect(Vec2F& v) void CodeMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/) { - if (mMainWindow->getCodeMarkerWidget()->showDetectedCandidates->isChecked()) + if (mMainWindow->getCodeMarkerWidget()->showDetectedCandidates()) { int nMarkers = static_cast<int>(mCorners.size()); int nRejected = static_cast<int>(mRejected.size()); @@ -91,8 +91,8 @@ void CodeMarkerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem */* if (false) // Show min/max marker size { - int minPerimeter = mMainWindow->getCodeMarkerWidget()->minMarkerPerimeter->value(); - int maxPerimeter = mMainWindow->getCodeMarkerWidget()->maxMarkerPerimeter->value(); + int minPerimeter = mArucoOptions.getDetectorParams().getMinMarkerPerimeter(); + int maxPerimeter = mArucoOptions.getDetectorParams().getMaxMarkerPerimeter(); double height = mMainWindow->getStatusPosRealHeight(); cv::Point2f p0,p1,p2,p3; diff --git a/src/codeMarkerWidget.cpp b/src/codeMarkerWidget.cpp index b141e6bdf508621caf5cf36719dafeb65d5429de..0982a4385573cd1fb1a234754d013ed49de87064 100644 --- a/src/codeMarkerWidget.cpp +++ b/src/codeMarkerWidget.cpp @@ -20,38 +20,46 @@ #include <opencv2/core/version.hpp> +#include "ui_codeMarker.h" + #include "codeMarkerWidget.h" #include "recognition.h" +#include "pMessageBox.h" -CodeMarkerWidget::CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& codeMarkerOpt) +CodeMarkerWidget::CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& codeMarkerOpt, Ui::CodeMarker* ui) : QWidget(parent), mCodeMarkerOpt(codeMarkerOpt) { mMainWindow = (class Petrack*) parent; + if(!ui){ + mUi = new Ui::CodeMarker(); + }else{ + mUi = ui; + } - setupUi(this); + mUi->setupUi(this); - dictList->addItem("DICT_4X4_50"); // 0 - dictList->addItem("DICT_4X4_100"); // 1 - dictList->addItem("DICT_4X4_250"); // 2 - dictList->addItem("DICT_4X4_1000");// 3 + mUi->dictList->addItem("DICT_4X4_50"); // 0 + mUi->dictList->addItem("DICT_4X4_100"); // 1 + mUi->dictList->addItem("DICT_4X4_250"); // 2 + mUi->dictList->addItem("DICT_4X4_1000");// 3 - dictList->addItem("DICT_5X5_50"); // 4 - dictList->addItem("DICT_5X5_100"); // 5 - dictList->addItem("DICT_5X5_250"); // 6 - dictList->addItem("DICT_5X5_1000");// 7 + mUi->dictList->addItem("DICT_5X5_50"); // 4 + mUi->dictList->addItem("DICT_5X5_100"); // 5 + mUi->dictList->addItem("DICT_5X5_250"); // 6 + mUi->dictList->addItem("DICT_5X5_1000");// 7 - dictList->addItem("DICT_6X6_50"); // 8 - dictList->addItem("DICT_6X6_100"); // 9 - dictList->addItem("DICT_6X6_250"); // 10 - dictList->addItem("DICT_6X6_1000");// 11 + mUi->dictList->addItem("DICT_6X6_50"); // 8 + mUi->dictList->addItem("DICT_6X6_100"); // 9 + mUi->dictList->addItem("DICT_6X6_250"); // 10 + mUi->dictList->addItem("DICT_6X6_1000");// 11 - dictList->addItem("DICT_7X7_50"); // 12 - dictList->addItem("DICT_7X7_100"); // 13 - dictList->addItem("DICT_7X7_250"); // 14 - dictList->addItem("DICT_7X7_1000");// 15 + mUi->dictList->addItem("DICT_7X7_50"); // 12 + mUi->dictList->addItem("DICT_7X7_100"); // 13 + mUi->dictList->addItem("DICT_7X7_250"); // 14 + mUi->dictList->addItem("DICT_7X7_1000");// 15 - dictList->addItem("DICT_ARUCO_ORGINAL"); // 16 - dictList->addItem("DICT_mip_36h12");//17 + mUi->dictList->addItem("DICT_ARUCO_ORGINAL"); // 16 + mUi->dictList->addItem("DICT_mip_36h12");//17 connect(&mCodeMarkerOpt, &reco::CodeMarkerOptions::detectorParamsChanged, this, &CodeMarkerWidget::readDetectorParams); connect(&mCodeMarkerOpt, &reco::CodeMarkerOptions::indexOfMarkerDictChanged, this, &CodeMarkerWidget::readDictListIndex); @@ -64,34 +72,39 @@ CodeMarkerWidget::CodeMarkerWidget(QWidget *parent, reco::CodeMarkerOptions& cod // 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()); + try{ + sendDetectorParams(packDetectorParams(mUi)); notifyChanged(); + }catch(std::invalid_argument &e){ + PWarning(this, "Wrong Value", e.what()); + readDetectorParams(); + } }; - 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); + connect(mUi->minMarkerPerimeter, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->maxMarkerPerimeter, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + + connect(mUi->adaptiveThreshWinSizeMin, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->adaptiveThreshWinSizeMax, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->adaptiveThreshWinSizeStep, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->adaptiveThreshConstant, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + + connect(mUi->polygonalApproxAccuracyRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->minCornerDistance, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->minDistanceToBorder, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->minMarkerDistance, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + + connect(mUi->doCornerRefinement, &QGroupBox::clicked, changedParams); + connect(mUi->cornerRefinementWinSize, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->cornerRefinementMaxIterations, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->cornerRefinementMinAccuracy, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + + connect(mUi->markerBorderBits, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->perspectiveRemovePixelPerCell, QOverload<int>::of(&QSpinBox::valueChanged), changedParams); + connect(mUi->perspectiveRemoveIgnoredMarginPerCell, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->maxErroneousBitsInBorderRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->errorCorrectionRate, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); + connect(mUi->minOtsuStdDev, QOverload<double>::of(&QDoubleSpinBox::valueChanged), changedParams); } //<COLOR_MARKER> @@ -107,31 +120,31 @@ void CodeMarkerWidget::setXml(QDomElement &elem) QDomElement subElem; subElem = (elem.ownerDocument()).createElement("DICTIONARY"); - subElem.setAttribute("ID", dictList->currentIndex()); + subElem.setAttribute("ID", mUi->dictList->currentIndex()); elem.appendChild(subElem); subElem = (elem.ownerDocument()).createElement("PARAM"); - subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_MIN",adaptiveThreshWinSizeMin->value()); - subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_MAX",adaptiveThreshWinSizeMax->value()); - subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_STEP",adaptiveThreshWinSizeStep->value()); - subElem.setAttribute("ADAPTIVE_THRESH_CONSTANT",adaptiveThreshConstant->value()); - subElem.setAttribute("MIN_MARKER_PERIMETER",minMarkerPerimeter->value()); - subElem.setAttribute("MAX_MARKER_PERIMETER",maxMarkerPerimeter->value()); - subElem.setAttribute("MAX_RATIO_ERROR",polygonalApproxAccuracyRate->value()); - subElem.setAttribute("MIN_CORNER_DISTANCE",minCornerDistance->value()); - subElem.setAttribute("MIN_DISTANCE_TO_BORDER",minDistanceToBorder->value()); - subElem.setAttribute("MIN_MARKER_DISTANCE",minMarkerDistance->value()); - subElem.setAttribute("CORNER_REFINEMENT", doCornerRefinement->isChecked()); - subElem.setAttribute("CORNER_REFINEMENT_WIN_SIZE",cornerRefinementWinSize->value()); - subElem.setAttribute("CORNER_REFINEMENT_MAX_ITERATIONS",cornerRefinementMaxIterations->value()); - subElem.setAttribute("CORNER_REFINEMENT_MIN_ACCURACY",cornerRefinementMinAccuracy->value()); - subElem.setAttribute("MARKER_BORDER_BITS",markerBorderBits->value()); - subElem.setAttribute("PERSPECTIVE_REMOVE_PIXEL_PER_CELL",perspectiveRemovePixelPerCell->value()); - subElem.setAttribute("PERSPECTIVE_REMOVE_IGNORED_MARGIN_PER_CELL",perspectiveRemoveIgnoredMarginPerCell->value()); - subElem.setAttribute("MAX_ERRONEOUS_BITS_IN_BORDER_RATE",maxErroneousBitsInBorderRate->value()); - subElem.setAttribute("MIN_OTSU_STD_DEV",minOtsuStdDev->value()); - subElem.setAttribute("ERROR_CORRECTION_RATE",errorCorrectionRate->value()); - subElem.setAttribute("SHOW_DETECTED_CANDIDATES", showDetectedCandidates->isChecked()); + subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_MIN",mUi->adaptiveThreshWinSizeMin->value()); + subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_MAX",mUi->adaptiveThreshWinSizeMax->value()); + subElem.setAttribute("ADAPTIVE_THRESH_WIN_SIZE_STEP",mUi->adaptiveThreshWinSizeStep->value()); + subElem.setAttribute("ADAPTIVE_THRESH_CONSTANT",mUi->adaptiveThreshConstant->value()); + subElem.setAttribute("MIN_MARKER_PERIMETER",mUi->minMarkerPerimeter->value()); + subElem.setAttribute("MAX_MARKER_PERIMETER",mUi->maxMarkerPerimeter->value()); + subElem.setAttribute("MAX_RATIO_ERROR",mUi->polygonalApproxAccuracyRate->value()); + subElem.setAttribute("MIN_CORNER_DISTANCE",mUi->minCornerDistance->value()); + subElem.setAttribute("MIN_DISTANCE_TO_BORDER",mUi->minDistanceToBorder->value()); + subElem.setAttribute("MIN_MARKER_DISTANCE",mUi->minMarkerDistance->value()); + subElem.setAttribute("CORNER_REFINEMENT",mUi-> doCornerRefinement->isChecked()); + subElem.setAttribute("CORNER_REFINEMENT_WIN_SIZE",mUi->cornerRefinementWinSize->value()); + subElem.setAttribute("CORNER_REFINEMENT_MAX_ITERATIONS",mUi->cornerRefinementMaxIterations->value()); + subElem.setAttribute("CORNER_REFINEMENT_MIN_ACCURACY",mUi->cornerRefinementMinAccuracy->value()); + subElem.setAttribute("MARKER_BORDER_BITS",mUi->markerBorderBits->value()); + subElem.setAttribute("PERSPECTIVE_REMOVE_PIXEL_PER_CELL",mUi->perspectiveRemovePixelPerCell->value()); + subElem.setAttribute("PERSPECTIVE_REMOVE_IGNORED_MARGIN_PER_CELL",mUi->perspectiveRemoveIgnoredMarginPerCell->value()); + subElem.setAttribute("MAX_ERRONEOUS_BITS_IN_BORDER_RATE",mUi->maxErroneousBitsInBorderRate->value()); + subElem.setAttribute("MIN_OTSU_STD_DEV",mUi->minOtsuStdDev->value()); + subElem.setAttribute("ERROR_CORRECTION_RATE",mUi->errorCorrectionRate->value()); + subElem.setAttribute("SHOW_DETECTED_CANDIDATES",mUi-> showDetectedCandidates->isChecked()); elem.appendChild(subElem); } @@ -148,82 +161,88 @@ void CodeMarkerWidget::getXml(QDomElement &elem) if (subElem.tagName() == "DICTIONARY") { if (subElem.hasAttribute("ID")) - dictList->setCurrentIndex(subElem.attribute("ID").toInt()); + mUi->dictList->setCurrentIndex(subElem.attribute("ID").toInt()); } if (subElem.tagName() == "PARAM") { - if (subElem.hasAttribute("ADAPTIVE_THRESH_WIN_SIZE_MIN")) - adaptiveThreshWinSizeMin->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_MIN").toInt()); - if (subElem.hasAttribute("ADAPTIVE_THRESH_WIN_SIZE_MAX")) - adaptiveThreshWinSizeMax->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_MAX").toInt()); - if (subElem.hasAttribute("ADAPTIVE_THRESH_WIN_SIZE_STEP")) - adaptiveThreshWinSizeStep->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_STEP").toInt()); - if (subElem.hasAttribute("ADAPTIVE_THRESH_CONSTANT")) - adaptiveThreshConstant->setValue(subElem.attribute("ADAPTIVE_THRESH_CONSTANT").toInt()); + if (subElem.hasAttribute("ADAPTIVE_TRHESH_WIN_SIZE_MIN")) + mUi->adaptiveThreshWinSizeMin->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_MIN").toInt()); + if (subElem.hasAttribute("ADAPTIVE_TRHESH_WIN_SIZE_MAX")) + mUi->adaptiveThreshWinSizeMax->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_MAX").toInt()); + if (subElem.hasAttribute("ADAPTIVE_TRHESH_WIN_SIZE_STEP")) + mUi->adaptiveThreshWinSizeStep->setValue(subElem.attribute("ADAPTIVE_THRESH_WIN_SIZE_STEP").toInt()); + if (subElem.hasAttribute("ADAPTIVE_TRHESH_CONSTANT")) + mUi->adaptiveThreshConstant->setValue(subElem.attribute("ADAPTIVE_THRESH_CONSTANT").toInt()); if (subElem.hasAttribute("MIN_MARKER_PERIMETER")) - minMarkerPerimeter->setValue(subElem.attribute("MIN_MARKER_PERIMETER").toDouble()); + mUi->minMarkerPerimeter->setValue(subElem.attribute("MIN_MARKER_PERIMETER").toDouble()); if (subElem.hasAttribute("MAX_MARKER_PERIMETER")) - maxMarkerPerimeter->setValue(subElem.attribute("MAX_MARKER_PERIMETER").toDouble()); + mUi->maxMarkerPerimeter->setValue(subElem.attribute("MAX_MARKER_PERIMETER").toDouble()); if (subElem.hasAttribute("MAX_RATIO_ERROR")) - polygonalApproxAccuracyRate->setValue(subElem.attribute("MAX_RATIO_ERROR").toDouble()); + mUi->polygonalApproxAccuracyRate->setValue(subElem.attribute("MAX_RATIO_ERROR").toDouble()); if (subElem.hasAttribute("MIN_CORNER_DISTANCE")) - minCornerDistance->setValue(subElem.attribute("MIN_CORNER_DISTANCE").toDouble()); + mUi->minCornerDistance->setValue(subElem.attribute("MIN_CORNER_DISTANCE").toDouble()); if (subElem.hasAttribute("MIN_DISTANCE_TO_BORDER")) - minDistanceToBorder->setValue(subElem.attribute("MIN_DISTANCE_TO_BORDER").toInt()); + mUi->minDistanceToBorder->setValue(subElem.attribute("MIN_DISTANCE_TO_BORDER").toInt()); if (subElem.hasAttribute("MIN_MARKER_DISTANCE")) - minMarkerDistance->setValue(subElem.attribute("MIN_MARKER_DISTANCE").toDouble()); + mUi->minMarkerDistance->setValue(subElem.attribute("MIN_MARKER_DISTANCE").toDouble()); if (subElem.hasAttribute("CORNER_REFINEMENT")) - doCornerRefinement->setChecked(subElem.attribute("CORNER_REFINEMENT").toInt()); - if (subElem.hasAttribute("CORNER_REFINEMENT_WIN_SIZE")) - cornerRefinementWinSize->setValue(subElem.attribute("CORNER_REFINEMENT_WIN_SIZE").toInt()); + mUi->doCornerRefinement->setChecked(subElem.attribute("CORNER_REFINEMENT").toInt()); + if (subElem.hasAttribute("CORNER_REFINEMENT_WIN_SIZE")) + mUi->cornerRefinementWinSize->setValue(subElem.attribute("CORNER_REFINEMENT_WIN_SIZE").toInt()); if (subElem.hasAttribute("CORNER_REFINEMENT_MAX_ITERATIONS")) - cornerRefinementMaxIterations->setValue(subElem.attribute("CORNER_REFINEMENT_MAX_ITERATIONS").toInt()); + mUi->cornerRefinementMaxIterations->setValue(subElem.attribute("CORNER_REFINEMENT_MAX_ITERATIONS").toInt()); if (subElem.hasAttribute("CORNER_REFINEMENT_MIN_ACCURACY")) - cornerRefinementMinAccuracy->setValue(subElem.attribute("CORNER_REFINEMENT_MIN_ACCURACY").toDouble()); + mUi->cornerRefinementMinAccuracy->setValue(subElem.attribute("CORNER_REFINEMENT_MIN_ACCURACY").toDouble()); if (subElem.hasAttribute("MARKER_BORDER_BITS")) - markerBorderBits->setValue(subElem.attribute("MARKER_BORDER_BITS").toInt()); + mUi->markerBorderBits->setValue(subElem.attribute("MARKER_BORDER_BITS").toInt()); if (subElem.hasAttribute("PERSPECTIVE_REMOVE_PIXEL_PER_CELL")) - perspectiveRemovePixelPerCell->setValue(subElem.attribute("PERSPECTIVE_REMOVE_PIXEL_PER_CELL").toInt()); + mUi->perspectiveRemovePixelPerCell->setValue(subElem.attribute("PERSPECTIVE_REMOVE_PIXEL_PER_CELL").toInt()); if (subElem.hasAttribute("PERSPECTIVE_REMOVE_IGNORED_MARGIN_PER_CELL")) - perspectiveRemoveIgnoredMarginPerCell->setValue(subElem.attribute("PERSPECTIVE_REMOVE_IGNORED_MARGIN_PER_CELL").toDouble()); + mUi->perspectiveRemoveIgnoredMarginPerCell->setValue(subElem.attribute("PERSPECTIVE_REMOVE_IGNORED_MARGIN_PER_CELL").toDouble()); if (subElem.hasAttribute("MAX_ERRONEOUS_BITS_IN_BORDER_RATE")) - maxErroneousBitsInBorderRate->setValue(subElem.attribute("MAX_ERRONEOUS_BITS_IN_BORDER_RATE").toDouble()); + mUi->maxErroneousBitsInBorderRate->setValue(subElem.attribute("MAX_ERRONEOUS_BITS_IN_BORDER_RATE").toDouble()); if (subElem.hasAttribute("MIN_OTSU_STD_DEV")) - minOtsuStdDev->setValue(subElem.attribute("MIN_OTSU_STD_DEV").toDouble()); + mUi->minOtsuStdDev->setValue(subElem.attribute("MIN_OTSU_STD_DEV").toDouble()); if (subElem.hasAttribute("ERROR_CORRECTION_RATE")) - errorCorrectionRate->setValue(subElem.attribute("ERROR_CORRECTION_RATE").toDouble()); + mUi->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); + mUi->showDetectedCandidates->setCheckState(subElem.attribute("SHOW_DETECTED_CANDIDATES").toInt() ? Qt::Checked : Qt::Unchecked); } } } -reco::ArucoCodeParams CodeMarkerWidget::packDetectorParams() +reco::ArucoCodeParams packDetectorParams(const Ui::CodeMarker *ui) { 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(); + params.setAdaptiveThreshConstant(ui->adaptiveThreshConstant->value()); + params.setAdaptiveThreshWinSizeMax(ui->adaptiveThreshWinSizeMax->value()); + params.setAdaptiveThreshWinSizeMin(ui->adaptiveThreshWinSizeMin->value()); + params.setAdaptiveThreshWinSizeStep(ui->adaptiveThreshWinSizeStep->value()); + params.setCornerRefinementMaxIterations(ui->cornerRefinementMaxIterations->value()); + params.setCornerRefinementMinAccuracy(ui->cornerRefinementMinAccuracy->value()); + params.setCornerRefinementWinSize(ui->cornerRefinementWinSize->value()); + params.setDoCornerRefinement(ui->doCornerRefinement->isChecked()); + params.setErrorCorrectionRate(ui->errorCorrectionRate->value()); + params.setMarkerBorderBits(ui->markerBorderBits->value()); + params.setMaxErroneousBitsInBorderRate(ui->maxErroneousBitsInBorderRate->value()); + params.setMinDistanceToBorder(ui->minDistanceToBorder->value()); + params.setMinMarkerDistance(ui->minMarkerDistance->value()); + params.setMaxMarkerPerimeter(ui->maxMarkerPerimeter->value()); + params.setMinMarkerPerimeter(ui->minMarkerPerimeter->value()); + params.setMinOtsuStdDev(ui->minOtsuStdDev->value()); + params.setPerspectiveRemoveIgnoredMarginPerCell(ui->perspectiveRemoveIgnoredMarginPerCell->value()); + params.setPerspectiveRemovePixelPerCell(ui->perspectiveRemovePixelPerCell->value()); + params.setPolygonalApproxAccuracyRate(ui->polygonalApproxAccuracyRate->value()); return params; } +bool CodeMarkerWidget::showDetectedCandidates() +{ + return mUi->showDetectedCandidates->isChecked(); +} + void CodeMarkerWidget::on_showDetectedCandidates_stateChanged(int i) { mMainWindow->getCodeMarkerItem()->setVisible(i); @@ -240,7 +259,7 @@ void CodeMarkerWidget::on_moreInfosButton_clicked() void CodeMarkerWidget::on_dictList_currentIndexChanged(int i) { - mCodeMarkerOpt.userChangedIndexOfMarkerDict(i); + mCodeMarkerOpt.setIndexOfMarkerDict(i); notifyChanged(); } @@ -255,34 +274,35 @@ void CodeMarkerWidget::notifyChanged() 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); + mUi->adaptiveThreshConstant->setValue(params.getAdaptiveThreshConstant()); + mUi->adaptiveThreshWinSizeMax->setValue(params.getAdaptiveThreshWinSizeMax()); + mUi->adaptiveThreshWinSizeMin->setValue(params.getAdaptiveThreshWinSizeMin()); + mUi->adaptiveThreshWinSizeStep->setValue(params.getAdaptiveThreshWinSizeStep()); + mUi->cornerRefinementMaxIterations->setValue(params.getCornerRefinementMaxIterations()); + mUi->cornerRefinementMinAccuracy->setValue(params.getCornerRefinementMinAccuracy()); + mUi->cornerRefinementWinSize->setValue(params.getCornerRefinementWinSize()); + mUi->doCornerRefinement->setChecked(params.getDoCornerRefinement()); + mUi->errorCorrectionRate->setValue(params.getErrorCorrectionRate()); + mUi->markerBorderBits->setValue(params.getMarkerBorderBits()); + mUi->maxErroneousBitsInBorderRate->setValue(params.getMaxErroneousBitsInBorderRate()); + mUi->minDistanceToBorder->setValue(params.getMinDistanceToBorder()); + mUi->minMarkerDistance->setValue(params.getMinMarkerDistance()); + mUi->maxMarkerPerimeter->setValue(params.getMaxMarkerPerimeter()); + mUi->minMarkerPerimeter->setValue(params.getMinMarkerPerimeter()); + mUi->minOtsuStdDev->setValue(params.getMinOtsuStdDev()); + mUi->perspectiveRemoveIgnoredMarginPerCell->setValue(params.getPerspectiveRemoveIgnoredMarginPerCell()); + mUi->perspectiveRemovePixelPerCell->setValue(params.getPerspectiveRemovePixelPerCell()); + mUi->polygonalApproxAccuracyRate->setValue(params.getPolygonalApproxAccuracyRate()); } void CodeMarkerWidget::readDictListIndex() { - dictList->setCurrentIndex(mCodeMarkerOpt.getIndexOfMarkerDict()); + mUi->dictList->setCurrentIndex(mCodeMarkerOpt.getIndexOfMarkerDict()); } void CodeMarkerWidget::sendDetectorParams(reco::ArucoCodeParams params) { - mCodeMarkerOpt.userChangedDetectorParams(params); + mCodeMarkerOpt.setDetectorParams(params); } #include "moc_codeMarkerWidget.cpp" diff --git a/src/petrack.cpp b/src/petrack.cpp index afd58b41ca2555145c8abee63a761d2bae7dcb1b..00cbb5f423bfa7784c09e1ff7b0eab641d09bceb 100644 --- a/src/petrack.cpp +++ b/src/petrack.cpp @@ -127,7 +127,7 @@ Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPa mColorMarkerWidget->setWindowFlags(Qt::Window); mColorMarkerWidget->setWindowTitle("Color marker parameter"); - mCodeMarkerWidget = new CodeMarkerWidget(this, mReco.getCodeMarkerOptions()); + mCodeMarkerWidget = new CodeMarkerWidget(this, mReco.getCodeMarkerOptions(), nullptr); mCodeMarkerWidget->setWindowFlags(Qt::Window); mCodeMarkerWidget->setWindowTitle("Code marker parameter"); @@ -203,7 +203,7 @@ Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPa mColorMarkerItem->setVisible(false); //--------------------------- - mCodeMarkerItem = new CodeMarkerItem(this); + mCodeMarkerItem = new CodeMarkerItem(this, mReco.getCodeMarkerOptions()); mCodeMarkerItem->setZValue(2);// groesser heisst weiter oben mCodeMarkerItem->setVisible(false); //--------------------------- @@ -271,8 +271,8 @@ Petrack::Petrack() : mAuthors(IO::readAuthors(QCoreApplication::applicationDirPa 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; + mReco.getCodeMarkerOptions().setControlWidget(mControlWidget); + mReco.getCodeMarkerOptions().setCodeMarkerItem(mCodeMarkerItem); mSeqFileName = QDir::currentPath(); //fuer allerersten Aufruf des Programms readSettings(); diff --git a/src/recognition.cpp b/src/recognition.cpp index 023f3d47ce3e613f7de9b0f48b1c5b5c3c67f06a..fb448346eae3ddd4ce575fb09960f899eca29779 100644 --- a/src/recognition.cpp +++ b/src/recognition.cpp @@ -582,7 +582,7 @@ void detail::refineWithAruco(std::vector<ColorBlob> &blobs, const cv::Mat& img, continue; // TODO: Use Reference to actual codeMarkerOptions in MulticolorMarkerOptions // NOTE: For now, add as parameter of findMulticolorMarker - codeOpt.offsetCropRect2Roi = offsetCropRect2Roi; + codeOpt.setOffsetCropRect2Roi(offsetCropRect2Roi); findCodeMarker(subImg, crossList, options.method, codeOpt); // The next three statements each: @@ -636,7 +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}; + codeOpt.setOffsetCropRect2Roi(Vec2F{0,0}); } /** @@ -864,12 +864,13 @@ void findColorMarker(cv::Mat &img, QList<TrackPoint> &crossList, Control *contro */ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, RecognitionMethod recoMethod, const CodeMarkerOptions& opt) { - CodeMarkerItem *codeMarkerItem = opt.codeMarkerItem; - const auto& par = opt.detectorParams; + CodeMarkerItem *codeMarkerItem = opt.getCodeMarkerItem(); + Control *controlWidget = opt.getControlWidget(); + const auto& par = opt.getDetectorParams(); - cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(opt.indexOfMarkerDict)); + cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(opt.getIndexOfMarkerDict())); - if (opt.indexOfMarkerDict == 17) //for usage of DICT_mip_36h12 as it is not predifined in opencv + if (opt.getIndexOfMarkerDict() == 17) //for usage of DICT_mip_36h12 as it is not predifined in opencv { dictionary = detail::getDictMip36h12(); } @@ -878,11 +879,11 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Recognit double minMarkerPerimeterRate = 0.03, maxMarkerPerimeterRate = 4, minCornerDistanceRate = 0.05, minMarkerDistanceRate = 0.05; - Petrack *mainWindow = opt.controlWidget->getMainWindow(); + Petrack *mainWindow = controlWidget->getMainWindow(); int bS = mainWindow->getImageBorderSize(); - if (opt.controlWidget->getCalibCoordDimension() == 0) // 3D + if (controlWidget->getCalibCoordDimension() == 0) // 3D { if (recoMethod == RecognitionMethod::Code) // for usage of codemarker with CodeMarker-function (-> without MulticolorMarker) { @@ -890,18 +891,18 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Recognit myRound(mainWindow->getRecoRoiItem()->rect().y()), myRound(mainWindow->getRecoRoiItem()->rect().width()), myRound(mainWindow->getRecoRoiItem()->rect().height())); - 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()); + 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()); 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 = (par.minMarkerPerimeter*4./cmPerPixel_max)/std::max(rect.width(),rect.height()); - maxMarkerPerimeterRate = (par.maxMarkerPerimeter*4./cmPerPixel_min)/std::max(rect.width(),rect.height()); + minMarkerPerimeterRate = (par.getMinMarkerPerimeter()*4./cmPerPixel_max)/std::max(rect.width(),rect.height()); + maxMarkerPerimeterRate = (par.getMaxMarkerPerimeter()*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); @@ -911,44 +912,44 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Recognit maxMarkerPerimeterRate = 4.; } - minCornerDistanceRate = par.minCornerDistance; - minMarkerDistanceRate = par.minMarkerDistance; + minCornerDistanceRate = par.getMinCornerDistance(); + minMarkerDistanceRate = par.getMinMarkerDistance(); } else // 2D { double cmPerPixel = mainWindow->getImageItem()->getCmPerPixel(); - 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); + minMarkerPerimeterRate = (par.getMinMarkerPerimeter()*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS); + maxMarkerPerimeterRate = (par.getMaxMarkerPerimeter()*4/cmPerPixel)/std::max(mainWindow->getImage()->width()-bS,mainWindow->getImage()->height()-bS); - minCornerDistanceRate = par.minCornerDistance; - minMarkerDistanceRate = par.minMarkerDistance; + minCornerDistanceRate = par.getMinCornerDistance(); + minMarkerDistanceRate = par.getMinMarkerDistance(); } - detectorParams->adaptiveThreshWinSizeMin = par.adaptiveThreshWinSizeMin; - detectorParams->adaptiveThreshWinSizeMax = par.adaptiveThreshWinSizeMax; - detectorParams->adaptiveThreshWinSizeStep = par.adaptiveThreshWinSizeStep; - detectorParams->adaptiveThreshConstant = par.adaptiveThreshConstant; + detectorParams->adaptiveThreshWinSizeMin = par.getAdaptiveThreshWinSizeMin(); + detectorParams->adaptiveThreshWinSizeMax = par.getAdaptiveThreshWinSizeMax(); + detectorParams->adaptiveThreshWinSizeStep = par.getAdaptiveThreshWinSizeStep(); + detectorParams->adaptiveThreshConstant = par.getAdaptiveThreshConstant(); detectorParams->minMarkerPerimeterRate = minMarkerPerimeterRate; detectorParams->maxMarkerPerimeterRate = maxMarkerPerimeterRate; - detectorParams->polygonalApproxAccuracyRate = par.polygonalApproxAccuracyRate; + detectorParams->polygonalApproxAccuracyRate = par.getPolygonalApproxAccuracyRate(); detectorParams->minCornerDistanceRate = minCornerDistanceRate; - detectorParams->minDistanceToBorder = par.minDistanceToBorder; + detectorParams->minDistanceToBorder = par.getMinDistanceToBorder(); detectorParams->minMarkerDistanceRate = minMarkerDistanceRate; // No refinement is default value // TODO Check if this is the best MEthod for our usecase - if(par.doCornerRefinement){ + if(par.getDoCornerRefinement()){ detectorParams->cornerRefinementMethod = cv::aruco::CornerRefineMethod::CORNER_REFINE_SUBPIX; } - 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; + detectorParams->cornerRefinementWinSize = par.getCornerRefinementWinSize(); + detectorParams->cornerRefinementMaxIterations = par.getCornerRefinementMaxIterations(); + detectorParams->cornerRefinementMinAccuracy = par.getCornerRefinementMinAccuracy(); + detectorParams->markerBorderBits = par.getMarkerBorderBits(); + detectorParams->perspectiveRemovePixelPerCell = par.getPerspectiveRemovePixelPerCell(); + detectorParams->perspectiveRemoveIgnoredMarginPerCell = par.getPerspectiveRemoveIgnoredMarginPerCell(); + detectorParams->maxErroneousBitsInBorderRate = par.getMaxErroneousBitsInBorderRate(); + detectorParams->minOtsuStdDev = par.getMinOtsuStdDev(); + detectorParams->errorCorrectionRate = par.getErrorCorrectionRate(); std::vector<int> ids; std::vector<std::vector<cv::Point2f> > corners, rejected; @@ -958,8 +959,8 @@ void detail::findCodeMarker(cv::Mat &img, QList<TrackPoint> &crossList, Recognit cv::aruco::detectMarkers(img, dictionary, corners, ids, detectorParams, rejected); - codeMarkerItem->addDetectedMarkers(corners,ids, opt.offsetCropRect2Roi); - codeMarkerItem->addRejectedMarkers(rejected, opt.offsetCropRect2Roi); + codeMarkerItem->addDetectedMarkers(corners,ids, opt.getOffsetCropRect2Roi()); + codeMarkerItem->addRejectedMarkers(rejected, opt.getOffsetCropRect2Roi()); // detected code markers for(size_t i = 0; i<ids.size(); i++) @@ -1149,7 +1150,17 @@ QList<TrackPoint> Recognizer::getMarkerPos(cv::Mat &img, QRect &roi, Control *co return crossList; } -void CodeMarkerOptions::userChangedDetectorParams(ArucoCodeParams params) +const Vec2F &CodeMarkerOptions::getOffsetCropRect2Roi() const +{ + return offsetCropRect2Roi; +} + +void CodeMarkerOptions::setOffsetCropRect2Roi(const Vec2F &newOffsetCropRect2Roi) +{ + offsetCropRect2Roi = newOffsetCropRect2Roi; +} + +void CodeMarkerOptions::setDetectorParams(ArucoCodeParams params) { if(params != detectorParams){ detectorParams = params; @@ -1157,7 +1168,7 @@ void CodeMarkerOptions::userChangedDetectorParams(ArucoCodeParams params) } } -void CodeMarkerOptions::userChangedIndexOfMarkerDict(int idx) +void CodeMarkerOptions::setIndexOfMarkerDict(int idx) { if(idx != indexOfMarkerDict){ indexOfMarkerDict = idx; @@ -1198,4 +1209,250 @@ cv::Ptr<cv::aruco::Dictionary> detail::getDictMip36h12() return dictionary; } + +double ArucoCodeParams::getMaxMarkerPerimeter() const +{ + return maxMarkerPerimeter; +} + +void ArucoCodeParams::setMaxMarkerPerimeter(double newMaxMarkerPerimeter) +{ + if(newMaxMarkerPerimeter < minMarkerPerimeter){ + throw std::invalid_argument("Max perimeter length needs to be at least as big as min perimiter length"); + } + maxMarkerPerimeter = newMaxMarkerPerimeter; +} + +double ArucoCodeParams::getMinCornerDistance() const +{ + return minCornerDistance; +} + +void ArucoCodeParams::setMinCornerDistance(double newMinCornerDistance) +{ + if(newMinCornerDistance < 0){ + throw std::invalid_argument("Min corner distance cannot be negative"); + } + minCornerDistance = newMinCornerDistance; +} + +double ArucoCodeParams::getMinMarkerDistance() const +{ + return minMarkerDistance; +} + +void ArucoCodeParams::setMinMarkerDistance(double newMinMarkerDistance) +{ + minMarkerDistance = newMinMarkerDistance; +} + +int ArucoCodeParams::getAdaptiveThreshWinSizeMin() const +{ + return adaptiveThreshWinSizeMin; +} + +void ArucoCodeParams::setAdaptiveThreshWinSizeMin(int newAdaptiveThreshWinSizeMin) +{ + if(newAdaptiveThreshWinSizeMin > adaptiveThreshWinSizeMax){ + throw std::invalid_argument("Min adaptiveTreshWinSize needs to be at most as large as max"); + } + if(newAdaptiveThreshWinSizeMin < 3){ + throw std::invalid_argument("Min winsize must be at least 3"); + } + adaptiveThreshWinSizeMin = newAdaptiveThreshWinSizeMin; +} + +int ArucoCodeParams::getAdaptiveThreshWinSizeMax() const +{ + return adaptiveThreshWinSizeMax; +} + +void ArucoCodeParams::setAdaptiveThreshWinSizeMax(int newAdaptiveThreshWinSizeMax) +{ + if(newAdaptiveThreshWinSizeMax < adaptiveThreshWinSizeMin){ + throw std::invalid_argument("Max adaptiveThreshWinSize needs to be at least as large as the minimum"); + } + if(newAdaptiveThreshWinSizeMax < 3){ + throw std::invalid_argument("Max adaptive winsize needs to be at lest 3"); + } + adaptiveThreshWinSizeMax = newAdaptiveThreshWinSizeMax; +} + +int ArucoCodeParams::getAdaptiveThreshWinSizeStep() const +{ + return adaptiveThreshWinSizeStep; +} + +void ArucoCodeParams::setAdaptiveThreshWinSizeStep(int newAdaptiveThreshWinSizeStep) +{ + if(newAdaptiveThreshWinSizeStep <= 0){ + throw std::invalid_argument("Winsize step needs to be larger than 0"); + } + adaptiveThreshWinSizeStep = newAdaptiveThreshWinSizeStep; +} + +int ArucoCodeParams::getAdaptiveThreshConstant() const +{ + return adaptiveThreshConstant; +} + +void ArucoCodeParams::setAdaptiveThreshConstant(int newAdaptiveThreshConstant) +{ + adaptiveThreshConstant = newAdaptiveThreshConstant; +} + +double ArucoCodeParams::getPolygonalApproxAccuracyRate() const +{ + return polygonalApproxAccuracyRate; +} + +void ArucoCodeParams::setPolygonalApproxAccuracyRate(double newPolygonalApproxAccuracyRate) +{ + polygonalApproxAccuracyRate = newPolygonalApproxAccuracyRate; +} + +int ArucoCodeParams::getMinDistanceToBorder() const +{ + return minDistanceToBorder; +} + +void ArucoCodeParams::setMinDistanceToBorder(int newMinDistanceToBorder) +{ + if(newMinDistanceToBorder < 0){ + throw std::invalid_argument("Min distance to border cannot be negative"); + } + minDistanceToBorder = newMinDistanceToBorder; +} + +bool ArucoCodeParams::getDoCornerRefinement() const +{ + return doCornerRefinement; +} + +void ArucoCodeParams::setDoCornerRefinement(bool newDoCornerRefinement) +{ + doCornerRefinement = newDoCornerRefinement; +} + +int ArucoCodeParams::getCornerRefinementWinSize() const +{ + return cornerRefinementWinSize; +} + +void ArucoCodeParams::setCornerRefinementWinSize(int newCornerRefinementWinSize) +{ + if(newCornerRefinementWinSize < 1){ + throw std::invalid_argument("Winsize needs to be at least 1"); + } + cornerRefinementWinSize = newCornerRefinementWinSize; +} + +int ArucoCodeParams::getCornerRefinementMaxIterations() const +{ + return cornerRefinementMaxIterations; +} + +void ArucoCodeParams::setCornerRefinementMaxIterations(int newCornerRefinementMaxIterations) +{ + if(newCornerRefinementMaxIterations < 1){ + throw std::invalid_argument("Max iterations needs to be at least 1"); + } + cornerRefinementMaxIterations = newCornerRefinementMaxIterations; +} + +double ArucoCodeParams::getCornerRefinementMinAccuracy() const +{ + return cornerRefinementMinAccuracy; +} + +void ArucoCodeParams::setCornerRefinementMinAccuracy(double newCornerRefinementMinAccuracy) +{ + if(newCornerRefinementMinAccuracy <= 0){ + throw std::invalid_argument("Min accuracy needs to be larger than 0"); + } + cornerRefinementMinAccuracy = newCornerRefinementMinAccuracy; +} + +int ArucoCodeParams::getMarkerBorderBits() const +{ + return markerBorderBits; +} + +void ArucoCodeParams::setMarkerBorderBits(int newMarkerBorderBits) +{ + if(newMarkerBorderBits < 1){ + throw std::invalid_argument("Marker Borderbits needs to be at least 1"); + } + markerBorderBits = newMarkerBorderBits; +} + +int ArucoCodeParams::getPerspectiveRemovePixelPerCell() const +{ + return perspectiveRemovePixelPerCell; +} + +void ArucoCodeParams::setPerspectiveRemovePixelPerCell(int newPerspectiveRemovePixelPerCell) +{ + perspectiveRemovePixelPerCell = newPerspectiveRemovePixelPerCell; +} + +double ArucoCodeParams::getPerspectiveRemoveIgnoredMarginPerCell() const +{ + return perspectiveRemoveIgnoredMarginPerCell; +} + +void ArucoCodeParams::setPerspectiveRemoveIgnoredMarginPerCell(double newPerspectiveRemoveIgnoredMarginPerCell) +{ + perspectiveRemoveIgnoredMarginPerCell = newPerspectiveRemoveIgnoredMarginPerCell; +} + +double ArucoCodeParams::getMaxErroneousBitsInBorderRate() const +{ + return maxErroneousBitsInBorderRate; +} + +void ArucoCodeParams::setMaxErroneousBitsInBorderRate(double newMaxErroneousBitsInBorderRate) +{ + maxErroneousBitsInBorderRate = newMaxErroneousBitsInBorderRate; +} + +double ArucoCodeParams::getMinOtsuStdDev() const +{ + return minOtsuStdDev; +} + +void ArucoCodeParams::setMinOtsuStdDev(double newMinOtsuStdDev) +{ + if(newMinOtsuStdDev <= 0){ + throw std::invalid_argument("Min Otsu stddev needs to be larger than 0"); + } + minOtsuStdDev = newMinOtsuStdDev; +} + +double ArucoCodeParams::getErrorCorrectionRate() const +{ + return errorCorrectionRate; +} + +void ArucoCodeParams::setErrorCorrectionRate(double newErrorCorrectionRate) +{ + errorCorrectionRate = newErrorCorrectionRate; +} + +double ArucoCodeParams::getMinMarkerPerimeter() const +{ + return minMarkerPerimeter; +} + +void ArucoCodeParams::setMinMarkerPerimeter(double newMinMarkerPerimeter) +{ + if(newMinMarkerPerimeter > maxMarkerPerimeter){ + throw std::invalid_argument("Min marker perimeter needs to be at most as large as the max perimeter."); + } + if(newMinMarkerPerimeter <= 0){ + throw std::invalid_argument("Min marker perimeter must be larger than 0"); + } + minMarkerPerimeter = newMinMarkerPerimeter; +} + } // namespace reco diff --git a/tests/unit_test/CMakeLists.txt b/tests/unit_test/CMakeLists.txt index 542fa407076194fa0102718c7094fbb5a9f29844..8b9088c44cb7bad704f5b1b06852408f90072d09 100644 --- a/tests/unit_test/CMakeLists.txt +++ b/tests/unit_test/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources(petrack_tests PRIVATE tst_SkeletonTree.cpp tst_moCapController.cpp tst_recognition.cpp + tst_codeMarkerWidget.cpp ) diff --git a/tests/unit_test/main.cpp b/tests/unit_test/main.cpp index db7f294c2596d9502b3314e006c6d7dfe6b3d795..ff63ecda9a346b96591ebebee16a78d94bc52fc7 100644 --- a/tests/unit_test/main.cpp +++ b/tests/unit_test/main.cpp @@ -23,13 +23,35 @@ #include <QApplication> #include <QtTest> +#include <vector> int main( int argc, char* argv[] ) { - QApplication a(argc, argv); + // always start unit tests as offscreen, so PMessageBox-es only log + bool platformAlreadyGiven = false; + for(int i = 0; i < argc; ++i){ + if(qstrcmp("-platform", argv[i]) == 0){ + platformAlreadyGiven = true; + } + } + int argc2; + char **argv2; + auto args = std::vector<const char*>(argv, argv+argc); + if(!platformAlreadyGiven) + { + args.push_back("-platform"); + args.push_back("offscreen"); + argc2 = argc+2; + argv2 = const_cast<char **>(args.data()); + }else{ + argc2 = argc; + argv2 = argv; + } + + QApplication a(argc2, argv2); QTEST_SET_MAIN_SOURCE_PATH - const int result = Catch::Session().run( argc, argv ); + const int result = Catch::Session().run( argc2, argv2 ); return ( result < 0xff ? result : 0xff ); } diff --git a/tests/unit_test/tst_codeMarkerWidget.cpp b/tests/unit_test/tst_codeMarkerWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4db371b653611a92f8a72dc9594e7dc99bcfc35f --- /dev/null +++ b/tests/unit_test/tst_codeMarkerWidget.cpp @@ -0,0 +1,218 @@ +/* + * PeTrack - Software for tracking pedestrians movement in videos + * Copyright (C) 2010-2020 Forschungszentrum Jülich GmbH, + * Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand, + * Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <catch2/catch.hpp> + +#include "recognition.h" +#include "codeMarkerWidget.h" +#include "ui_codeMarker.h" + +SCENARIO("The user opens the CodeMarkerWidget", "[ui]") +{ + // create the dialog + Petrack petrack; + reco::CodeMarkerOptions options; + Ui::CodeMarker *view = new Ui::CodeMarker(); + CodeMarkerWidget widget {&petrack, options, view}; + + THEN("The view shows the correct values") + { + const auto& params = options.getDetectorParams(); + const auto displayedParams = packDetectorParams(view); + REQUIRE(params == displayedParams); + } + + GIVEN("The user changes an AruCo Parameter") + { + // since the params are handled the same, not all are + // explicitly tested here + constexpr double newMinMarkerDistance = 0; + view->minMarkerDistance->setValue(newMinMarkerDistance); // <- user input + + const int newListIndex = view->dictList->currentIndex() + 1; + view->dictList->setCurrentIndex(newListIndex); // <- user input + + THEN("The options-object is updated") + { + REQUIRE(options.getDetectorParams().getMinMarkerDistance() == Approx(newMinMarkerDistance)); + REQUIRE(options.getIndexOfMarkerDict() == newListIndex); + } + } + + GIVEN("The AruCo Parameters changed via an other way") + { + reco::ArucoCodeParams newData; + newData.setMinMarkerDistance(10); + options.setDetectorParams(newData); + constexpr int newIndex = 2; + options.setIndexOfMarkerDict(newIndex); + + THEN("The view is updated") + { + REQUIRE(packDetectorParams(view) == newData); + REQUIRE(view->dictList->currentIndex() == newIndex); + } + } + + GIVEN("Minimum larger than maximum") + { + auto oldValues = packDetectorParams(view); + view->adaptiveThreshWinSizeMin->setValue(view->adaptiveThreshWinSizeMax->value() + 1); + view->minMarkerPerimeter->setValue(view->maxMarkerPerimeter->value() + 1); + THEN("It is not changed") + { + REQUIRE(view->adaptiveThreshWinSizeMin->value() == oldValues.getAdaptiveThreshWinSizeMin()); + REQUIRE(view->minMarkerPerimeter->value() == Approx(oldValues.getMinMarkerPerimeter())); + } + } + + GIVEN("Maximum lower than minimum") + { + auto oldValues = packDetectorParams(view); + // Since min already has minimal value this isn't properly tested with the default min + view->adaptiveThreshWinSizeMin->setValue(10); + view->adaptiveThreshWinSizeMax->setValue(view->adaptiveThreshWinSizeMin->value()-1); + //view->minMarkerPerimeter-> + view->maxMarkerPerimeter->setValue(view->minMarkerPerimeter->value()-1); + THEN("It is not changed") + { + REQUIRE(view->adaptiveThreshWinSizeMax->value() == oldValues.getAdaptiveThreshWinSizeMax()); + REQUIRE(view->maxMarkerPerimeter->value() == Approx(oldValues.getMaxMarkerPerimeter())); + } + } + + GIVEN("A cornerRefinementWinSize less than 1") + { + view->cornerRefinementWinSize->setValue(-2); + THEN("The value gets set to 1") + { + REQUIRE(view->cornerRefinementWinSize->value() == 1); + } + } + + GIVEN("A cornerRefinementMaxIterations less than 1") + { + view->cornerRefinementMaxIterations->setValue(0); + THEN("The value gets set to 1") + { + REQUIRE(view->cornerRefinementMaxIterations->value() == 1); + } + } + + GIVEN("A cornerRefinementMinAccuracy less than or equal to 0") + { + view->cornerRefinementMinAccuracy->setValue(-3); + THEN("It is set to 0.01") + { + REQUIRE(view->cornerRefinementMinAccuracy->value() == Approx(0.01)); + } + } + + GIVEN("markerBorderBits less than 1") + { + view->markerBorderBits->setValue(0); + THEN("The value is set to 1") + { + REQUIRE(view->markerBorderBits->value() == 1); + } + } + + GIVEN("minStdDevOtsu less than or equal to 0") + { + view->minOtsuStdDev->setValue(-2); + THEN("The value is set to 0.01") + { + REQUIRE(view->minOtsuStdDev->value() == Approx(0.01)); + } + } + + GIVEN("adaptiveThreshSizeMin less than 3") + { + view->adaptiveThreshWinSizeMin->setValue(1); + THEN("The value is set to 3"){ + REQUIRE(view->adaptiveThreshWinSizeMin->value() == 3); + } + } + + GIVEN("adaptiveThreshSizeMax less than 3") + { + view->adaptiveThreshWinSizeMax->setValue(1); + THEN("The value is set to 3") + { + REQUIRE(view->adaptiveThreshWinSizeMax->value() == 3); + } + } + + GIVEN("adaptiveThreshWinSizeStep less than or equal to 0") + { + view->adaptiveThreshWinSizeStep->setValue(0); + THEN("The value is set to 1") + { + REQUIRE(view->adaptiveThreshWinSizeStep->value() == 1); + } + } + + GIVEN("minMarkerPerimeter less than or equal to 0") + { + view->minMarkerPerimeter->setValue(0); + THEN("The value is set to 0.1") + { + REQUIRE(view->minMarkerPerimeter->value() == Approx(0.1)); + } + } + + GIVEN("maxMarkerPerimeter less than or equal to 0") + { + auto oldVal = view->maxMarkerPerimeter->value(); + view->minMarkerPerimeter->setValue(0); // since max cannot be lower than min + view->maxMarkerPerimeter->setValue(0); + THEN("The value is not changed") + { + REQUIRE(view->maxMarkerPerimeter->value() == Approx(oldVal)); + } + } + + GIVEN("cornerRefinementMinAccuracy less than or equal to 0") + { + view->cornerRefinementMinAccuracy->setValue(0); + THEN("The value is set to 0.01") + { + REQUIRE(view->cornerRefinementMinAccuracy->value() == Approx(0.01)); + } + } + + GIVEN("minCornerDistance less than 0") + { + view->minCornerDistance->setValue(-1); + THEN("The value is set to 1") + { + REQUIRE(view->minCornerDistance->value() == Approx(0)); + } + } + + GIVEN("minDistanceToBorder less than 0") + { + view->minDistanceToBorder->setValue(-2); + THEN("The value is set to 0") + { + REQUIRE(view->minDistanceToBorder->value() == 0); + } + } +} diff --git a/tests/unit_test/tst_recognition.cpp b/tests/unit_test/tst_recognition.cpp index 77b603e01ed78a6ab2b1ec9db161fc447c1596e1..758c1cb4b2ac3faabdba6b272b45e8a828612909 100644 --- a/tests/unit_test/tst_recognition.cpp +++ b/tests/unit_test/tst_recognition.cpp @@ -20,9 +20,13 @@ #include <catch2/catch.hpp> +#include <QSignalSpy> + #include "recognition.h" #include "petrack.h" +using namespace reco; + TEST_CASE("src/recognition", "[recognition]") { SECTION("RecognitionMarker to int") @@ -37,3 +41,202 @@ TEST_CASE("src/recognition", "[recognition]") REQUIRE(static_cast<int>(reco::RecognitionMethod::Code) == 6); } } + +SCENARIO("I change Aruco parameters (via UI)"){ + CodeMarkerOptions options; + + GIVEN("I change the detector params"){ + QSignalSpy spy{&options, &CodeMarkerOptions::detectorParamsChanged}; + ArucoCodeParams params; + params.setAdaptiveThreshConstant(20); + options.setDetectorParams(params); + THEN("A corresponding change signal was emitted"){ + REQUIRE(spy.count() == 1); + } + } + + GIVEN("I change the index of the marker dict"){ + QSignalSpy spy{&options, &CodeMarkerOptions::indexOfMarkerDictChanged}; + const int newIndex = options.getIndexOfMarkerDict() + 1; + options.setIndexOfMarkerDict(newIndex); + THEN("A corresponding change signal was emitted"){ + REQUIRE(spy.count() == 1); + } + } +} + +SCENARIO("I use the setter/getter of ArucoCodeParams") +{ + ArucoCodeParams params; + GIVEN("I set a minimum larger than the maximum") + { + const int newAdaptiveThreshWinSizeMin = params.getAdaptiveThreshWinSizeMax() + 1; + const double newMinMarkerPerimeter = params.getMaxMarkerPerimeter() + 1; + const auto oldAdaptiveThreshWinSizeMin = params.getAdaptiveThreshWinSizeMin(); + const auto oldMinMarkerPerimeter = params.getMinMarkerPerimeter(); + THEN("An exception is thrown and values aren't changed") + { + REQUIRE_THROWS(params.setAdaptiveThreshWinSizeMin(newAdaptiveThreshWinSizeMin)); + REQUIRE(params.getAdaptiveThreshWinSizeMin() == oldAdaptiveThreshWinSizeMin); + REQUIRE_THROWS(params.setMinMarkerPerimeter(newMinMarkerPerimeter)); + REQUIRE(params.getMinMarkerPerimeter() == Approx(oldMinMarkerPerimeter)); + } + } + + GIVEN("I set a maximum lower than the minimum") + { + const int newAdaptiveThreshSizeMax = params.getAdaptiveThreshWinSizeMin() - 1; + const double newMaxMarkerPerimeter = params.getMinMarkerPerimeter() - 1; + const auto oldAdaptiveThreshWinSizeMax = params.getAdaptiveThreshWinSizeMax(); + const auto oldMaxMarkerPerimeter = params.getMaxMarkerPerimeter(); + THEN("An exception is thrown and values aren't changed") + { + REQUIRE_THROWS(params.setAdaptiveThreshWinSizeMax(newAdaptiveThreshSizeMax)); + REQUIRE(params.getAdaptiveThreshWinSizeMax() == oldAdaptiveThreshWinSizeMax); + REQUIRE_THROWS(params.setMaxMarkerPerimeter(newMaxMarkerPerimeter)); + REQUIRE(params.getMaxMarkerPerimeter() == Approx(oldMaxMarkerPerimeter)); + } + } + + GIVEN("A cornerRefinementWinSize less than 1") + { + constexpr int newCornerRefinementWinSize = -2; + const int oldCornerRefinementWinSize = params.getCornerRefinementWinSize(); + THEN("An Exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setCornerRefinementWinSize(newCornerRefinementWinSize)); + REQUIRE(params.getCornerRefinementWinSize() == oldCornerRefinementWinSize); + } + } + + GIVEN("A cornerRefinementMaxIterations less than 1") + { + constexpr int newCornerRefinementMaxIterations = 0; + const int oldCornerRefinementMaxIterations = params.getCornerRefinementMaxIterations(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setCornerRefinementMaxIterations(newCornerRefinementMaxIterations)); + REQUIRE(params.getCornerRefinementMaxIterations() == oldCornerRefinementMaxIterations); + } + } + + GIVEN("A cornerRefinementMinAccuracy less than or equal to 0") + { + constexpr double newCornerRefinementMinAccuracy = -3; + const auto oldCornerRefinementMinAccuracy = params.getCornerRefinementMinAccuracy(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setCornerRefinementMinAccuracy(newCornerRefinementMinAccuracy)); + REQUIRE(params.getCornerRefinementMinAccuracy() == Approx(oldCornerRefinementMinAccuracy)); + } + } + + GIVEN("markerBorderBits less than 1") + { + constexpr int newBorderBits = 0; + const int oldBorderBits = params.getMarkerBorderBits(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setMarkerBorderBits(newBorderBits)); + REQUIRE(params.getMarkerBorderBits() == oldBorderBits); + } + } + + GIVEN("minStdDevOtsu less than or equal to 0") + { + constexpr double newMinOtsuStdDev = -2; + const auto oldMinOtsuStdDev = params.getMinOtsuStdDev(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setMinOtsuStdDev(newMinOtsuStdDev)); + REQUIRE(params.getMinOtsuStdDev() == Approx(oldMinOtsuStdDev)); + } + } + + GIVEN("adaptiveThreshSizeMin less than 3") + { + constexpr int newThreshSizeMin = 2; + const int oldThreshSizeMin = params.getAdaptiveThreshWinSizeMin(); + THEN("An exception is thrown and value isn't changed"){ + REQUIRE_THROWS(params.setAdaptiveThreshWinSizeMin(newThreshSizeMin)); + REQUIRE(params.getAdaptiveThreshWinSizeMin() == oldThreshSizeMin); + } + } + + GIVEN("adaptiveThreshSizeMax less than 3") + { + constexpr int newThreshWinSizeMax = 2; + const int oldThreshWinSizeMax = params.getAdaptiveThreshWinSizeMax(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setAdaptiveThreshWinSizeMax(newThreshWinSizeMax)); + REQUIRE(params.getAdaptiveThreshWinSizeMax() == oldThreshWinSizeMax); + } + } + + GIVEN("adaptiveThreshWinSizeStep less than or equal to 0") + { + constexpr int newWinSizeStep = 0; + const int oldWinSizeStep = params.getAdaptiveThreshWinSizeStep(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setAdaptiveThreshWinSizeStep(newWinSizeStep)); + REQUIRE(params.getAdaptiveThreshWinSizeStep() == oldWinSizeStep); + } + } + + GIVEN("minMarkerPerimeter less than or equal to 0") + { + constexpr double newMinMarkerPerimeter = 0; + const auto oldMinMarkerPerimeter = params.getMinMarkerPerimeter(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setMinMarkerPerimeter(newMinMarkerPerimeter)); + REQUIRE(params.getMinMarkerPerimeter() == Approx(oldMinMarkerPerimeter)); + } + } + + GIVEN("maxMarkerPerimeter less than or equal to 0") + { + constexpr double newMaxMarkerPerimeter = 0; + const auto oldMaxMarkerPerimeter = params.getMaxMarkerPerimeter(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setMaxMarkerPerimeter(newMaxMarkerPerimeter)); + REQUIRE(params.getMaxMarkerPerimeter() == Approx(oldMaxMarkerPerimeter)); + } + } + + GIVEN("cornerRefinementMinAccuracy less than or equal to 0") + { + constexpr double newMinAccuracy = 0; + const auto oldMinAccuracy = params.getCornerRefinementMinAccuracy(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setCornerRefinementMinAccuracy(newMinAccuracy)); + REQUIRE(params.getCornerRefinementMinAccuracy() == Approx(oldMinAccuracy)); + } + } + + GIVEN("minCornerDistance less than 0") + { + constexpr double newMinCornerDistance = -1; + const auto oldMinCornerDistance = params.getMinMarkerDistance(); + THEN("An exception is thrown and value isn't changed") + { + REQUIRE_THROWS(params.setMinCornerDistance(newMinCornerDistance)); + REQUIRE(params.getMinCornerDistance() == Approx(oldMinCornerDistance)); + } + } + + GIVEN("minDistanceToBorder less than 0") + { + constexpr int newMinDistToBorder = -2; + const int oldMinDistToBorder = params.getMinDistanceToBorder(); + THEN("An exception is thown and value isn't changed") + { + REQUIRE_THROWS(params.setMinDistanceToBorder(newMinDistToBorder)); + REQUIRE(params.getMinDistanceToBorder() == oldMinDistToBorder); + } + } +}