Add tesseract config file support

This commit is contained in:
warmuptill 2025-05-13 08:59:21 +02:00 committed by WarmUpTill
parent 5490fabf92
commit 0e5f56b562
15 changed files with 384 additions and 284 deletions

View File

@ -194,12 +194,12 @@ AdvSceneSwitcher.condition.video.modelLoadFail="Modelldaten konnten nicht gelade
AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.condition.video.type.source="Quelle"
AdvSceneSwitcher.condition.video.type.scene="Szene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Minimale Größe:"
AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:"
AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen"

View File

@ -392,6 +392,13 @@ AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage="Full image matche
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.ocrMatchSuccess="Detected text:\n\n%1"
AdvSceneSwitcher.condition.video.ocrMatchFail="Could not detect any text!"
AdvSceneSwitcher.condition.video.ocrUseConfigFile="Use custom tesseract config file"
AdvSceneSwitcher.condition.video.ocrOpenConfigFile="Open"
AdvSceneSwitcher.condition.video.ocrOpenConfig.createFailed="Could not create the config file!"
AdvSceneSwitcher.condition.video.ocrOpenConfig.openFailed="Could not open the config file!"
AdvSceneSwitcher.condition.video.ocrConfigReload="Reload configuration file"
AdvSceneSwitcher.condition.video.ocrConfigHint="Tesseract config files consist of lines with parameter-value pairs (space separated).\nFor example:\n\ntessedit_char_blacklist\t\t\t\t\"abc\"\nlanguage_model_penalty_non_dict_word\t0"
AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!"
AdvSceneSwitcher.condition.video.selectColor="Select Color"
AdvSceneSwitcher.condition.video.ocrMode.singleColumn="Single column of text of variable sizes"
@ -411,17 +418,18 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="How similar
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{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.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Perform check only in area"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Check for text color:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Check for text type:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcBaseDir="Tesseract base directory:{{tesseractBaseDir}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Check for language:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Check for color:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Model data (haar cascade classifier):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum neighbors:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Perform check only in area"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Check for text color:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="Check for text type:{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrBaseDir="Tesseract base directory:{{tesseractBaseDir}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Check for language:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.ocrConfig="Config file:{{configFile}}{{openConfigFile}}{{reloadConfig}}{{configFileHint}}"
AdvSceneSwitcher.condition.video.layout.color="Check for color:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Minimum size:"
AdvSceneSwitcher.condition.video.maxSize="Maximum size:"
AdvSceneSwitcher.condition.video.selectArea="Select area"

View File

@ -154,12 +154,12 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="El patrón está resaltado
AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo"
AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar comprobación solo en el área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar comprobación solo en el área"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Tamaño mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamaño máximo:"
AdvSceneSwitcher.condition.video.selectArea="Seleccionar área"

View File

@ -257,14 +257,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="À quel poi
AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS"
AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scène"
AdvSceneSwitcher.condition.video.entry.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Vérifier le type de texte :{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"

View File

@ -379,16 +379,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="一致と
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="ソース"
AdvSceneSwitcher.condition.video.type.scene="シーン"
; AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="モデルデータ (そのカスケード分類子):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小近傍数:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}:{{throttleCount}}ミリ秒ごとにのみチェックを実行することでCPU負荷を軽減します"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="エリア内のみチェックを実施"
; AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="テキストの色の確認:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="テキストタイプの確認:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="言語の確認:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="カラーを確認してください:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.modelPath="モデルデータ (そのカスケード分類子):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="最小近傍数:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}:{{throttleCount}}ミリ秒ごとにのみチェックを実行することでCPU負荷を軽減します"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="エリア内のみチェックを実施"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="テキストの色の確認:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="テキストタイプの確認:{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="言語の確認:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="カラーを確認してください:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="最小サイズ:"
AdvSceneSwitcher.condition.video.maxSize="最大サイズ:"
AdvSceneSwitcher.condition.video.selectArea="範囲指定"

View File

@ -372,16 +372,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="Quão semel
AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS"
AdvSceneSwitcher.condition.video.type.source="Fonte"
AdvSceneSwitcher.condition.video.type.scene="Cena"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar verificação apenas na área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Verificar tipo de texto:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
AdvSceneSwitcher.condition.video.selectArea="Selecionar área"

View File

@ -139,10 +139,10 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{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.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum komşular: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.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"
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"

View File

@ -395,16 +395,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="颜色与
AdvSceneSwitcher.condition.video.type.main="OBS的主输出"
AdvSceneSwitcher.condition.video.type.source="源"
AdvSceneSwitcher.condition.video.type.scene="场景"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载."
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="仅在区域内执行检查"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="文本检查颜色:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="文本检查类型:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="语言检查:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="颜色检查:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.layout.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.layout.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载."
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="仅在区域内执行检查"
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.layout.ocrColorPick="文本检查颜色:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.layout.ocrTextType="文本检查类型:{{textType}}"
AdvSceneSwitcher.condition.video.layout.ocrLanguage="语言检查:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.color="颜色检查:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="最小尺寸:"
AdvSceneSwitcher.condition.video.maxSize="最大尺寸:"
AdvSceneSwitcher.condition.video.selectArea="选择区域"

View File

@ -6,6 +6,7 @@
#include <plugin-state-helpers.hpp>
#include <QBuffer>
#include <QColorDialog>
#include <QDesktopServices>
#include <QFileDialog>
#include <QMessageBox>
#include <QtGlobal>
@ -370,12 +371,16 @@ bool MacroConditionVideo::CheckOCR()
auto text = RunOCR(_ocrParameters.GetOCR(), _screenshotData.GetImage(),
_ocrParameters.color, _ocrParameters.colorThreshold);
SetVariableValue(text);
SetTempVarValue("text", text);
if (!text) {
return false;
}
SetVariableValue(*text);
SetTempVarValue("text", *text);
if (!_ocrParameters.regex.Enabled()) {
return text == std::string(_ocrParameters.text);
}
return _ocrParameters.regex.Matches(text, _ocrParameters.text);
return _ocrParameters.regex.Matches(*text, _ocrParameters.text);
}
bool MacroConditionVideo::CheckColor()
@ -520,7 +525,7 @@ BrightnessEdit::BrightnessEdit(QWidget *parent,
obs_module_text(
"AdvSceneSwitcher.condition.video.brightnessThresholdDescription"))),
_current(new QLabel),
_data(data)
_entryData(data)
{
auto layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
@ -538,7 +543,7 @@ BrightnessEdit::BrightnessEdit(QWidget *parent,
&BrightnessEdit::UpdateCurrentBrightness);
_timer.start(1000);
_threshold->SetDoubleValue(_data->_brightnessThreshold);
_threshold->SetDoubleValue(_entryData->_brightnessThreshold);
_loading = false;
}
@ -546,17 +551,34 @@ void BrightnessEdit::UpdateCurrentBrightness()
{
QString text = obs_module_text(
"AdvSceneSwitcher.condition.video.currentBrightness");
_current->setText(text.arg(_data->GetCurrentBrightness()));
_current->setText(text.arg(_entryData->GetCurrentBrightness()));
}
void BrightnessEdit::BrightnessThresholdChanged(const DoubleVariable &value)
{
if (_loading || !_data) {
return;
GUARD_LOADING_AND_LOCK();
_entryData->_brightnessThreshold = value;
}
static void openFileInEditor(const std::string &filepath)
{
const auto path = QString::fromStdString(filepath);
const QFileInfo fileInfo(path);
if (!fileInfo.exists()) {
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
DisplayMessage(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrOpenConfig.createFailed"));
return;
}
file.close();
}
auto lock = LockContext();
_data->_brightnessThreshold = value;
QUrl fileUrl = QUrl::fromLocalFile(path);
if (!QDesktopServices::openUrl(fileUrl)) {
DisplayMessage(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrOpenConfig.openFailed"));
}
}
OCREdit::OCREdit(QWidget *parent, PreviewDialog *previewDialog,
@ -577,11 +599,25 @@ OCREdit::OCREdit(QWidget *parent, PreviewDialog *previewDialog,
_pageSegMode(new QComboBox()),
_tesseractBaseDir(new FileSelection(FileSelection::Type::FOLDER)),
_languageCode(new VariableLineEdit(this)),
_useConfig(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrUseConfigFile"))),
_configFile(new FileSelection(FileSelection::Type::WRITE, this)),
_openConfigFile(new QPushButton(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrOpenConfigFile"))),
_reloadConfig(new QPushButton()),
_configLayout(new QHBoxLayout()),
_previewDialog(previewDialog),
_data(data)
_entryData(data)
{
populatePageSegModeSelection(_pageSegMode);
_reloadConfig->setMaximumWidth(22);
SetButtonIcon(_reloadConfig, GetThemeTypeName() == "Light"
? ":res/images/refresh.svg"
: "theme:Dark/refresh.svg");
_reloadConfig->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrConfigReload"));
QWidget::connect(_selectColor, SIGNAL(clicked()), this,
SLOT(SelectColorClicked()));
QWidget::connect(
@ -601,6 +637,29 @@ OCREdit::OCREdit(QWidget *parent, PreviewDialog *previewDialog,
SLOT(TesseractBaseDirChanged(const QString &)));
QWidget::connect(_languageCode, SIGNAL(editingFinished()), this,
SLOT(LanguageChanged()));
QWidget::connect(_useConfig, SIGNAL(stateChanged(int)), this,
SLOT(UseConfigChanged(int)));
QWidget::connect(_configFile, SIGNAL(PathChanged(const QString &)),
this, SLOT(ConfigFileChanged(const QString &)));
QWidget::connect(_openConfigFile, &QPushButton::clicked, [this](bool) {
openFileInEditor(
_entryData->_ocrParameters.GetCustomConfigFile());
});
QWidget::connect(_reloadConfig, &QPushButton::clicked, [this](bool) {
_entryData->_ocrParameters.EnableCustomConfig(true);
_previewDialog->OCRParametersChanged(
_entryData->_ocrParameters);
});
auto configFileHint = new QLabel();
const QString path = GetThemeTypeName() == "Light"
? ":/res/images/help.svg"
: ":/res/images/help_light.svg";
const QIcon icon(path);
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
configFileHint->setPixmap(pixmap);
configFileHint->setToolTip(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrConfigHint"));
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{textColor}}", _textColor},
@ -608,6 +667,10 @@ OCREdit::OCREdit(QWidget *parent, PreviewDialog *previewDialog,
{"{{textType}}", _pageSegMode},
{"{{tesseractBaseDir}}", _tesseractBaseDir},
{"{{languageCode}}", _languageCode},
{"{{configFile}}", _configFile},
{"{{openConfigFile}}", _openConfigFile},
{"{{reloadConfig}}", _reloadConfig},
{"{{configFileHint}}", configFileHint},
};
auto layout = new QVBoxLayout();
@ -620,39 +683,51 @@ OCREdit::OCREdit(QWidget *parent, PreviewDialog *previewDialog,
auto pageModeSegLayout = new QHBoxLayout();
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.orcTextType"),
"AdvSceneSwitcher.condition.video.layout.ocrTextType"),
pageModeSegLayout, widgetPlaceholders);
layout->addLayout(pageModeSegLayout);
auto baseDirLayout = new QHBoxLayout();
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.orcBaseDir"),
"AdvSceneSwitcher.condition.video.layout.ocrBaseDir"),
baseDirLayout, widgetPlaceholders, false);
layout->addLayout(baseDirLayout);
auto languageLayout = new QHBoxLayout();
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.orcLanguage"),
"AdvSceneSwitcher.condition.video.layout.ocrLanguage"),
languageLayout, widgetPlaceholders);
layout->addLayout(languageLayout);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.layout.ocrConfig"),
_configLayout, widgetPlaceholders, false);
layout->addWidget(_useConfig);
layout->addLayout(_configLayout);
auto colorPickLayout = new QHBoxLayout();
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.orcColorPick"),
"AdvSceneSwitcher.condition.video.layout.ocrColorPick"),
colorPickLayout, widgetPlaceholders);
layout->addLayout(colorPickLayout);
layout->addWidget(_colorThreshold);
setLayout(layout);
_matchText->setPlainText(_data->_ocrParameters.text);
_regex->SetRegexConfig(_data->_ocrParameters.regex);
SetupColorLabel(_data->_ocrParameters.color);
_colorThreshold->SetDoubleValue(_data->_ocrParameters.colorThreshold);
_matchText->setPlainText(_entryData->_ocrParameters.text);
_regex->SetRegexConfig(_entryData->_ocrParameters.regex);
SetupColorLabel(_entryData->_ocrParameters.color);
_colorThreshold->SetDoubleValue(
_entryData->_ocrParameters.colorThreshold);
_pageSegMode->setCurrentIndex(_pageSegMode->findData(
static_cast<int>(_data->_ocrParameters.GetPageMode())));
static_cast<int>(_entryData->_ocrParameters.GetPageMode())));
_tesseractBaseDir->SetPath(
_data->_ocrParameters.GetTesseractBasePath());
_languageCode->setText(_data->_ocrParameters.GetLanguageCode());
_entryData->_ocrParameters.GetTesseractBasePath());
_languageCode->setText(_entryData->_ocrParameters.GetLanguageCode());
_useConfig->setChecked(
_entryData->_ocrParameters.CustomConfigIsEnabled());
_configFile->SetPath(_entryData->_ocrParameters.GetCustomConfigFile());
SetLayoutVisible(_configLayout,
_entryData->_ocrParameters.CustomConfigIsEnabled());
_loading = false;
}
@ -665,12 +740,12 @@ void OCREdit::SetupColorLabel(const QColor &color)
void OCREdit::SelectColorClicked()
{
if (_loading || !_data) {
if (_loading || !_entryData) {
return;
}
const QColor color = QColorDialog::getColor(
_data->_ocrParameters.color, this,
_entryData->_ocrParameters.color, this,
obs_module_text("AdvSceneSwitcher.condition.video.selectColor"),
QColorDialog::ColorDialogOption());
@ -680,73 +755,54 @@ void OCREdit::SelectColorClicked()
SetupColorLabel(color);
auto lock = LockContext();
_data->_ocrParameters.color = color;
_entryData->_ocrParameters.color = color;
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::ColorThresholdChanged(const DoubleVariable &value)
{
if (_loading || !_data) {
return;
}
GUARD_LOADING_AND_LOCK();
_entryData->_ocrParameters.colorThreshold = value;
auto lock = LockContext();
_data->_ocrParameters.colorThreshold = value;
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::MatchTextChanged()
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_ocrParameters.text =
GUARD_LOADING_AND_LOCK();
_entryData->_ocrParameters.text =
_matchText->toPlainText().toUtf8().constData();
adjustSize();
updateGeometry();
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::RegexChanged(const RegexConfig &conf)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_ocrParameters.regex = conf;
GUARD_LOADING_AND_LOCK();
_entryData->_ocrParameters.regex = conf;
adjustSize();
updateGeometry();
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::PageSegModeChanged(int idx)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->SetPageSegMode(static_cast<tesseract::PageSegMode>(
GUARD_LOADING_AND_LOCK();
_entryData->SetPageSegMode(static_cast<tesseract::PageSegMode>(
_pageSegMode->itemData(idx).toInt()));
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::TesseractBaseDirChanged(const QString &path){
if (_loading || !_data) {
return;
}
auto lock = LockContext();
if (!_data->SetTesseractBaseDir(path.toStdString())) {
void OCREdit::TesseractBaseDirChanged(const QString &path)
{
GUARD_LOADING_AND_LOCK();
if (!_entryData->SetTesseractBaseDir(path.toStdString())) {
const QString message(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrLanguageNotFound"));
const QDir dataDir(path);
@ -755,34 +811,48 @@ void OCREdit::TesseractBaseDirChanged(const QString &path){
// Reset to previous value
const QSignalBlocker b(this);
_tesseractBaseDir->SetPath(_data->_ocrParameters.GetTesseractBasePath());
_tesseractBaseDir->SetPath(
_entryData->_ocrParameters.GetTesseractBasePath());
return;
}
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::LanguageChanged()
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
if (!_data->SetLanguageCode(_languageCode->text().toStdString())) {
GUARD_LOADING_AND_LOCK();
if (!_entryData->SetLanguageCode(_languageCode->text().toStdString())) {
const QString message(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrLanguageNotFound"));
const QDir dataDir(QString::fromStdString(
_data->_ocrParameters.GetTesseractBasePath()));
_entryData->_ocrParameters.GetTesseractBasePath()));
const QString fileName(_languageCode->text() + ".traineddata");
DisplayMessage(message.arg(fileName, dataDir.absolutePath()));
// Reset to previous value
const QSignalBlocker b(this);
_languageCode->setText(_data->_ocrParameters.GetLanguageCode());
_languageCode->setText(
_entryData->_ocrParameters.GetLanguageCode());
return;
}
_previewDialog->OCRParametersChanged(_data->_ocrParameters);
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::UseConfigChanged(int value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_ocrParameters.EnableCustomConfig(value);
SetLayoutVisible(_configLayout, value);
adjustSize();
updateGeometry();
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
void OCREdit::ConfigFileChanged(const QString &path)
{
GUARD_LOADING_AND_LOCK();
_entryData->_ocrParameters.SetCustomConfigFile(path.toStdString());
_previewDialog->OCRParametersChanged(_entryData->_ocrParameters);
}
ObjectDetectEdit::ObjectDetectEdit(
@ -802,7 +872,7 @@ ObjectDetectEdit::ObjectDetectEdit(
_minSize(new SizeSelection(0, 1024)),
_maxSize(new SizeSelection(0, 4096)),
_previewDialog(previewDialog),
_data(data)
_entryData(data)
{
_minNeighbors->setMinimum(minMinNeighbors);
_minNeighbors->setMaximum(maxMinNeighbors);
@ -833,14 +903,14 @@ ObjectDetectEdit::ObjectDetectEdit(
pathLayout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.modelPath"),
"AdvSceneSwitcher.condition.video.layout.modelPath"),
pathLayout, widgetPlaceholders);
auto neighborsLayout = new QHBoxLayout;
neighborsLayout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.minNeighbor"),
"AdvSceneSwitcher.condition.video.layout.minNeighbor"),
neighborsLayout, widgetPlaceholders);
auto sizeGrid = new QGridLayout;
@ -866,62 +936,50 @@ ObjectDetectEdit::ObjectDetectEdit(
layout->addLayout(sizeLayout);
setLayout(layout);
_modelDataPath->SetPath(_data->GetModelDataPath());
_modelDataPath->SetPath(_entryData->GetModelDataPath());
_objectScaleThreshold->SetDoubleValue(
_data->_objMatchParameters.scaleFactor);
_minNeighbors->setValue(_data->_objMatchParameters.minNeighbors);
_minSize->SetSize(_data->_objMatchParameters.minSize);
_maxSize->SetSize(_data->_objMatchParameters.maxSize);
_entryData->_objMatchParameters.scaleFactor);
_minNeighbors->setValue(_entryData->_objMatchParameters.minNeighbors);
_minSize->SetSize(_entryData->_objMatchParameters.minSize);
_maxSize->SetSize(_entryData->_objMatchParameters.maxSize);
_loading = false;
}
void ObjectDetectEdit::ObjectScaleThresholdChanged(const DoubleVariable &value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_objMatchParameters.scaleFactor = value;
_previewDialog->ObjDetectParametersChanged(_data->_objMatchParameters);
GUARD_LOADING_AND_LOCK();
_entryData->_objMatchParameters.scaleFactor = value;
_previewDialog->ObjDetectParametersChanged(
_entryData->_objMatchParameters);
}
void ObjectDetectEdit::MinNeighborsChanged(int value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_objMatchParameters.minNeighbors = value;
_previewDialog->ObjDetectParametersChanged(_data->_objMatchParameters);
GUARD_LOADING_AND_LOCK();
_entryData->_objMatchParameters.minNeighbors = value;
_previewDialog->ObjDetectParametersChanged(
_entryData->_objMatchParameters);
}
void ObjectDetectEdit::MinSizeChanged(advss::Size value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_objMatchParameters.minSize = value;
_previewDialog->ObjDetectParametersChanged(_data->_objMatchParameters);
GUARD_LOADING_AND_LOCK();
_entryData->_objMatchParameters.minSize = value;
_previewDialog->ObjDetectParametersChanged(
_entryData->_objMatchParameters);
}
void ObjectDetectEdit::MaxSizeChanged(advss::Size value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_objMatchParameters.maxSize = value;
_previewDialog->ObjDetectParametersChanged(_data->_objMatchParameters);
GUARD_LOADING_AND_LOCK();
_entryData->_objMatchParameters.maxSize = value;
_previewDialog->ObjDetectParametersChanged(
_entryData->_objMatchParameters);
}
void ObjectDetectEdit::ModelPathChanged(const QString &text)
{
if (_loading || !_data) {
if (_loading || !_entryData) {
return;
}
@ -929,13 +987,14 @@ void ObjectDetectEdit::ModelPathChanged(const QString &text)
{
auto lock = LockContext();
std::string path = text.toStdString();
dataLoaded = _data->LoadModelData(path);
dataLoaded = _entryData->LoadModelData(path);
}
if (!dataLoaded) {
DisplayMessage(obs_module_text(
"AdvSceneSwitcher.condition.video.modelLoadFail"));
}
_previewDialog->ObjDetectParametersChanged(_data->_objMatchParameters);
_previewDialog->ObjDetectParametersChanged(
_entryData->_objMatchParameters);
}
ColorEdit::ColorEdit(QWidget *parent,
@ -958,7 +1017,7 @@ ColorEdit::ColorEdit(QWidget *parent,
_color(new QLabel),
_selectColor(new QPushButton(obs_module_text(
"AdvSceneSwitcher.condition.video.selectColor"))),
_data(data)
_entryData(data)
{
QWidget::connect(_selectColor, SIGNAL(clicked()), this,
SLOT(SelectColorClicked()));
@ -979,9 +1038,9 @@ ColorEdit::ColorEdit(QWidget *parent,
};
auto colorLayout = new QHBoxLayout;
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.condition.video.entry.color"),
colorLayout, widgetPlaceholders);
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.condition.video.layout.color"),
colorLayout, widgetPlaceholders);
auto layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0);
@ -990,9 +1049,11 @@ ColorEdit::ColorEdit(QWidget *parent,
layout->addWidget(_matchThreshold);
setLayout(layout);
_matchThreshold->SetDoubleValue(_data->_colorParameters.matchThreshold);
_colorThreshold->SetDoubleValue(_data->_colorParameters.colorThreshold);
SetupColorLabel(_data->_colorParameters.color);
_matchThreshold->SetDoubleValue(
_entryData->_colorParameters.matchThreshold);
_colorThreshold->SetDoubleValue(
_entryData->_colorParameters.colorThreshold);
SetupColorLabel(_entryData->_colorParameters.color);
_loading = false;
}
@ -1005,32 +1066,24 @@ void ColorEdit::SetupColorLabel(const QColor &color)
void ColorEdit::MatchThresholdChanged(const DoubleVariable &value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_colorParameters.matchThreshold = value;
GUARD_LOADING_AND_LOCK();
_entryData->_colorParameters.matchThreshold = value;
}
void ColorEdit::ColorThresholdChanged(const DoubleVariable &value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_colorParameters.colorThreshold = value;
GUARD_LOADING_AND_LOCK();
_entryData->_colorParameters.colorThreshold = value;
}
void ColorEdit::SelectColorClicked()
{
if (_loading || !_data) {
if (_loading || !_entryData) {
return;
}
const QColor color = QColorDialog::getColor(
_data->_colorParameters.color, this,
_entryData->_colorParameters.color, this,
obs_module_text("AdvSceneSwitcher.condition.video.selectColor"),
QColorDialog::ColorDialogOption());
@ -1040,19 +1093,19 @@ void ColorEdit::SelectColorClicked()
SetupColorLabel(color);
auto lock = LockContext();
_data->_colorParameters.color = color;
_entryData->_colorParameters.color = color;
}
AreaEdit::AreaEdit(QWidget *parent, PreviewDialog *previewDialog,
const std::shared_ptr<MacroConditionVideo> &data)
: QWidget(parent),
_checkAreaEnable(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.video.entry.checkAreaEnable"))),
"AdvSceneSwitcher.condition.video.layout.checkAreaEnable"))),
_checkArea(new AreaSelection(0, 99999)),
_selectArea(new QPushButton(obs_module_text(
"AdvSceneSwitcher.condition.video.selectArea"))),
_previewDialog(previewDialog),
_data(data)
_entryData(data)
{
QWidget::connect(_checkAreaEnable, SIGNAL(stateChanged(int)), this,
SLOT(CheckAreaEnableChanged(int)));
@ -1073,20 +1126,20 @@ AreaEdit::AreaEdit(QWidget *parent, PreviewDialog *previewDialog,
layout->setContentsMargins(0, 0, 0, 0);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.entry.checkArea"),
"AdvSceneSwitcher.condition.video.layout.checkArea"),
layout, widgetPlaceholders);
setLayout(layout);
_checkAreaEnable->setChecked(_data->_areaParameters.enable);
_checkArea->SetArea(_data->_areaParameters.area);
_checkAreaEnable->setChecked(_entryData->_areaParameters.enable);
_checkArea->SetArea(_entryData->_areaParameters.area);
SetWidgetVisibility();
_loading = false;
}
void AreaEdit::SetWidgetVisibility()
{
_checkArea->setVisible(_data->_areaParameters.enable);
_selectArea->setVisible(_data->_areaParameters.enable);
_checkArea->setVisible(_entryData->_areaParameters.enable);
_selectArea->setVisible(_entryData->_areaParameters.enable);
adjustSize();
updateGeometry();
}
@ -1101,26 +1154,18 @@ void AreaEdit::SelectAreaClicked()
void AreaEdit::CheckAreaEnableChanged(int value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_areaParameters.enable = value;
GUARD_LOADING_AND_LOCK();
_entryData->_areaParameters.enable = value;
SetWidgetVisibility();
_previewDialog->AreaParametersChanged(_data->_areaParameters);
_previewDialog->AreaParametersChanged(_entryData->_areaParameters);
emit Resized();
}
void AreaEdit::CheckAreaChanged(Area value)
{
if (_loading || !_data) {
return;
}
auto lock = LockContext();
_data->_areaParameters.area = value;
_previewDialog->AreaParametersChanged(_data->_areaParameters);
GUARD_LOADING_AND_LOCK();
_entryData->_areaParameters.area = value;
_previewDialog->AreaParametersChanged(_entryData->_areaParameters);
}
void AreaEdit::CheckAreaChanged(QRect rect)
@ -1261,15 +1306,16 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
{"{{throttleCount}}", _throttleCount},
{"{{patternMatchingModes}}", _patternMatchMode},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.video.entry"),
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.video.layout"),
entryLine1Layout, widgetPlaceholders);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchMode"),
_patternMatchModeLayout, widgetPlaceholders);
PlaceWidgets(obs_module_text(
"AdvSceneSwitcher.condition.video.entry.throttle"),
_throttleControlLayout, widgetPlaceholders);
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.condition.video.layout.throttle"),
_throttleControlLayout, widgetPlaceholders);
QHBoxLayout *showMatchLayout = new QHBoxLayout;
showMatchLayout->addWidget(_showMatch);
@ -1323,33 +1369,21 @@ void MacroConditionVideoEdit::UpdatePreviewTooltip()
void MacroConditionVideoEdit::SourceChanged(const SourceSelection &source)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
GUARD_LOADING_AND_LOCK();
_entryData->_video.source = source;
HandleVideoInputUpdate();
}
void MacroConditionVideoEdit::SceneChanged(const SceneSelection &scene)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
GUARD_LOADING_AND_LOCK();
_entryData->_video.scene = scene;
HandleVideoInputUpdate();
}
void MacroConditionVideoEdit::VideoInputTypeChanged(int type)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
GUARD_LOADING_AND_LOCK();
_entryData->_video.type = static_cast<VideoInput::Type>(type);
HandleVideoInputUpdate();
SetWidgetVisibility();
@ -1365,11 +1399,7 @@ void MacroConditionVideoEdit::HandleVideoInputUpdate()
void MacroConditionVideoEdit::ConditionChanged(int idx)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
GUARD_LOADING_AND_LOCK();
_entryData->SetCondition(
static_cast<VideoCondition>(_condition->itemData(idx).toInt()));
_entryData->ResetLastMatch();
@ -1397,11 +1427,7 @@ void MacroConditionVideoEdit::ConditionChanged(int idx)
void MacroConditionVideoEdit::ImagePathChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
GUARD_LOADING_AND_LOCK();
_entryData->_file = text.toUtf8().constData();
_entryData->ResetLastMatch();
if (_entryData->LoadImageFromFile()) {

View File

@ -128,7 +128,7 @@ private:
QLabel *_current;
QTimer _timer;
std::shared_ptr<MacroConditionVideo> _data;
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};
@ -147,6 +147,8 @@ private slots:
void PageSegModeChanged(int);
void TesseractBaseDirChanged(const QString &);
void LanguageChanged();
void UseConfigChanged(int);
void ConfigFileChanged(const QString &);
private:
void SetupColorLabel(const QColor &);
@ -159,10 +161,15 @@ private:
QComboBox *_pageSegMode;
FileSelection *_tesseractBaseDir;
VariableLineEdit *_languageCode;
QCheckBox *_useConfig;
FileSelection *_configFile;
QPushButton *_openConfigFile;
QPushButton *_reloadConfig;
QHBoxLayout *_configLayout;
PreviewDialog *_previewDialog;
std::shared_ptr<MacroConditionVideo> _data;
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};
@ -190,7 +197,7 @@ private:
PreviewDialog *_previewDialog;
std::shared_ptr<MacroConditionVideo> _data;
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};
@ -214,7 +221,7 @@ private:
QLabel *_color;
QPushButton *_selectColor;
std::shared_ptr<MacroConditionVideo> _data;
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};
@ -243,7 +250,7 @@ private:
PreviewDialog *_previewDialog;
std::shared_ptr<MacroConditionVideo> _data;
std::shared_ptr<MacroConditionVideo> _entryData;
bool _loading = true;
};

View File

@ -202,14 +202,15 @@ cv::Mat PreprocessForOCR(const QImage &image, const QColor &textColor,
return result;
}
std::string RunOCR(tesseract::TessBaseAPI *ocr, const QImage &image,
const QColor &color, double colorDiff)
std::optional<std::string> RunOCR(tesseract::TessBaseAPI *ocr,
const QImage &image, const QColor &color,
double colorDiff)
{
(void)ocr;
(void)color;
(void)colorDiff;
if (image.isNull()) {
return "";
return {};
}
#ifdef OCR_SUPPORT
@ -221,12 +222,12 @@ std::string RunOCR(tesseract::TessBaseAPI *ocr, const QImage &image,
std::unique_ptr<char[]> detectedText(ocr->GetUTF8Text());
if (!detectedText) {
return "";
return {};
}
return detectedText.get();
#else
return "";
return {};
#endif
}

View File

@ -27,10 +27,23 @@ enum PageSegMode {
PSM_COUNT
};
enum OcrEngineMode {
OEM_TESSERACT_ONLY,
OEM_LSTM_ONLY,
OEM_TESSERACT_LSTM_COMBINED,
OEM_DEFAULT,
OEM_COUNT // Number of OEMs
};
class TessBaseAPI {
public:
void SetPageSegMode(PageSegMode) {}
int Init(const char *, const char *) { return 0; }
int Init(const char *, const char *, OcrEngineMode, char **, int,
const std::vector<std::string> *,
const std::vector<std::string> *, bool)
{
return 0;
}
void End() {}
};
} // namespace tesseract
@ -62,8 +75,8 @@ std::vector<cv::Rect> MatchObject(QImage &img, cv::CascadeClassifier &cascade,
uchar GetAvgBrightness(QImage &img);
cv::Mat PreprocessForOCR(const QImage &image, const QColor &color,
double colorDiff);
std::string RunOCR(tesseract::TessBaseAPI *, const QImage &, const QColor &,
double colorDiff);
std::optional<std::string> RunOCR(tesseract::TessBaseAPI *, const QImage &,
const QColor &, double colorDiff);
bool ContainsPixelsInColorRange(const QImage &image, const QColor &color,
double colorDeviationThreshold,
double totalPixelMatchThreshold);

View File

@ -1,4 +1,5 @@
#include "parameter-wrappers.hpp"
#include "log-helper.hpp"
#include <QFileInfo>
#include <source-helpers.hpp>
@ -253,14 +254,13 @@ OCRParameters::OCRParameters(const OCRParameters &other)
colorThreshold(other.colorThreshold),
pageSegMode(other.pageSegMode),
tesseractBasePath(other.tesseractBasePath),
languageCode(other.languageCode)
languageCode(other.languageCode),
useConfig(other.useConfig),
configFile(other.configFile)
{
if (!initDone) {
Setup();
}
if (initDone) {
ocr->SetPageSegMode(pageSegMode);
}
}
OCRParameters &OCRParameters::operator=(const OCRParameters &other)
@ -272,12 +272,11 @@ OCRParameters &OCRParameters::operator=(const OCRParameters &other)
pageSegMode = other.pageSegMode;
tesseractBasePath = other.tesseractBasePath;
languageCode = other.languageCode;
useConfig = other.useConfig;
configFile = other.configFile;
if (!initDone) {
Setup();
}
if (initDone) {
ocr->SetPageSegMode(pageSegMode);
}
return *this;
}
@ -288,6 +287,8 @@ bool OCRParameters::Save(obs_data_t *obj) const
regex.Save(data);
tesseractBasePath.Save(data, "tesseractBasePath");
languageCode.Save(data, "language");
obs_data_set_bool(data, "useConfig", useConfig);
obs_data_set_string(data, "configFile", configFile.c_str());
SaveColor(data, "textColor", color);
colorThreshold.Save(data, "colorThreshold");
obs_data_set_int(data, "pageSegMode", static_cast<int>(pageSegMode));
@ -311,6 +312,8 @@ bool OCRParameters::Load(obs_data_t *obj)
obs_current_module())) +
"/res/ocr/";
}
useConfig = obs_data_get_bool(data, "useConfig");
configFile = obs_data_get_string(data, "configFile");
color = LoadColor(data, "textColor");
if (obs_data_has_user_value(data, "version")) {
@ -320,9 +323,6 @@ bool OCRParameters::Load(obs_data_t *obj)
obs_data_get_int(data, "pageSegMode"));
obs_data_release(data);
if (initDone) {
ocr->SetPageSegMode(pageSegMode);
}
Setup();
return true;
}
@ -330,7 +330,9 @@ bool OCRParameters::Load(obs_data_t *obj)
void OCRParameters::SetPageMode(tesseract::PageSegMode mode)
{
pageSegMode = mode;
ocr->SetPageSegMode(mode);
if (ocr) {
ocr->SetPageSegMode(mode);
}
}
bool OCRParameters::SetLanguageCode(const std::string &value)
@ -343,7 +345,6 @@ bool OCRParameters::SetLanguageCode(const std::string &value)
}
languageCode = value;
Setup();
ocr->SetPageSegMode(pageSegMode);
return true;
}
@ -363,7 +364,6 @@ bool OCRParameters::SetTesseractBasePath(const std::string &value)
}
tesseractBasePath = value;
Setup();
ocr->SetPageSegMode(pageSegMode);
return true;
}
@ -372,6 +372,18 @@ std::string OCRParameters::GetTesseractBasePath() const
return tesseractBasePath;
}
void OCRParameters::EnableCustomConfig(bool enable)
{
useConfig = enable;
Setup();
}
void OCRParameters::SetCustomConfigFile(const std::string &filename)
{
configFile = filename;
Setup();
}
void OCRParameters::Setup()
{
ocr = std::make_unique<tesseract::TessBaseAPI>();
@ -383,18 +395,41 @@ void OCRParameters::Setup()
const std::string dataPath = std::string(tesseractBasePath) + "/";
const std::string modelFile =
std::string(languageCode) + ".traineddata";
const auto fullPath = QString::fromStdString(dataPath) +
QString::fromStdString(modelFile);
QFileInfo fileInfo(fullPath);
if (!fileInfo.exists(fullPath)) {
const auto modelFullPath = QString::fromStdString(dataPath) +
QString::fromStdString(modelFile);
QFileInfo modelFileInfo(modelFullPath);
if (!modelFileInfo.exists(modelFullPath)) {
initDone = false;
blog(LOG_WARNING,
"cannot init tesseract! Model path does not exists: %s",
modelFileInfo.absoluteFilePath().toStdString().c_str());
return;
}
auto configPath = QString::fromStdString(configFile);
QFileInfo configFileInfo(configPath);
bool configFileExists = configFileInfo.exists(configPath);
bool setupWithConfig = useConfig;
if (useConfig && !configFileExists) {
blog(LOG_WARNING,
"tesseract config file will be ignored! File does not exists: %s",
configFileInfo.absoluteFilePath().toStdString().c_str());
setupWithConfig = false;
}
char *configs[] = {configFile.data()};
if (ocr->Init(dataPath.c_str(), languageCode.c_str(),
tesseract::OEM_DEFAULT,
setupWithConfig ? configs : nullptr,
setupWithConfig ? 1 : 0, nullptr, nullptr, false) != 0) {
blog(LOG_WARNING, "tesseract init failed!");
initDone = false;
return;
}
if (ocr->Init(dataPath.c_str(), languageCode.c_str()) != 0) {
initDone = false;
return;
}
ocr->SetPageSegMode(pageSegMode);
initDone = true;
}

View File

@ -95,6 +95,10 @@ public:
std::string GetLanguageCode() const;
bool SetTesseractBasePath(const std::string &);
std::string GetTesseractBasePath() const;
void EnableCustomConfig(bool enable);
bool CustomConfigIsEnabled() const { return useConfig; }
void SetCustomConfigFile(const std::string &);
std::string GetCustomConfigFile() const { return configFile; }
tesseract::PageSegMode GetPageMode() const { return pageSegMode; }
tesseract::TessBaseAPI *GetOCR() const { return ocr.get(); }
@ -111,6 +115,8 @@ private:
obs_get_module_data_path(obs_current_module()) +
std::string("/res/ocr");
StringVariable languageCode = "eng";
bool useConfig = false;
std::string configFile = "config.txt";
std::unique_ptr<tesseract::TessBaseAPI> ocr;
bool initDone = false;
};

View File

@ -353,9 +353,15 @@ void PreviewImage::MarkMatch(QImage &screenshot,
} else if (condition == VideoCondition::OCR) {
auto text = RunOCR(ocrParams.GetOCR(), screenshot,
ocrParams.color, ocrParams.colorThreshold);
if (!text) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrMatchFail"));
}
QString status(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrMatchSuccess"));
emit StatusUpdate(status.arg(QString::fromStdString(text)));
emit StatusUpdate(status.arg(QString::fromStdString(*text)));
}
}