mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-07-19 01:15:14 -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:
parent
293d3dd16c
commit
5462334693
|
|
@ -160,9 +160,14 @@ 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}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum neighbors: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minSize="Minimum size: {{minSizeX}} x {{minSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.maxSize="Maximum size: {{maxSizeX}} x {{maxSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduce CPU load by performing check only every {{throttleCount}} milliseconds"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}Perform check only in area {{checkArea}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Minimum size:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Maximum size:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Select area"
|
||||
AdvSceneSwitcher.condition.video.selectArea.status="Only highlighted area will be checked"
|
||||
AdvSceneSwitcher.condition.video.width="Width"
|
||||
AdvSceneSwitcher.condition.video.height="Height"
|
||||
AdvSceneSwitcher.condition.stream="Streaming"
|
||||
AdvSceneSwitcher.condition.stream.state.start="Stream running"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
|
||||
|
|
|
|||
|
|
@ -146,8 +146,6 @@ AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
|
|||
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minSize="Minimum boyut: {{minSizeX}} x {{minSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.maxSize="Maximum boyut: {{maxSizeX}} x {{maxSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
|
||||
AdvSceneSwitcher.condition.stream="Yayınlama"
|
||||
AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
|
||||
|
|
@ -275,7 +273,6 @@ AdvSceneSwitcher.action.audio.type.mute="Sessiz"
|
|||
AdvSceneSwitcher.action.audio.type.unmute="Ses açmak"
|
||||
AdvSceneSwitcher.action.audio.type.sourceVolume="Kaynak ses seviyesini ayarla"
|
||||
AdvSceneSwitcher.action.audio.type.masterVolume="Ana ses seviyesini ayarla"
|
||||
AdvSceneSwitcher.action.audio.fade="{{fade}}karartmak {{duration}} saniye"
|
||||
AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}"
|
||||
AdvSceneSwitcher.action.recording="Kayıt"
|
||||
AdvSceneSwitcher.action.recording.type.stop="Kayıt Durdur"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和
|
|||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="隐藏可通过宏操作的分组栏"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.highlightExecutedMacros="突出显示最近执行的宏"
|
||||
AdvSceneSwitcher.generalTab.priority="优先级"
|
||||
AdvSceneSwitcher.generalTab.priority.description="切换场景优先级 (最上方的项优先级最高)"
|
||||
AdvSceneSwitcher.generalTab.priority.threadPriority="使用线程优先级"
|
||||
|
|
@ -155,8 +154,6 @@ AdvSceneSwitcher.condition.video.modelLoadFail="无法加载模型数据!"
|
|||
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minSize="最小尺寸: {{minSizeX}} x {{minSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.maxSize="最大尺寸: {{maxSizeX}} x {{maxSizeY}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}通过只执行每一次检查来减少CPU负载 {{throttleCount}} 毫秒"
|
||||
AdvSceneSwitcher.condition.stream="推流"
|
||||
AdvSceneSwitcher.condition.stream.state.start="推流启动"
|
||||
|
|
@ -320,7 +317,6 @@ AdvSceneSwitcher.action.audio.type.mute="静音"
|
|||
AdvSceneSwitcher.action.audio.type.unmute="取消静音"
|
||||
AdvSceneSwitcher.action.audio.type.sourceVolume="来源音量"
|
||||
AdvSceneSwitcher.action.audio.type.masterVolume="主音量"
|
||||
AdvSceneSwitcher.action.audio.fade="{{fade}}淡出 {{duration}} 秒"
|
||||
AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}"
|
||||
AdvSceneSwitcher.action.recording="录制"
|
||||
AdvSceneSwitcher.action.recording.type.stop="停止录制"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user