mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-10-01 05:49:48 -05:00
Add option to perform video check only on parts of the video source
This will significantly reduce CPU usage if the video source larger than the selected area and make it easier to only check parts of a video source output image.
This commit is contained in:
@@ -17,6 +17,8 @@ endif()
|
||||
|
||||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../headers")
|
||||
set(module_SOURCES
|
||||
area-selection.cpp
|
||||
area-selection.hpp
|
||||
macro-condition-video.cpp
|
||||
macro-condition-video.hpp
|
||||
video-match-dialog.cpp
|
||||
|
||||
130
src/external-macro-modules/opencv/area-selection.cpp
Normal file
130
src/external-macro-modules/opencv/area-selection.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include "area-selection.hpp"
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <obs-module.h>
|
||||
|
||||
void advss::Size::Save(obs_data_t *obj, const char *name)
|
||||
{
|
||||
auto data = obs_data_create();
|
||||
obs_data_set_int(data, "width", width);
|
||||
obs_data_set_int(data, "height", height);
|
||||
obs_data_set_obj(obj, name, data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void advss::Size::Load(obs_data_t *obj, const char *name)
|
||||
{
|
||||
auto data = obs_data_get_obj(obj, name);
|
||||
width = obs_data_get_int(data, "width");
|
||||
height = obs_data_get_int(data, "height");
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
cv::Size advss::Size::CV()
|
||||
{
|
||||
return {width, height};
|
||||
}
|
||||
|
||||
void advss::Area::Save(obs_data_t *obj, const char *name)
|
||||
{
|
||||
auto data = obs_data_create();
|
||||
obs_data_set_int(data, "x", x);
|
||||
obs_data_set_int(data, "y", y);
|
||||
obs_data_set_int(data, "width", width);
|
||||
obs_data_set_int(data, "height", height);
|
||||
obs_data_set_obj(obj, name, data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void advss::Area::Load(obs_data_t *obj, const char *name)
|
||||
{
|
||||
auto data = obs_data_get_obj(obj, name);
|
||||
x = obs_data_get_int(data, "x");
|
||||
y = obs_data_get_int(data, "y");
|
||||
width = obs_data_get_int(data, "width");
|
||||
height = obs_data_get_int(data, "height");
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
SizeSelection::SizeSelection(int min, int max, QWidget *parent)
|
||||
: _x(new QSpinBox), _y(new QSpinBox), QWidget(parent)
|
||||
{
|
||||
_x->setMinimum(min);
|
||||
_y->setMinimum(min);
|
||||
_x->setMaximum(max);
|
||||
_y->setMaximum(max);
|
||||
|
||||
connect(_x, SIGNAL(valueChanged(int)), this, SLOT(XChanged(int)));
|
||||
connect(_y, SIGNAL(valueChanged(int)), this, SLOT(YChanged(int)));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_x);
|
||||
layout->addWidget(new QLabel(" x "));
|
||||
layout->addWidget(_y);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void SizeSelection::SetSize(const advss::Size &s)
|
||||
{
|
||||
_x->setValue(s.width);
|
||||
_y->setValue(s.height);
|
||||
}
|
||||
|
||||
advss::Size SizeSelection::Size()
|
||||
{
|
||||
return advss::Size{_x->value(), _y->value()};
|
||||
}
|
||||
|
||||
void SizeSelection::XChanged(int value)
|
||||
{
|
||||
emit SizeChanged(advss::Size{value, _y->value()});
|
||||
}
|
||||
|
||||
void SizeSelection::YChanged(int value)
|
||||
{
|
||||
emit SizeChanged(advss::Size{_x->value(), value});
|
||||
}
|
||||
|
||||
AreaSelection::AreaSelection(int min, int max, QWidget *parent)
|
||||
: _x(new SizeSelection(min, max)),
|
||||
_y(new SizeSelection(min, max)),
|
||||
QWidget(parent)
|
||||
{
|
||||
_x->_x->setToolTip("X");
|
||||
_x->_y->setToolTip("Y");
|
||||
_y->_x->setToolTip(
|
||||
obs_module_text("AdvSceneSwitcher.condition.video.width"));
|
||||
_y->_y->setToolTip(
|
||||
obs_module_text("AdvSceneSwitcher.condition.video.height"));
|
||||
|
||||
connect(_x, SIGNAL(SizeChanged(advss::Size)), this,
|
||||
SLOT(XSizeChanged(advss::Size)));
|
||||
connect(_y, SIGNAL(SizeChanged(advss::Size)), this,
|
||||
SLOT(YSizeChanged(advss::Size)));
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_x);
|
||||
layout->addWidget(_y);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void AreaSelection::SetArea(const advss::Area &value)
|
||||
{
|
||||
_x->SetSize({value.x, value.y});
|
||||
_y->SetSize({value.width, value.height});
|
||||
}
|
||||
|
||||
void AreaSelection::XSizeChanged(advss::Size value)
|
||||
{
|
||||
emit AreaChanged(advss::Area{value.width, value.height,
|
||||
_y->Size().width, _y->Size().height});
|
||||
}
|
||||
|
||||
void AreaSelection::YSizeChanged(advss::Size value)
|
||||
{
|
||||
emit AreaChanged(advss::Area{_x->Size().width, _x->Size().height,
|
||||
value.width, value.height});
|
||||
}
|
||||
67
src/external-macro-modules/opencv/area-selection.hpp
Normal file
67
src/external-macro-modules/opencv/area-selection.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include <QWidget>
|
||||
#include <QSpinBox>
|
||||
#include <obs-data.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct Size {
|
||||
void Save(obs_data_t *obj, const char *name);
|
||||
void Load(obs_data_t *obj, const char *name);
|
||||
cv::Size CV();
|
||||
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Area {
|
||||
void Save(obs_data_t *obj, const char *name);
|
||||
void Load(obs_data_t *obj, const char *name);
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class SizeSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SizeSelection(int min, int max, QWidget *parent = 0);
|
||||
void SetSize(const advss::Size &);
|
||||
advss::Size Size();
|
||||
|
||||
private slots:
|
||||
void XChanged(int);
|
||||
void YChanged(int);
|
||||
signals:
|
||||
void SizeChanged(advss::Size value);
|
||||
|
||||
private:
|
||||
QSpinBox *_x;
|
||||
QSpinBox *_y;
|
||||
|
||||
friend class AreaSelection;
|
||||
};
|
||||
|
||||
class AreaSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AreaSelection(int min, int max, QWidget *parent = 0);
|
||||
void SetArea(const advss::Area &);
|
||||
|
||||
private slots:
|
||||
void XSizeChanged(advss::Size value);
|
||||
void YSizeChanged(advss::Size value);
|
||||
signals:
|
||||
void AreaChanged(advss::Area value);
|
||||
|
||||
private:
|
||||
SizeSelection *_x;
|
||||
SizeSelection *_y;
|
||||
};
|
||||
@@ -110,12 +110,12 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
|
||||
obs_data_set_string(obj, "modelDataPath", _modelDataPath.c_str());
|
||||
obs_data_set_double(obj, "scaleFactor", _scaleFactor);
|
||||
obs_data_set_int(obj, "minNeighbors", _minNeighbors);
|
||||
obs_data_set_int(obj, "minSizeX", _minSizeX);
|
||||
obs_data_set_int(obj, "minSizeY", _minSizeY);
|
||||
obs_data_set_int(obj, "maxSizeX", _maxSizeX);
|
||||
obs_data_set_int(obj, "maxSizeY", _maxSizeY);
|
||||
_minSize.Save(obj, "minSize");
|
||||
_maxSize.Save(obj, "maxSize");
|
||||
obs_data_set_bool(obj, "throttleEnabled", _throttleEnabled);
|
||||
obs_data_set_int(obj, "throttleCount", _throttleCount);
|
||||
obs_data_set_bool(obj, "checkAreaEnabled", _checkAreaEnable);
|
||||
_checkArea.Save(obj, "checkArea");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -151,13 +151,20 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
||||
if (!isMinNeighborsValid(_minNeighbors)) {
|
||||
_minNeighbors = minMinNeighbors;
|
||||
}
|
||||
_minSizeX = obs_data_get_int(obj, "minSizeX");
|
||||
_minSizeY = obs_data_get_int(obj, "minSizeY");
|
||||
_maxSizeX = obs_data_get_int(obj, "maxSizeX");
|
||||
_maxSizeY = obs_data_get_int(obj, "maxSizeY");
|
||||
// TODO: Remove this fallback in future version
|
||||
if (obs_data_has_user_value(obj, "minSizeX")) {
|
||||
_minSize.width = obs_data_get_int(obj, "minSizeX");
|
||||
_minSize.height = obs_data_get_int(obj, "minSizeY");
|
||||
_maxSize.width = obs_data_get_int(obj, "maxSizeX");
|
||||
_maxSize.height = obs_data_get_int(obj, "maxSizeY");
|
||||
} else {
|
||||
_minSize.Load(obj, "minSize");
|
||||
_maxSize.Load(obj, "maxSize");
|
||||
}
|
||||
_throttleEnabled = obs_data_get_bool(obj, "throttleEnabled");
|
||||
_throttleCount = obs_data_get_int(obj, "throttleCount");
|
||||
|
||||
_checkAreaEnable = obs_data_get_bool(obj, "checkAreaEnabled");
|
||||
_checkArea.Load(obj, "checkArea");
|
||||
if (requiresFileInput(_condition)) {
|
||||
(void)LoadImageFromFile();
|
||||
}
|
||||
@@ -230,14 +237,19 @@ bool MacroConditionVideo::OutputChanged()
|
||||
bool MacroConditionVideo::ScreenshotContainsObject()
|
||||
{
|
||||
auto objects = matchObject(_screenshotData.image, _objectCascade,
|
||||
_scaleFactor, _minNeighbors,
|
||||
{_minSizeX, _minSizeY},
|
||||
{_maxSizeX, _maxSizeY});
|
||||
_scaleFactor, _minNeighbors, _minSize.CV(),
|
||||
_maxSize.CV());
|
||||
return objects.size() > 0;
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::Compare()
|
||||
{
|
||||
if (_checkAreaEnable && _condition != VideoCondition::NO_IMAGE) {
|
||||
_screenshotData.image = _screenshotData.image.copy(
|
||||
_checkArea.x, _checkArea.y, _checkArea.width,
|
||||
_checkArea.height);
|
||||
}
|
||||
|
||||
switch (_condition) {
|
||||
case VideoCondition::MATCH:
|
||||
return _screenshotData.image == _matchImage;
|
||||
@@ -269,54 +281,52 @@ static inline void populateConditionSelection(QComboBox *list)
|
||||
MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionVideo> entryData)
|
||||
: QWidget(parent),
|
||||
_matchDialog(this, entryData.get(), &GetSwitcher()->m)
|
||||
_videoSelection(new QComboBox()),
|
||||
_condition(new QComboBox()),
|
||||
_imagePath(new FileSelection()),
|
||||
_usePatternForChangedCheck(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.usePatternForChangedCheck"))),
|
||||
_patternThreshold(new ThresholdSlider(
|
||||
0., 1.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdDescription"))),
|
||||
_useAlphaAsMask(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask"))),
|
||||
_modelDataPath(new FileSelection()),
|
||||
_objectScaleThreshold(new ThresholdSlider(
|
||||
1.1, 5.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.objectScaleThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.objectScaleThresholdDescription"))),
|
||||
_minNeighbors(new QSpinBox()),
|
||||
_minNeighborsDescription(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.minNeighborDescription"))),
|
||||
_minSize(new SizeSelection(0, 1024)),
|
||||
_maxSize(new SizeSelection(0, 4096)),
|
||||
_checkAreaEnable(new QCheckBox()),
|
||||
_checkArea(new AreaSelection(0, 99999)),
|
||||
_throttleEnable(new QCheckBox()),
|
||||
_throttleCount(new QSpinBox()),
|
||||
_showMatch(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.showMatch"))),
|
||||
_matchDialog(this, entryData.get(), &GetSwitcher()->m),
|
||||
_modelPathLayout(new QHBoxLayout),
|
||||
_neighborsControlLayout(new QHBoxLayout),
|
||||
_checkAreaControlLayout(new QHBoxLayout),
|
||||
_throttleControlLayout(new QHBoxLayout),
|
||||
_sizeLayout(new QHBoxLayout())
|
||||
{
|
||||
_videoSelection = new QComboBox();
|
||||
_condition = new QComboBox();
|
||||
|
||||
_imagePath = new FileSelection();
|
||||
_imagePath->Button()->disconnect();
|
||||
_usePatternForChangedCheck = new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.usePatternForChangedCheck"));
|
||||
_usePatternForChangedCheck->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip"));
|
||||
_patternThreshold = new ThresholdSlider(
|
||||
0., 1.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdDescription"));
|
||||
_useAlphaAsMask = new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask"));
|
||||
|
||||
_modelDataPath = new FileSelection();
|
||||
_objectScaleThreshold = new ThresholdSlider(
|
||||
1.1, 5.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.objectScaleThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.objectScaleThresholdDescription"));
|
||||
_minNeighbors = new QSpinBox();
|
||||
_minNeighbors->setMinimum(minMinNeighbors);
|
||||
_minNeighbors->setMaximum(maxMinNeighbors);
|
||||
_minNeighborsDescription = new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.minNeighborDescription"));
|
||||
_minSizeX = new QSpinBox();
|
||||
_minSizeY = new QSpinBox();
|
||||
_minSizeX->setMaximum(1024);
|
||||
_minSizeY->setMaximum(1024);
|
||||
_maxSizeX = new QSpinBox();
|
||||
_maxSizeY = new QSpinBox();
|
||||
_maxSizeX->setMaximum(4096);
|
||||
_maxSizeY->setMaximum(4096);
|
||||
|
||||
_throttleEnable = new QCheckBox();
|
||||
_throttleCount = new QSpinBox();
|
||||
_throttleCount->setMinimum(1 * GetSwitcher()->interval);
|
||||
_throttleCount->setMaximum(10 * GetSwitcher()->interval);
|
||||
_throttleCount->setSingleStep(GetSwitcher()->interval);
|
||||
_showMatch = new QPushButton(
|
||||
obs_module_text("AdvSceneSwitcher.condition.video.showMatch"));
|
||||
|
||||
QWidget::connect(_videoSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
@@ -338,14 +348,14 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
SLOT(ObjectScaleThresholdChanged(double)));
|
||||
QWidget::connect(_minNeighbors, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MinNeighborsChanged(int)));
|
||||
QWidget::connect(_minSizeX, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MinSizeXChanged(int)));
|
||||
QWidget::connect(_minSizeY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MinSizeYChanged(int)));
|
||||
QWidget::connect(_maxSizeX, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxSizeXChanged(int)));
|
||||
QWidget::connect(_maxSizeY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxSizeYChanged(int)));
|
||||
QWidget::connect(_minSize, SIGNAL(SizeChanged(advss::Size)), this,
|
||||
SLOT(MinSizeChanged(advss::Size)));
|
||||
QWidget::connect(_maxSize, SIGNAL(SizeChanged(advss::Size)), this,
|
||||
SLOT(MaxSizeChanged(advss::Size)));
|
||||
QWidget::connect(_checkAreaEnable, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(CheckAreaEnableChanged(int)));
|
||||
QWidget::connect(_checkArea, SIGNAL(AreaChanged(advss::Area)), this,
|
||||
SLOT(CheckAreaChanged(advss::Area)));
|
||||
QWidget::connect(_modelDataPath, SIGNAL(PathChanged(const QString &)),
|
||||
this, SLOT(ModelPathChanged(const QString &)));
|
||||
QWidget::connect(_throttleEnable, SIGNAL(stateChanged(int)), this,
|
||||
@@ -364,43 +374,46 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
{"{{condition}}", _condition},
|
||||
{"{{imagePath}}", _imagePath},
|
||||
{"{{minNeighbors}}", _minNeighbors},
|
||||
{"{{minSizeX}}", _minSizeX},
|
||||
{"{{minSizeY}}", _minSizeY},
|
||||
{"{{maxSizeX}}", _maxSizeX},
|
||||
{"{{maxSizeY}}", _maxSizeY},
|
||||
{"{{minSize}}", _minSize},
|
||||
{"{{maxSize}}", _maxSize},
|
||||
{"{{modelDataPath}}", _modelDataPath},
|
||||
{"{{throttleEnable}}", _throttleEnable},
|
||||
{"{{throttleCount}}", _throttleCount},
|
||||
{"{{checkAreaEnable}}", _checkAreaEnable},
|
||||
{"{{checkArea}}", _checkArea},
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.video.entry"),
|
||||
entryLine1Layout, widgetPlaceholders);
|
||||
|
||||
_modelPathLayout = new QHBoxLayout;
|
||||
placeWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.modelPath"),
|
||||
_modelPathLayout, widgetPlaceholders);
|
||||
|
||||
_neighborsControlLayout = new QHBoxLayout;
|
||||
placeWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.minNeighbor"),
|
||||
_neighborsControlLayout, widgetPlaceholders);
|
||||
|
||||
_minSizeControlLayout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.minSize"),
|
||||
_minSizeControlLayout, widgetPlaceholders);
|
||||
|
||||
_maxSizeControlLayout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.maxSize"),
|
||||
_maxSizeControlLayout, widgetPlaceholders);
|
||||
|
||||
_throttleControlLayout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.throttle"),
|
||||
_throttleControlLayout, widgetPlaceholders);
|
||||
placeWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.entry.checkArea"),
|
||||
_checkAreaControlLayout, widgetPlaceholders);
|
||||
|
||||
QGridLayout *sizeGrid = new QGridLayout;
|
||||
sizeGrid->addWidget(
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.minSize")),
|
||||
0, 0);
|
||||
sizeGrid->addWidget(_minSize, 0, 1);
|
||||
sizeGrid->addWidget(
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.maxSize")),
|
||||
1, 0);
|
||||
sizeGrid->addWidget(_maxSize, 1, 1);
|
||||
_sizeLayout->addLayout(sizeGrid);
|
||||
_sizeLayout->addStretch();
|
||||
_sizeLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QHBoxLayout *showMatchLayout = new QHBoxLayout;
|
||||
showMatchLayout->addWidget(_showMatch);
|
||||
@@ -414,10 +427,10 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
mainLayout->addWidget(_objectScaleThreshold);
|
||||
mainLayout->addLayout(_neighborsControlLayout);
|
||||
mainLayout->addWidget(_minNeighborsDescription);
|
||||
mainLayout->addLayout(_minSizeControlLayout);
|
||||
mainLayout->addLayout(_maxSizeControlLayout);
|
||||
mainLayout->addLayout(_sizeLayout);
|
||||
mainLayout->addLayout(showMatchLayout);
|
||||
mainLayout->addLayout(_throttleControlLayout);
|
||||
mainLayout->addLayout(_checkAreaControlLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -620,44 +633,45 @@ void MacroConditionVideoEdit::MinNeighborsChanged(int value)
|
||||
_entryData->_minNeighbors = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::MinSizeXChanged(int value)
|
||||
void MacroConditionVideoEdit::MinSizeChanged(advss::Size value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_minSizeX = value;
|
||||
_entryData->_minSize = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::MinSizeYChanged(int value)
|
||||
void MacroConditionVideoEdit::MaxSizeChanged(advss::Size value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_minSizeY = value;
|
||||
_entryData->_maxSize = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::MaxSizeXChanged(int value)
|
||||
void MacroConditionVideoEdit::CheckAreaEnableChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_maxSizeX = value;
|
||||
_entryData->_checkAreaEnable = value;
|
||||
_checkArea->setEnabled(value);
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::MaxSizeYChanged(int value)
|
||||
void MacroConditionVideoEdit::CheckAreaChanged(advss::Area value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_maxSizeY = value;
|
||||
_entryData->_checkArea = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::ThrottleEnableChanged(int value)
|
||||
@@ -737,6 +751,11 @@ bool patternControlIsOptional(VideoCondition cond)
|
||||
cond == VideoCondition::HAS_NOT_CHANGED;
|
||||
}
|
||||
|
||||
bool needsAreaControls(VideoCondition cond)
|
||||
{
|
||||
return cond != VideoCondition::NO_IMAGE;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::SetWidgetVisibility()
|
||||
{
|
||||
_imagePath->setVisible(requiresFileInput(_entryData->_condition));
|
||||
@@ -752,14 +771,14 @@ void MacroConditionVideoEdit::SetWidgetVisibility()
|
||||
needsObjectControls(_entryData->_condition));
|
||||
_minNeighborsDescription->setVisible(
|
||||
needsObjectControls(_entryData->_condition));
|
||||
setLayoutVisible(_minSizeControlLayout,
|
||||
needsObjectControls(_entryData->_condition));
|
||||
setLayoutVisible(_maxSizeControlLayout,
|
||||
setLayoutVisible(_sizeLayout,
|
||||
needsObjectControls(_entryData->_condition));
|
||||
setLayoutVisible(_modelPathLayout,
|
||||
needsObjectControls(_entryData->_condition));
|
||||
setLayoutVisible(_throttleControlLayout,
|
||||
needsThrottleControls(_entryData->_condition));
|
||||
setLayoutVisible(_checkAreaControlLayout,
|
||||
needsAreaControls(_entryData->_condition));
|
||||
|
||||
if (_entryData->_condition == VideoCondition::HAS_CHANGED ||
|
||||
_entryData->_condition == VideoCondition::HAS_NOT_CHANGED) {
|
||||
@@ -787,12 +806,13 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
||||
_modelDataPath->SetPath(_entryData->GetModelDataPath().c_str());
|
||||
_objectScaleThreshold->SetDoubleValue(_entryData->_scaleFactor);
|
||||
_minNeighbors->setValue(_entryData->_minNeighbors);
|
||||
_minSizeX->setValue(_entryData->_minSizeX);
|
||||
_minSizeY->setValue(_entryData->_minSizeY);
|
||||
_maxSizeX->setValue(_entryData->_maxSizeX);
|
||||
_maxSizeY->setValue(_entryData->_maxSizeY);
|
||||
_minSize->SetSize(_entryData->_minSize);
|
||||
_maxSize->SetSize(_entryData->_maxSize);
|
||||
_throttleEnable->setChecked(_entryData->_throttleEnabled);
|
||||
_throttleCount->setValue(_entryData->_throttleCount *
|
||||
GetSwitcher()->interval);
|
||||
_checkAreaEnable->setChecked(_entryData->_checkAreaEnable);
|
||||
_checkArea->SetArea(_entryData->_checkArea);
|
||||
UpdatePreviewTooltip();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#pragma once
|
||||
#include "opencv-helpers.hpp"
|
||||
#include "threshold-slider.hpp"
|
||||
#include "video-match-dialog.hpp"
|
||||
#include "area-selection.hpp"
|
||||
|
||||
#include <macro.hpp>
|
||||
#include <screenshot-helper.hpp>
|
||||
#include <opencv-helpers.hpp>
|
||||
#include <file-selection.hpp>
|
||||
#include <threshold-slider.hpp>
|
||||
#include <video-match-dialog.hpp>
|
||||
#include <screenshot-helper.hpp>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
|
||||
enum class VideoCondition {
|
||||
@@ -51,10 +54,11 @@ public:
|
||||
cv::CascadeClassifier _objectCascade;
|
||||
double _scaleFactor = 1.1;
|
||||
int _minNeighbors = minMinNeighbors;
|
||||
int _minSizeX = 0;
|
||||
int _minSizeY = 0;
|
||||
int _maxSizeX = 0;
|
||||
int _maxSizeY = 0;
|
||||
advss::Size _minSize{0, 0};
|
||||
advss::Size _maxSize{0, 0};
|
||||
|
||||
bool _checkAreaEnable = false;
|
||||
advss::Area _checkArea{0, 0, 0, 0};
|
||||
|
||||
bool _throttleEnabled = false;
|
||||
int _throttleCount = 3;
|
||||
@@ -110,10 +114,11 @@ private slots:
|
||||
void ModelPathChanged(const QString &text);
|
||||
void ObjectScaleThresholdChanged(double);
|
||||
void MinNeighborsChanged(int value);
|
||||
void MinSizeXChanged(int value);
|
||||
void MinSizeYChanged(int value);
|
||||
void MaxSizeXChanged(int value);
|
||||
void MaxSizeYChanged(int value);
|
||||
void MinSizeChanged(advss::Size value);
|
||||
void MaxSizeChanged(advss::Size value);
|
||||
|
||||
void CheckAreaEnableChanged(int value);
|
||||
void CheckAreaChanged(advss::Area);
|
||||
|
||||
void ThrottleEnableChanged(int value);
|
||||
void ThrottleCountChanged(int value);
|
||||
@@ -136,16 +141,18 @@ protected:
|
||||
QHBoxLayout *_neighborsControlLayout;
|
||||
QSpinBox *_minNeighbors;
|
||||
QLabel *_minNeighborsDescription;
|
||||
QHBoxLayout *_minSizeControlLayout;
|
||||
QSpinBox *_minSizeX;
|
||||
QSpinBox *_minSizeY;
|
||||
QHBoxLayout *_maxSizeControlLayout;
|
||||
QSpinBox *_maxSizeX;
|
||||
QSpinBox *_maxSizeY;
|
||||
QHBoxLayout *_sizeLayout;
|
||||
SizeSelection *_minSize;
|
||||
SizeSelection *_maxSize;
|
||||
|
||||
QHBoxLayout *_checkAreaControlLayout;
|
||||
QCheckBox *_checkAreaEnable;
|
||||
AreaSelection *_checkArea;
|
||||
|
||||
QHBoxLayout *_throttleControlLayout;
|
||||
QCheckBox *_throttleEnable;
|
||||
QSpinBox *_throttleCount;
|
||||
|
||||
QPushButton *_showMatch;
|
||||
ShowMatchDialog _matchDialog;
|
||||
|
||||
|
||||
@@ -88,12 +88,20 @@ void ShowMatchDialog::CheckForMatchLoop()
|
||||
_imageLabel->setPixmap(QPixmap());
|
||||
continue;
|
||||
}
|
||||
auto image = MarkMatch(screenshot.image);
|
||||
|
||||
if (_conditionData->_checkAreaEnable) {
|
||||
screenshot.image = screenshot.image.copy(
|
||||
_conditionData->_checkArea.x,
|
||||
_conditionData->_checkArea.y,
|
||||
_conditionData->_checkArea.width,
|
||||
_conditionData->_checkArea.height);
|
||||
}
|
||||
MarkMatch(screenshot.image);
|
||||
_imageLabel->setPixmap(QPixmap::fromImage(screenshot.image));
|
||||
}
|
||||
}
|
||||
|
||||
QImage markPatterns(cv::Mat &matchResult, QImage &image, QImage &pattern)
|
||||
void markPatterns(cv::Mat &matchResult, QImage &image, QImage &pattern)
|
||||
{
|
||||
auto matchImg = QImageToMat(image);
|
||||
for (int row = 0; row < matchResult.rows - 1; row++) {
|
||||
@@ -106,10 +114,9 @@ QImage markPatterns(cv::Mat &matchResult, QImage &image, QImage &pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
return MatToQImage(matchImg);
|
||||
}
|
||||
|
||||
QImage markObjects(QImage &image, std::vector<cv::Rect> &objects)
|
||||
void markObjects(QImage &image, std::vector<cv::Rect> &objects)
|
||||
{
|
||||
auto frame = QImageToMat(image);
|
||||
for (size_t i = 0; i < objects.size(); i++) {
|
||||
@@ -118,12 +125,10 @@ QImage markObjects(QImage &image, std::vector<cv::Rect> &objects)
|
||||
objects[i].y + objects[i].height),
|
||||
cv::Scalar(255, 0, 0, 255), 2, 8, 0);
|
||||
}
|
||||
return MatToQImage(frame);
|
||||
}
|
||||
|
||||
QImage ShowMatchDialog::MarkMatch(QImage &screenshot)
|
||||
void ShowMatchDialog::MarkMatch(QImage &screenshot)
|
||||
{
|
||||
QImage resultIamge;
|
||||
if (_conditionData->_condition == VideoCondition::PATTERN) {
|
||||
cv::Mat result;
|
||||
QImage pattern = _conditionData->GetMatchImage();
|
||||
@@ -131,30 +136,27 @@ QImage ShowMatchDialog::MarkMatch(QImage &screenshot)
|
||||
_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);
|
||||
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});
|
||||
auto objects = matchObject(screenshot,
|
||||
_conditionData->_objectCascade,
|
||||
_conditionData->_scaleFactor,
|
||||
_conditionData->_minNeighbors,
|
||||
_conditionData->_minSize.CV(),
|
||||
_conditionData->_maxSize.CV());
|
||||
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);
|
||||
markObjects(screenshot, objects);
|
||||
}
|
||||
}
|
||||
return resultIamge;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void CheckForMatchLoop();
|
||||
QImage MarkMatch(QImage &screenshot);
|
||||
void MarkMatch(QImage &screenshot);
|
||||
|
||||
MacroConditionVideo *_conditionData;
|
||||
QScrollArea *_scrollArea;
|
||||
|
||||
Reference in New Issue
Block a user