Add option to check for average brightness

This commit is contained in:
WarmUpTill 2022-10-15 17:08:34 +02:00 committed by WarmUpTill
parent a330378c16
commit e5843de4fc
5 changed files with 85 additions and 0 deletions

View File

@ -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."

View File

@ -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);

View File

@ -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;
};

View File

@ -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)

View File

@ -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);