mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-22 01:44:49 -05:00
Add option to check for average brightness
This commit is contained in:
parent
a330378c16
commit
e5843de4fc
|
|
@ -149,6 +149,7 @@ AdvSceneSwitcher.condition.video.condition.hasNotChanged="has not changed"
|
|||
AdvSceneSwitcher.condition.video.condition.noImage="has no output"
|
||||
AdvSceneSwitcher.condition.video.condition.pattern="matches pattern"
|
||||
AdvSceneSwitcher.condition.video.condition.object="contains object"
|
||||
AdvSceneSwitcher.condition.video.condition.brightness="brightness"
|
||||
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
|
||||
|
|
@ -159,6 +160,9 @@ AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="This will al
|
|||
AdvSceneSwitcher.condition.video.patternThreshold="Threshold: "
|
||||
AdvSceneSwitcher.condition.video.patternThresholdDescription="A higher threshold value means that the pattern needs to match the video source more closely."
|
||||
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="Use alpha channel as mask for pattern."
|
||||
AdvSceneSwitcher.condition.video.brightnessThreshold="Average brightness:"
|
||||
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="A high value is indicating a bright image and a low one a darker one."
|
||||
AdvSceneSwitcher.condition.video.currentBrightness="Current average brightness: %1"
|
||||
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."
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ static std::map<VideoCondition, std::string> conditionTypes = {
|
|||
"AdvSceneSwitcher.condition.video.condition.pattern"},
|
||||
{VideoCondition::OBJECT,
|
||||
"AdvSceneSwitcher.condition.video.condition.object"},
|
||||
{VideoCondition::BRIGHTNESS,
|
||||
"AdvSceneSwitcher.condition.video.condition.brightness"},
|
||||
};
|
||||
|
||||
cv::CascadeClassifier initObjectCascade(std::string &path)
|
||||
|
|
@ -116,6 +118,7 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
|
|||
_usePatternForChangedCheck);
|
||||
obs_data_set_double(obj, "threshold", _patternThreshold);
|
||||
obs_data_set_bool(obj, "useAlphaAsMask", _useAlphaAsMask);
|
||||
obs_data_set_double(obj, "brightness", _brightnessThreshold);
|
||||
obs_data_set_string(obj, "modelDataPath", _modelDataPath.c_str());
|
||||
obs_data_set_double(obj, "scaleFactor", _scaleFactor);
|
||||
obs_data_set_int(obj, "minNeighbors", _minNeighbors);
|
||||
|
|
@ -155,6 +158,7 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
|||
obs_data_get_bool(obj, "usePatternForChangedCheck");
|
||||
_patternThreshold = obs_data_get_double(obj, "threshold");
|
||||
_useAlphaAsMask = obs_data_get_bool(obj, "useAlphaAsMask");
|
||||
_brightnessThreshold = obs_data_get_double(obj, "brightness");
|
||||
_modelDataPath = obs_data_get_string(obj, "modelDataPath");
|
||||
_scaleFactor = obs_data_get_double(obj, "scaleFactor");
|
||||
if (!isScaleFactorValid(_scaleFactor)) {
|
||||
|
|
@ -255,6 +259,12 @@ bool MacroConditionVideo::ScreenshotContainsObject()
|
|||
return objects.size() > 0;
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::CheckBrightnessThreshold()
|
||||
{
|
||||
_currentBrigthness = getAvgBrightness(_screenshotData.image) / 255.;
|
||||
return _currentBrigthness > _brightnessThreshold;
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::Compare()
|
||||
{
|
||||
if (_checkAreaEnable && _condition != VideoCondition::NO_IMAGE) {
|
||||
|
|
@ -278,6 +288,8 @@ bool MacroConditionVideo::Compare()
|
|||
return ScreenshotContainsPattern();
|
||||
case VideoCondition::OBJECT:
|
||||
return ScreenshotContainsObject();
|
||||
case VideoCondition::BRIGHTNESS:
|
||||
return CheckBrightnessThreshold();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -309,6 +321,13 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
"AdvSceneSwitcher.condition.video.patternThresholdDescription"))),
|
||||
_useAlphaAsMask(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask"))),
|
||||
_brightnessThreshold(new ThresholdSlider(
|
||||
0., 1.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.brightnessThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.brightnessThresholdDescription"))),
|
||||
_currentBrightness(new QLabel),
|
||||
_modelDataPath(new FileSelection()),
|
||||
_modelPathLayout(new QHBoxLayout),
|
||||
_objectScaleThreshold(new ThresholdSlider(
|
||||
|
|
@ -366,6 +385,9 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
this, SLOT(PatternThresholdChanged(double)));
|
||||
QWidget::connect(_useAlphaAsMask, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(UseAlphaAsMaskChanged(int)));
|
||||
QWidget::connect(_brightnessThreshold,
|
||||
SIGNAL(DoubleValueChanged(double)), this,
|
||||
SLOT(BrightnessThresholdChanged(double)));
|
||||
QWidget::connect(_objectScaleThreshold,
|
||||
SIGNAL(DoubleValueChanged(double)), this,
|
||||
SLOT(ObjectScaleThresholdChanged(double)));
|
||||
|
|
@ -451,6 +473,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
mainLayout->addWidget(_usePatternForChangedCheck);
|
||||
mainLayout->addWidget(_patternThreshold);
|
||||
mainLayout->addWidget(_useAlphaAsMask);
|
||||
mainLayout->addWidget(_brightnessThreshold);
|
||||
mainLayout->addWidget(_currentBrightness);
|
||||
mainLayout->addLayout(_modelPathLayout);
|
||||
mainLayout->addWidget(_objectScaleThreshold);
|
||||
mainLayout->addLayout(_neighborsControlLayout);
|
||||
|
|
@ -465,6 +489,10 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
|
||||
connect(&_updateBrightnessTimer, &QTimer::timeout, this,
|
||||
&MacroConditionVideoEdit::UpdateCurrentBrightness);
|
||||
_updateBrightnessTimer.start(1000);
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::UpdatePreviewTooltip()
|
||||
|
|
@ -673,6 +701,16 @@ void MacroConditionVideoEdit::UseAlphaAsMaskChanged(int value)
|
|||
_entryData->LoadImageFromFile();
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::BrightnessThresholdChanged(double value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_brightnessThreshold = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::ObjectScaleThresholdChanged(double value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
|
|
@ -774,6 +812,14 @@ void MacroConditionVideoEdit::ShowMatchClicked()
|
|||
_previewDialog.ShowMatch();
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::UpdateCurrentBrightness()
|
||||
{
|
||||
QString text = obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.currentBrightness");
|
||||
_currentBrightness->setText(
|
||||
text.arg(_entryData->GetCurrentBrightness()));
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::SelectAreaClicked()
|
||||
{
|
||||
_previewDialog.show();
|
||||
|
|
@ -843,6 +889,10 @@ void MacroConditionVideoEdit::SetWidgetVisibility()
|
|||
_patternThreshold->setVisible(needsThreshold(_entryData->_condition));
|
||||
_useAlphaAsMask->setVisible(_entryData->_condition ==
|
||||
VideoCondition::PATTERN);
|
||||
_brightnessThreshold->setVisible(_entryData->_condition ==
|
||||
VideoCondition::BRIGHTNESS);
|
||||
_currentBrightness->setVisible(_entryData->_condition ==
|
||||
VideoCondition::BRIGHTNESS);
|
||||
_showMatch->setVisible(needsShowMatch(_entryData->_condition));
|
||||
_objectScaleThreshold->setVisible(
|
||||
needsObjectControls(_entryData->_condition));
|
||||
|
|
@ -884,6 +934,7 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
|||
_entryData->_usePatternForChangedCheck);
|
||||
_patternThreshold->SetDoubleValue(_entryData->_patternThreshold);
|
||||
_useAlphaAsMask->setChecked(_entryData->_useAlphaAsMask);
|
||||
_brightnessThreshold->SetDoubleValue(_entryData->_brightnessThreshold);
|
||||
_modelDataPath->SetPath(_entryData->GetModelDataPath().c_str());
|
||||
_objectScaleThreshold->SetDoubleValue(_entryData->_scaleFactor);
|
||||
_minNeighbors->setValue(_entryData->_minNeighbors);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ enum class VideoCondition {
|
|||
NO_IMAGE,
|
||||
PATTERN,
|
||||
OBJECT,
|
||||
BRIGHTNESS,
|
||||
};
|
||||
|
||||
class MacroConditionVideo : public MacroCondition {
|
||||
|
|
@ -45,6 +46,7 @@ public:
|
|||
bool LoadModelData(std::string &path);
|
||||
std::string GetModelDataPath() { return _modelDataPath; }
|
||||
void ResetLastMatch() { _lastMatchResult = false; }
|
||||
double GetCurrentBrightness() { return _currentBrigthness; }
|
||||
|
||||
VideoSelection _video;
|
||||
VideoCondition _condition = VideoCondition::MATCH;
|
||||
|
|
@ -60,6 +62,7 @@ public:
|
|||
bool _usePatternForChangedCheck = false;
|
||||
PatternMatchData _patternData;
|
||||
double _patternThreshold = 0.8;
|
||||
double _brightnessThreshold = 0.5;
|
||||
cv::CascadeClassifier _objectCascade;
|
||||
double _scaleFactor = 1.1;
|
||||
int _minNeighbors = minMinNeighbors;
|
||||
|
|
@ -76,6 +79,7 @@ private:
|
|||
bool OutputChanged();
|
||||
bool ScreenshotContainsPattern();
|
||||
bool ScreenshotContainsObject();
|
||||
bool CheckBrightnessThreshold();
|
||||
bool Compare();
|
||||
bool CheckShouldBeSkipped();
|
||||
|
||||
|
|
@ -88,6 +92,7 @@ private:
|
|||
"/res/cascadeClassifiers/haarcascade_frontalface_alt.xml");
|
||||
bool _lastMatchResult = false;
|
||||
int _runCount = 0;
|
||||
double _currentBrigthness = 0.;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
|
@ -123,6 +128,8 @@ private slots:
|
|||
void PatternThresholdChanged(double);
|
||||
void UseAlphaAsMaskChanged(int value);
|
||||
|
||||
void BrightnessThresholdChanged(double);
|
||||
|
||||
void ModelPathChanged(const QString &text);
|
||||
void ObjectScaleThresholdChanged(double);
|
||||
void MinNeighborsChanged(int value);
|
||||
|
|
@ -137,6 +144,8 @@ private slots:
|
|||
void ThrottleEnableChanged(int value);
|
||||
void ThrottleCountChanged(int value);
|
||||
void ShowMatchClicked();
|
||||
|
||||
void UpdateCurrentBrightness();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
|
|
@ -152,6 +161,9 @@ protected:
|
|||
ThresholdSlider *_patternThreshold;
|
||||
QCheckBox *_useAlphaAsMask;
|
||||
|
||||
ThresholdSlider *_brightnessThreshold;
|
||||
QLabel *_currentBrightness;
|
||||
|
||||
FileSelection *_modelDataPath;
|
||||
QHBoxLayout *_modelPathLayout;
|
||||
ThresholdSlider *_objectScaleThreshold;
|
||||
|
|
@ -177,6 +189,8 @@ protected:
|
|||
std::shared_ptr<MacroConditionVideo> _entryData;
|
||||
|
||||
private:
|
||||
QTimer _updateBrightnessTimer;
|
||||
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -77,6 +77,21 @@ std::vector<cv::Rect> matchObject(QImage &img, cv::CascadeClassifier &cascade,
|
|||
return objects;
|
||||
}
|
||||
|
||||
uchar getAvgBrightness(QImage &img)
|
||||
{
|
||||
auto i = QImageToMat(img);
|
||||
cv::Mat hsvImage, rgbImage;
|
||||
cv::cvtColor(i, rgbImage, cv::COLOR_RGBA2RGB);
|
||||
cv::cvtColor(rgbImage, hsvImage, cv::COLOR_RGB2HSV);
|
||||
long long brightnessSum = 0;
|
||||
for (int i = 0; i < hsvImage.rows; ++i) {
|
||||
for (int j = 0; j < hsvImage.cols; ++j) {
|
||||
brightnessSum += hsvImage.at<cv::Vec3b>(i, j)[2];
|
||||
}
|
||||
}
|
||||
return brightnessSum / (hsvImage.rows * hsvImage.cols);
|
||||
}
|
||||
|
||||
// Assumption is that QImage uses Format_RGBA8888.
|
||||
// Conversion from: https://github.com/dbzhang800/QtOpenCV
|
||||
cv::Mat QImageToMat(const QImage &img)
|
||||
|
|
|
|||
|
|
@ -20,5 +20,6 @@ void matchPattern(QImage &img, QImage &pattern, double threshold,
|
|||
std::vector<cv::Rect> matchObject(QImage &img, cv::CascadeClassifier &cascade,
|
||||
double scaleFactor, int minNeighbors,
|
||||
cv::Size minSize, cv::Size maxSize);
|
||||
uchar getAvgBrightness(QImage &img);
|
||||
cv::Mat QImageToMat(const QImage &img);
|
||||
QImage MatToQImage(const cv::Mat &mat);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user