Compare commits

...

9 Commits

Author SHA1 Message Date
WarmUpTill
68c6492c3f Revert "Add OCL support to improve performance"
This reverts commit 284c8020b2.
2023-08-09 17:04:00 +02:00
WarmUpTill
0ba7ba77d8 Fix potential crash related to OCR 2023-08-09 17:04:00 +02:00
WarmUpTill
04b2b3474d Fix crash in output change check with pattern matching enabled 2023-08-09 17:04:00 +02:00
WarmUpTill
ecbb5ebbd7 Update issue template 2023-08-09 17:04:00 +02:00
WarmUpTill
b62757b65d Rely on output flag to identify media sources
Using OBS_SOURCE_CONTROLLABLE_MEDIA instead of a hardcoded list of
source names is much more reliable and has the upside of also supporting
plugin sources
2023-08-09 14:01:19 +02:00
WarmUpTill
b1a3ab5493 Fix window condition ignoring title matching if regex is disabled
If the only enabled option was window title matching and regular
expressions were not used any window title would match regardless if it
existed or not
2023-08-09 13:50:32 +02:00
WarmUpTill
abc3357180 Make macro properties dialog resizable 2023-08-07 19:17:41 +02:00
WarmUpTill
29f9cba236 Add option to skip execution of given macro on OBS startup 2023-08-07 19:17:41 +02:00
WarmUpTill
9a62522140 Fix DisplayMessage() not being visible when OBS is always on top
The previous behaviour would cause the impression of OSB being frozen
due to dialogs windows being opened behind OBS while they take over the
input focus.
2023-08-07 18:03:12 +02:00
16 changed files with 180 additions and 111 deletions

View File

@@ -22,6 +22,7 @@ A clear and concise description of what you expected to happen.
**Logs**
Please provide a log of your issue with verbose logging enabled (See General tab of the plugin).
In case of a crash, please also include the corresponding crash log.
See [here](https://obsproject.com/forum/threads/please-post-a-log-with-your-issue-heres-how.23074/) for a description where to find the log files and how to share them.
Please share the currently used plugin settings by exporting them them to a file (See General tab of the plugin).
If applicable, add screenshots to help explain your problem.

View File

@@ -104,12 +104,14 @@ AdvSceneSwitcher.macroTab.maximize="Maximize"
AdvSceneSwitcher.macroTab.minimize="Minimize"
AdvSceneSwitcher.macroTab.highlightSettings="Visual settings"
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings"
AdvSceneSwitcher.macroTab.generalSettings="General settings"
AdvSceneSwitcher.macroTab.dockSettings="Dock settings"
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Highlight recently executed macros"
AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of currently selected macro that evaluated to true recently"
AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro"
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro"
AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup"
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"

View File

@@ -40,7 +40,8 @@ static bool windowContainsText(const std::string &window,
return text == matchText;
}
bool MacroConditionWindow::WindowMatches(const std::string &window)
bool MacroConditionWindow::WindowMatchesRequirements(
const std::string &window) const
{
const bool focusCheckOK = (!_focus || window == switcher->currentTitle);
if (!focusCheckOK) {
@@ -60,26 +61,52 @@ bool MacroConditionWindow::WindowMatches(const std::string &window)
return false;
}
if (_checkText) {
auto text = GetTextInWindow(window);
SetVariableValue(text.value_or(""));
}
return true;
}
bool MacroConditionWindow::WindowMatches(
const std::vector<std::string> &windowList)
{
bool match = !_checkTitle ||
std::find(windowList.begin(), windowList.end(),
std::string(_window)) != windowList.end();
match = match && WindowMatchesRequirements(_window);
SetVariableValueBasedOnMatch(_window);
return match;
}
bool MacroConditionWindow::WindowRegexMatches(
const std::vector<std::string> &windowList)
{
// No need to test if checking for window title is required as if the
// user has disabled window title matching the option will always be
// enabled in the backend and use the regular expression ".*".
for (const auto &window : windowList) {
if (matchRegex(_windowRegex, window, _window) &&
WindowMatches(window)) {
WindowMatchesRequirements(window)) {
SetVariableValueBasedOnMatch(window);
return true;
}
}
SetVariableValueBasedOnMatch("");
return false;
}
void MacroConditionWindow::SetVariableValueBasedOnMatch(
const std::string &matchWindow)
{
if (!IsReferencedInVars()) {
return;
}
if (_checkText) {
auto text = GetTextInWindow(matchWindow);
SetVariableValue(text.value_or(""));
} else {
SetVariableValue(switcher->currentTitle);
}
}
static bool foregroundWindowChanged()
{
return switcher->currentTitle != switcher->lastTitle;
@@ -87,19 +114,13 @@ static bool foregroundWindowChanged()
bool MacroConditionWindow::CheckCondition()
{
SetVariableValue("");
if (!_checkText) {
SetVariableValue(switcher->currentTitle);
}
std::vector<std::string> windowList;
GetWindowList(windowList);
bool match = false;
if (_windowRegex.Enabled()) {
match = WindowRegexMatches(windowList);
} else {
match = WindowMatches(_window);
match = WindowMatches(windowList);
}
match = match && (!_windowFocusChanged || foregroundWindowChanged());
return match;

View File

@@ -21,10 +21,6 @@ public:
return std::make_shared<MacroConditionWindow>(m);
}
private:
bool WindowMatches(const std::string &window);
bool WindowRegexMatches(const std::vector<std::string> &windowList);
public:
StringVariable _window;
RegexConfig _windowRegex;
@@ -40,6 +36,11 @@ public:
RegexConfig _textRegex = RegexConfig::PartialMatchRegexConfig();
private:
bool WindowMatchesRequirements(const std::string &window) const;
bool WindowMatches(const std::vector<std::string> &windowList);
bool WindowRegexMatches(const std::vector<std::string> &windowList);
void SetVariableValueBasedOnMatch(const std::string &matchWindow);
static bool _registered;
static const std::string id;
};

View File

@@ -4,6 +4,8 @@
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <QScrollArea>
#include <QScrollBar>
namespace advss {
@@ -44,6 +46,8 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
"AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))),
_currentMacroRegisterHotkeys(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentDisableHotkeys"))),
_currentSkipOnStartup(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
@@ -82,6 +86,12 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
hotkeyLayout->addWidget(_currentMacroRegisterHotkeys);
hotkeyOptions->setLayout(hotkeyLayout);
auto generalOptions = new QGroupBox(
obs_module_text("AdvSceneSwitcher.macroTab.generalSettings"));
auto generalLayout = new QVBoxLayout;
generalLayout->addWidget(_currentSkipOnStartup);
generalOptions->setLayout(generalLayout);
int row = 0;
_dockLayout->addWidget(_currentMacroRegisterDock, row, 1, 1, 2);
row++;
@@ -146,12 +156,23 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
connect(_currentMacroDockAddStatusLabel, &QCheckBox::stateChanged, this,
&MacroPropertiesDialog::StatusLabelEnableChanged);
auto layout = new QVBoxLayout;
auto scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setFrameShape(QFrame::NoFrame);
auto contentWidget = new QWidget(scrollArea);
auto layout = new QVBoxLayout(contentWidget);
layout->addWidget(highlightOptions);
layout->addWidget(hotkeyOptions);
layout->addWidget(generalOptions);
layout->addWidget(_dockOptions);
layout->addWidget(buttonbox);
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
scrollArea->setWidget(contentWidget);
auto dialogLayout = new QVBoxLayout();
dialogLayout->addWidget(scrollArea);
dialogLayout->addWidget(buttonbox);
setLayout(dialogLayout);
_executed->setChecked(prop._highlightExecuted);
_conditions->setChecked(prop._highlightConditions);
@@ -159,10 +180,12 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
_newMacroRegisterHotkeys->setChecked(prop._newMacroRegisterHotkeys);
if (!macro || macro->IsGroup()) {
hotkeyOptions->hide();
generalOptions->hide();
_dockOptions->hide();
return;
}
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
const bool dockEnabled = macro->DockEnabled();
_currentMacroRegisterDock->setChecked(dockEnabled);
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
@@ -194,6 +217,20 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
dockEnabled && macro->DockHasStatusLabel());
MinimizeSizeOfColumn(_dockLayout, 0);
Resize();
// Try to set sensible initial size for the dialog window
QSize contentSize = contentWidget->sizeHint();
resize(contentSize.width() + layout->contentsMargins().left() +
layout->contentsMargins().right() +
dialogLayout->contentsMargins().left() +
dialogLayout->contentsMargins().right() +
scrollArea->verticalScrollBar()->sizeHint().width() + 20,
contentSize.height() + dialogLayout->spacing() +
buttonbox->sizeHint().height() +
dialogLayout->contentsMargins().top() +
dialogLayout->contentsMargins().bottom() +
scrollArea->horizontalScrollBar()->sizeHint().height() +
20);
}
void MacroPropertiesDialog::DockEnableChanged(int enabled)
@@ -244,8 +281,6 @@ void MacroPropertiesDialog::Resize()
{
_dockOptions->adjustSize();
_dockOptions->updateGeometry();
adjustSize();
updateGeometry();
}
bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
@@ -268,6 +303,7 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
macro->EnablePauseHotkeys(
dialog._currentMacroRegisterHotkeys->isChecked());
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
macro->EnableDock(dialog._currentMacroRegisterDock->isChecked());
macro->SetDockHasRunButton(
dialog._currentMacroDockAddRunButton->isChecked());

View File

@@ -47,6 +47,7 @@ private:
QCheckBox *_newMacroRegisterHotkeys;
// Current macro specific settings
QCheckBox *_currentMacroRegisterHotkeys;
QCheckBox *_currentSkipOnStartup;
QCheckBox *_currentMacroRegisterDock;
QCheckBox *_currentMacroDockAddRunButton;
QCheckBox *_currentMacroDockAddPauseButton;

View File

@@ -31,7 +31,7 @@ Macro::~Macro()
Stop();
ClearHotkeys();
// Keep the dock widgets in case of shutdown so they can be rostored by
// Keep the dock widgets in case of shutdown so they can be restored by
// OBS on startup
if (!switcher->obsIsShuttingDown) {
RemoveDock();
@@ -361,6 +361,7 @@ bool Macro::Save(obs_data_t *obj) const
obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel);
obs_data_set_bool(obj, "onChange", _matchOnChange);
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
obs_data_set_bool(obj, "group", _isGroup);
if (_isGroup) {
@@ -453,6 +454,7 @@ bool Macro::Load(obs_data_t *obj)
_paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel");
_matchOnChange = obs_data_get_bool(obj, "onChange");
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
_isGroup = obs_data_get_bool(obj, "group");
if (_isGroup) {
@@ -1026,7 +1028,7 @@ bool SwitcherData::CheckMacros()
bool SwitcherData::RunMacros()
{
// Create copy of macor list as elements might be removed, inserted, or
// Create copy of macro list as elements might be removed, inserted, or
// reordered while macros are currently being executed.
// For example, this can happen if a macro is performing a wait action,
// as the main lock will be unlocked during this time.
@@ -1047,12 +1049,18 @@ bool SwitcherData::RunMacros()
}
for (auto &m : runPhaseMacros) {
if (m && m->Matched()) {
vblog(LOG_INFO, "running macro: %s", m->Name().c_str());
if (!m->PerformActions()) {
blog(LOG_WARNING, "abort macro: %s",
m->Name().c_str());
}
if (!m || !m->Matched()) {
continue;
}
if (firstInterval && m->SkipExecOnStart()) {
blog(LOG_INFO,
"skip execution of macro \"%s\" at startup",
m->Name().c_str());
continue;
}
vblog(LOG_INFO, "running macro: %s", m->Name().c_str());
if (!m->PerformActions()) {
blog(LOG_WARNING, "abort macro: %s", m->Name().c_str());
}
}
if (GetLock()) {

View File

@@ -37,6 +37,8 @@ public:
bool Paused() const { return _paused; }
void SetMatchOnChange(bool onChange) { _matchOnChange = onChange; }
bool MatchOnChange() const { return _matchOnChange; }
void SetSkipExecOnStart(bool skip) { _skipExecOnStart = skip; }
bool SkipExecOnStart() const { return _skipExecOnStart; }
int RunCount() const { return _runCount; };
void ResetRunCount() { _runCount = 0; };
void ResetTimers();
@@ -141,6 +143,7 @@ private:
bool _matched = false;
bool _lastMatched = false;
bool _matchOnChange = true;
bool _skipExecOnStart = false;
bool _paused = false;
int _runCount = 0;
bool _registerHotkeys = true;

View File

@@ -83,11 +83,6 @@ const static std::map<tesseract::PageSegMode, std::string> pageSegModes = {
"AdvSceneSwitcher.condition.video.ocrMode.sparseTextOSD"},
};
MacroConditionVideo::MacroConditionVideo(Macro *m) : MacroCondition(m, true)
{
SetupOpenCL();
}
cv::CascadeClassifier initObjectCascade(std::string &path)
{
cv::CascadeClassifier cascade;
@@ -266,7 +261,7 @@ bool MacroConditionVideo::SetLanguage(const std::string &language)
bool MacroConditionVideo::ScreenshotContainsPattern()
{
cv::UMat result;
cv::Mat result;
MatchPattern(_screenshotData.image, _patternImageData,
_patternMatchParameters.threshold, result,
_patternMatchParameters.useAlphaAsMask,
@@ -279,16 +274,20 @@ bool MacroConditionVideo::ScreenshotContainsPattern()
bool MacroConditionVideo::OutputChanged()
{
if (_patternMatchParameters.useForChangedCheck) {
cv::UMat result;
_patternImageData = CreatePatternData(_matchImage);
MatchPattern(_screenshotData.image, _patternImageData,
_patternMatchParameters.threshold, result,
_patternMatchParameters.useAlphaAsMask,
_patternMatchParameters.matchMode);
return countNonZero(result) == 0;
if (!_patternMatchParameters.useForChangedCheck) {
return _screenshotData.image != _matchImage;
}
return _screenshotData.image != _matchImage;
cv::Mat result;
_patternImageData = CreatePatternData(_matchImage);
MatchPattern(_screenshotData.image, _patternImageData,
_patternMatchParameters.threshold, result,
_patternMatchParameters.useAlphaAsMask,
_patternMatchParameters.matchMode);
if (result.total() == 0) {
return false;
}
return countNonZero(result) == 0;
}
bool MacroConditionVideo::ScreenshotContainsObject()

View File

@@ -25,7 +25,7 @@ class PreviewDialog;
class MacroConditionVideo : public MacroCondition {
public:
MacroConditionVideo(Macro *m);
MacroConditionVideo(Macro *m) : MacroCondition(m, true){};
bool CheckCondition();
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);

View File

@@ -1,8 +1,6 @@
#include "opencv-helpers.hpp"
#include "log-helper.hpp"
#include <opencv2/core/ocl.hpp>
#include <opencv2/core/mat.hpp>
#include <log-helper.hpp>
namespace advss {
@@ -24,19 +22,17 @@ PatternImageData CreatePatternData(const QImage &pattern)
return data;
}
static void invertPatternMatchResult(cv::UMat &umat)
static void invertPatternMatchResult(cv::Mat &mat)
{
auto mat = umat.getMat(cv::ACCESS_RW);
for (int r = 0; r < mat.rows; r++) {
for (int c = 0; c < mat.cols; c++) {
mat.at<float>(r, c) = 1.0 - mat.at<float>(r, c);
}
}
umat = mat.getUMat(cv::ACCESS_RW);
}
void MatchPattern(QImage &img, const PatternImageData &patternData,
double threshold, cv::UMat &result, bool useAlphaAsMask,
double threshold, cv::Mat &result, bool useAlphaAsMask,
cv::TemplateMatchModes matchMode)
{
if (img.isNull() || patternData.rgbaPattern.empty()) {
@@ -55,12 +51,13 @@ void MatchPattern(QImage &img, const PatternImageData &patternData,
// thus should not be used while matching the pattern as well
//
// Input format is Format_RGBA8888 so discard the 4th channel
std::vector<cv::UMat> inputChannels;
std::vector<cv::Mat1b> inputChannels;
cv::split(input, inputChannels);
std::vector<cv::UMat> rgbChanlesImage(
std::vector<cv::Mat1b> rgbChanlesImage(
inputChannels.begin(), inputChannels.begin() + 3);
cv::UMat rgbInput;
cv::Mat3b rgbInput;
cv::merge(rgbChanlesImage, rgbInput);
cv::matchTemplate(rgbInput, patternData.rgbPattern, result,
matchMode, patternData.mask);
} else {
@@ -79,7 +76,7 @@ void MatchPattern(QImage &img, const PatternImageData &patternData,
}
void MatchPattern(QImage &img, QImage &pattern, double threshold,
cv::UMat &result, bool useAlphaAsMask,
cv::Mat &result, bool useAlphaAsMask,
cv::TemplateMatchModes matchColor)
{
auto data = CreatePatternData(pattern);
@@ -96,12 +93,16 @@ std::vector<cv::Rect> MatchObject(QImage &img, cv::CascadeClassifier &cascade,
}
auto image = QImageToMat(img);
cv::UMat frameGray;
cv::Mat frameGray;
cv::cvtColor(image, frameGray, cv::COLOR_RGBA2GRAY);
cv::equalizeHist(frameGray, frameGray);
std::vector<cv::Rect> objects;
cascade.detectMultiScale(frameGray, objects, scaleFactor, minNeighbors,
0, minSize, maxSize);
try {
cascade.detectMultiScale(frameGray, objects, scaleFactor,
minNeighbors, 0, minSize, maxSize);
} catch (const std::exception &e) {
vblog(LOG_INFO, "detectMultiScale failed: %s", e.what());
}
return objects;
}
@@ -111,9 +112,9 @@ uchar GetAvgBrightness(QImage &img)
return 0;
}
auto i = QImageToMat(img);
auto image = QImageToMat(img);
cv::Mat hsvImage, rgbImage;
cv::cvtColor(i, rgbImage, cv::COLOR_RGBA2RGB);
cv::cvtColor(image, rgbImage, cv::COLOR_RGBA2RGB);
cv::cvtColor(rgbImage, hsvImage, cv::COLOR_RGB2HSV);
long long brightnessSum = 0;
for (int i = 0; i < hsvImage.rows; ++i) {
@@ -138,8 +139,7 @@ static bool colorIsSimilar(const QColor &color1, const QColor &color2,
cv::Mat PreprocessForOCR(const QImage &image, const QColor &textColor,
double colorDiff)
{
auto umat = QImageToMat(image);
auto mat = umat.getMat(cv::ACCESS_RW);
auto mat = QImageToMat(image);
// Tesseract works best when matching black text on a white background,
// so everything that matches the text color will be displayed black
@@ -224,14 +224,13 @@ bool ContainsPixelsInColorRange(const QImage &image, const QColor &color,
// Assumption is that QImage uses Format_RGBA8888.
// Conversion from: https://github.com/dbzhang800/QtOpenCV
cv::UMat QImageToMat(const QImage &img)
cv::Mat QImageToMat(const QImage &img)
{
if (img.isNull()) {
return cv::UMat();
return cv::Mat();
}
auto temp = cv::Mat(img.height(), img.width(), CV_8UC(img.depth() / 8),
(uchar *)img.bits(), img.bytesPerLine());
return temp.getUMat(cv::ACCESS_RW);
return cv::Mat(img.height(), img.width(), CV_8UC(img.depth() / 8),
(uchar *)img.bits(), img.bytesPerLine());
}
QImage MatToQImage(const cv::Mat &mat)
@@ -243,12 +242,4 @@ QImage MatToQImage(const cv::Mat &mat)
QImage::Format::Format_RGBA8888);
}
void SetupOpenCL()
{
if (cv::ocl::haveOpenCL() && !cv::ocl::useOpenCL()) {
blog(LOG_INFO, "enabled OpenCL support for OpenCV");
cv::ocl::setUseOpenCL(true);
}
}
} // namespace advss

View File

@@ -42,17 +42,17 @@ constexpr int maxMinNeighbors = 6;
constexpr double defaultScaleFactor = 1.1;
struct PatternImageData {
cv::UMat rgbaPattern;
cv::UMat rgbPattern;
cv::UMat mask;
cv::Mat4b rgbaPattern;
cv::Mat3b rgbPattern;
cv::Mat1b mask;
};
PatternImageData CreatePatternData(const QImage &pattern);
void MatchPattern(QImage &img, const PatternImageData &patternData,
double threshold, cv::UMat &result, bool useAlphaAsMask,
double threshold, cv::Mat &result, bool useAlphaAsMask,
cv::TemplateMatchModes matchMode);
void MatchPattern(QImage &img, QImage &pattern, double threshold,
cv::UMat &result, bool useAlphaAsMask,
cv::Mat &result, bool useAlphaAsMask,
cv::TemplateMatchModes matchMode);
std::vector<cv::Rect> MatchObject(QImage &img, cv::CascadeClassifier &cascade,
double scaleFactor, int minNeighbors,
@@ -66,8 +66,7 @@ std::string RunOCR(tesseract::TessBaseAPI *, const QImage &, const QColor &,
bool ContainsPixelsInColorRange(const QImage &image, const QColor &color,
double colorDeviationThreshold,
double totalPixelMatchThreshold);
cv::UMat QImageToMat(const QImage &img);
cv::Mat QImageToMat(const QImage &img);
QImage MatToQImage(const cv::Mat &mat);
void SetupOpenCL();
} // namespace advss

View File

@@ -252,7 +252,9 @@ OCRParameters::OCRParameters(const OCRParameters &other)
colorThreshold(other.colorThreshold),
pageSegMode(other.pageSegMode)
{
Setup();
if (!initDone) {
Setup();
}
if (initDone) {
ocr->SetPageSegMode(pageSegMode);
}
@@ -265,7 +267,12 @@ OCRParameters &OCRParameters::operator=(const OCRParameters &other)
color = other.color;
colorThreshold = other.colorThreshold;
pageSegMode = other.pageSegMode;
ocr->SetPageSegMode(pageSegMode);
if (!initDone) {
Setup();
}
if (initDone) {
ocr->SetPageSegMode(pageSegMode);
}
return *this;
}

View File

@@ -122,6 +122,7 @@ void PreviewDialog::PatternMatchParametersChanged(
{
std::unique_lock<std::mutex> lock(_mtx);
_patternMatchParams = params;
_patternImageData = CreatePatternData(_patternMatchParams.image);
}
void PreviewDialog::ObjDetectParametersChanged(const ObjDetectParameters &params)
@@ -169,8 +170,8 @@ void PreviewDialog::UpdateImage(const QPixmap &image)
if (_type == PreviewType::SELECT_AREA && !_selectingArea) {
DrawFrame();
}
emit NeedImage(_video, _type, _patternMatchParams, _objDetectParams,
_ocrParams, _areaParams, _condition);
emit NeedImage(_video, _type, _patternMatchParams, _patternImageData,
_objDetectParams, _ocrParams, _areaParams, _condition);
}
void PreviewDialog::Start()
@@ -186,7 +187,7 @@ void PreviewDialog::Start()
return;
}
PreviewImage *worker = new PreviewImage(_mtx);
auto worker = new PreviewImage(_mtx);
worker->moveToThread(&_thread);
connect(&_thread, &QThread::finished, worker, &QObject::deleteLater);
connect(worker, &PreviewImage::ImageReady, this,
@@ -197,8 +198,8 @@ void PreviewDialog::Start()
&PreviewImage::CreateImage);
_thread.start();
emit NeedImage(_video, _type, _patternMatchParams, _objDetectParams,
_ocrParams, _areaParams, _condition);
emit NeedImage(_video, _type, _patternMatchParams, _patternImageData,
_objDetectParams, _ocrParams, _areaParams, _condition);
}
void PreviewDialog::DrawFrame()
@@ -216,14 +217,13 @@ void PreviewDialog::DrawFrame()
_rubberBand->show();
}
static void markPatterns(cv::UMat &matchResult, QImage &image,
const cv::UMat &pattern)
static void markPatterns(cv::Mat &matchResult, QImage &image,
const cv::Mat &pattern)
{
auto temp = matchResult.getMat(cv::ACCESS_RW);
auto matchImg = QImageToMat(image);
for (int row = 0; row < temp.rows - 1; row++) {
for (int col = 0; col < temp.cols - 1; col++) {
if (temp.at<float>(row, col) != 0.0) {
for (int row = 0; row < matchResult.rows - 1; row++) {
for (int col = 0; col < matchResult.cols - 1; col++) {
if (matchResult.at<float>(row, col) != 0.0) {
rectangle(matchImg, {col, row},
cv::Point(col + pattern.cols,
row + pattern.rows),
@@ -231,7 +231,6 @@ static void markPatterns(cv::UMat &matchResult, QImage &image,
}
}
}
matchResult = temp.getUMat(cv::ACCESS_RW);
}
static void markObjects(QImage &image, std::vector<cv::Rect> &objects)
@@ -249,6 +248,7 @@ PreviewImage::PreviewImage(std::mutex &mtx) : _mtx(mtx) {}
void PreviewImage::CreateImage(const VideoInput &video, PreviewType type,
const PatternMatchParameters &patternMatchParams,
const PatternImageData &patternImageData,
ObjDetectParameters objDetectParams,
OCRParameters ocrParams,
const AreaParameters &areaParams,
@@ -279,8 +279,6 @@ void PreviewImage::CreateImage(const VideoInput &video, PreviewType type,
areaParams.area.x, areaParams.area.y,
areaParams.area.width, areaParams.area.height);
}
const auto patternImageData =
CreatePatternData(patternMatchParams.image);
// Will emit status label update
MarkMatch(screenshot.image, patternMatchParams,
patternImageData, objDetectParams, ocrParams,
@@ -299,7 +297,7 @@ void PreviewImage::MarkMatch(QImage &screenshot,
VideoCondition condition)
{
if (condition == VideoCondition::PATTERN) {
cv::UMat result;
cv::Mat result;
MatchPattern(screenshot, patternImageData,
patternMatchParams.threshold, result,
patternMatchParams.useAlphaAsMask,

View File

@@ -25,7 +25,8 @@ public:
public slots:
void CreateImage(const VideoInput &, PreviewType,
const PatternMatchParameters &, ObjDetectParameters,
const PatternMatchParameters &,
const PatternImageData &, ObjDetectParameters,
OCRParameters, const AreaParameters &, VideoCondition);
signals:
void ImageReady(const QPixmap &);
@@ -63,8 +64,9 @@ private slots:
signals:
void SelectionAreaChanged(QRect area);
void NeedImage(const VideoInput &, PreviewType,
const PatternMatchParameters &, ObjDetectParameters,
OCRParameters, const AreaParameters &, VideoCondition);
const PatternMatchParameters &, const PatternImageData &,
ObjDetectParameters, OCRParameters,
const AreaParameters &, VideoCondition);
private:
void Start();
@@ -76,6 +78,7 @@ private:
VideoInput _video;
PatternMatchParameters _patternMatchParams;
PatternImageData _patternImageData;
ObjDetectParameters _objDetectParams;
OCRParameters _ocrParams;
AreaParameters _areaParams;

View File

@@ -510,7 +510,8 @@ bool DisplayMessage(const QString &msg, bool question, bool modal)
return (answer == QMessageBox::Yes);
} else if (question && modal) {
auto answer = QMessageBox::question(
nullptr,
static_cast<QMainWindow *>(
obs_frontend_get_main_window()),
obs_module_text("AdvSceneSwitcher.windowTitle"), msg,
QMessageBox::Yes | QMessageBox::No);
return answer == QMessageBox::Yes;
@@ -842,11 +843,9 @@ QStringList GetMediaSourceNames()
auto sourceEnum = [](void *param, obs_source_t *source) -> bool /* -- */
{
QStringList *list = reinterpret_cast<QStringList *>(param);
std::string sourceId = obs_source_get_id(source);
if (sourceId.compare("ffmpeg_source") == 0 ||
sourceId.compare("vlc_source") == 0 ||
sourceId.compare("slideshow") == 0 ||
sourceId.compare("media_playlist_source_codeyan") == 0) {
uint32_t flags = obs_source_get_output_flags(source);
if ((flags & OBS_SOURCE_CONTROLLABLE_MEDIA) != 0) {
*list << obs_source_get_name(source);
}
return true;