From ab4a70a7588caeb51a30330bd6ee8e49f462ad3a Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sun, 13 Feb 2022 05:24:52 +0100 Subject: [PATCH] Refresh contents of "Show match" dialog every second --- data/locale/en-US.ini | 4 + .../opencv/macro-condition-video.cpp | 166 +++++++++++++----- .../opencv/macro-condition-video.hpp | 27 +++ 3 files changed, 149 insertions(+), 48 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index c8951ebd..8649749b 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -148,9 +148,13 @@ AdvSceneSwitcher.condition.video.objectScaleThreshold="Scale factor: " AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="A lower scale factor will lead to more matches but higher CPU load." AdvSceneSwitcher.condition.video.minNeighborDescription="A higher minimum neighbors value will result in fewer but higher quality matches." AdvSceneSwitcher.condition.video.showMatch="Show match" +AdvSceneSwitcher.condition.video.showMatch.loading="Checking for match" AdvSceneSwitcher.condition.video.screenshotFail="Failed to get screenshot of source!" +AdvSceneSwitcher.condition.video.screenshotEmpty="Screenshot is empty - Is the source visible?" AdvSceneSwitcher.condition.video.patternMatchFail="Pattern was not found!" +AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in red" AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!" +AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red" AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!" AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}" AdvSceneSwitcher.condition.video.entry.modelPath="Model data (haar cascade classifier): {{modelDataPath}}" diff --git a/src/external-macro-modules/opencv/macro-condition-video.cpp b/src/external-macro-modules/opencv/macro-condition-video.cpp index 21fb3b05..999d9796 100644 --- a/src/external-macro-modules/opencv/macro-condition-video.cpp +++ b/src/external-macro-modules/opencv/macro-condition-video.cpp @@ -409,7 +409,7 @@ void ThresholdSlider::SetDoubleValueText(double value) MacroConditionVideoEdit::MacroConditionVideoEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), _matchDialog(this, entryData.get()) { _videoSelection = new QComboBox(); _condition = new QComboBox(); @@ -852,53 +852,10 @@ QImage markObjects(QImage &image, std::vector &objects) void MacroConditionVideoEdit::ShowMatchClicked() { - auto source = obs_weak_source_get_source(_entryData->_videoSource); - auto screenshot = std::make_unique(source); - obs_source_release(source); - if (!screenshot->done) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - if (!screenshot->done) { - DisplayMessage(obs_module_text( - "AdvSceneSwitcher.condition.video.screenshotFail")); - return; - } - - QImage markedIamge; - if (_entryData->_condition == VideoCondition::PATTERN) { - cv::Mat result; - QImage pattern = _entryData->GetMatchImage(); - matchPattern(screenshot->image, pattern, - _entryData->_patternThreshold, result, - _entryData->_useAlphaAsMask); - if (countNonZero(result) == 0) { - DisplayMessage(obs_module_text( - "AdvSceneSwitcher.condition.video.patternMatchFail")); - return; - } - markedIamge = markPatterns(result, screenshot->image, pattern); - } else if (_entryData->_condition == VideoCondition::OBJECT) { - auto objects = matchObject( - screenshot->image, _entryData->_objectCascade, - _entryData->_scaleFactor, _entryData->_minNeighbors, - {_entryData->_minSizeX, _entryData->_minSizeY}, - {_entryData->_maxSizeX, _entryData->_maxSizeY}); - if (objects.empty()) { - DisplayMessage(obs_module_text( - "AdvSceneSwitcher.condition.video.objectMatchFail")); - return; - } - markedIamge = markObjects(screenshot->image, objects); - } - - QLabel *label = new QLabel; - label->setPixmap(QPixmap::fromImage(markedIamge)); - QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(label); - QDialog dialog; - dialog.setLayout(layout); - dialog.setWindowTitle("Advanced Scene Switcher"); - dialog.exec(); + _matchDialog.show(); + _matchDialog.raise(); + _matchDialog.activateWindow(); + _matchDialog.ShowMatch(); } void MacroConditionVideoEdit::ModelPathChanged(const QString &text) @@ -1008,3 +965,116 @@ void MacroConditionVideoEdit::UpdateEntryData() GetSwitcher()->interval); SetWidgetVisibility(); } + +ShowMatchDialog::ShowMatchDialog(QWidget *parent, + MacroConditionVideo *conditionData) + : QDialog(parent), + _conditionData(conditionData), + _imageLabel(new QLabel), + _scrollArea(new QScrollArea) +{ + setWindowTitle("Advanced Scene Switcher"); + _statusLabel = new QLabel(obs_module_text( + "AdvSceneSwitcher.condition.video.showMatch.loading")); + + _scrollArea->setBackgroundRole(QPalette::Dark); + _scrollArea->setWidget(_imageLabel); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(_statusLabel); + layout->addWidget(_scrollArea); + setLayout(layout); +} + +ShowMatchDialog::~ShowMatchDialog() +{ + _stop = true; + if (_thread.joinable()) { + _thread.join(); + } +} + +void ShowMatchDialog::ShowMatch() +{ + if (_thread.joinable()) { + return; + } + if (!_conditionData) { + DisplayMessage(obs_module_text( + "AdvSceneSwitcher.condition.video.screenshotFail")); + return; + } + _thread = std::thread(&ShowMatchDialog::CheckForMatchLoop, this); +} + +void ShowMatchDialog::RedrawImage(QImage img) +{ + _imageLabel->setPixmap(QPixmap::fromImage(img)); + _imageLabel->adjustSize(); +} + +void ShowMatchDialog::CheckForMatchLoop() +{ + while (!_stop) { + auto source = obs_weak_source_get_source( + _conditionData->_videoSource); + AdvSSScreenshotObj screenshot(source); + obs_source_release(source); + std::this_thread::sleep_for(std::chrono::seconds(1)); + if (!screenshot.done) { + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.screenshotFail")); + continue; + } + if (screenshot.image.width() == 0 || + screenshot.image.height() == 0) { + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.screenshotEmpty")); + continue; + } + auto image = MarkMatch(screenshot.image); + if (_stop) { + return; + } + QMetaObject::invokeMethod(this, "RedrawImage", + Qt::BlockingQueuedConnection, + Q_ARG(QImage, image)); + } +} + +QImage ShowMatchDialog::MarkMatch(QImage &screenshot) +{ + QImage resultIamge; + if (_conditionData->_condition == VideoCondition::PATTERN) { + cv::Mat result; + QImage pattern = _conditionData->GetMatchImage(); + matchPattern(screenshot, pattern, + _conditionData->_patternThreshold, result, + _conditionData->_useAlphaAsMask); + if (countNonZero(result) == 0) { + resultIamge = screenshot; + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.patternMatchFail")); + } else { + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.patternMatchSuccess")); + resultIamge = markPatterns(result, screenshot, pattern); + } + } else if (_conditionData->_condition == VideoCondition::OBJECT) { + auto objects = matchObject( + screenshot, _conditionData->_objectCascade, + _conditionData->_scaleFactor, + _conditionData->_minNeighbors, + {_conditionData->_minSizeX, _conditionData->_minSizeY}, + {_conditionData->_maxSizeX, _conditionData->_maxSizeY}); + if (objects.empty()) { + resultIamge = screenshot; + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.objectMatchFail")); + } else { + _statusLabel->setText(obs_module_text( + "AdvSceneSwitcher.condition.video.objectMatchSuccess")); + resultIamge = markObjects(screenshot, objects); + } + } + return resultIamge; +} diff --git a/src/external-macro-modules/opencv/macro-condition-video.hpp b/src/external-macro-modules/opencv/macro-condition-video.hpp index faadcfe8..1e16913e 100644 --- a/src/external-macro-modules/opencv/macro-condition-video.hpp +++ b/src/external-macro-modules/opencv/macro-condition-video.hpp @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #undef NO // MacOS macro that can conflict with OpenCV #include @@ -108,6 +111,29 @@ private: int _precision = 2; }; +class ShowMatchDialog : public QDialog { + Q_OBJECT + +public: + ShowMatchDialog(QWidget *parent, MacroConditionVideo *_conditionData); + virtual ~ShowMatchDialog(); + void ShowMatch(); + +private slots: + void RedrawImage(QImage img); + +private: + void CheckForMatchLoop(); + QImage MarkMatch(QImage &screenshot); + + MacroConditionVideo *_conditionData; + QScrollArea *_scrollArea; + QLabel *_statusLabel; + QLabel *_imageLabel; + std::thread _thread; + std::atomic_bool _stop = {false}; +}; + class MacroConditionVideoEdit : public QWidget { Q_OBJECT @@ -175,6 +201,7 @@ protected: QCheckBox *_throttleEnable; QSpinBox *_throttleCount; QPushButton *_showMatch; + ShowMatchDialog _matchDialog; std::shared_ptr _entryData;