Rework preview dialog to improve performance

Object detection and OCR models were constantly being re-initialized
each frame due to copy in the signal / slot handling
This commit is contained in:
WarmUpTill 2025-05-23 20:23:22 +02:00 committed by WarmUpTill
parent 32d29875ed
commit 721a786e79
2 changed files with 109 additions and 67 deletions

View File

@ -134,13 +134,13 @@ void PreviewDialog::PatternMatchParametersChanged(
void PreviewDialog::ObjDetectParametersChanged(const ObjDetectParameters &params) void PreviewDialog::ObjDetectParametersChanged(const ObjDetectParameters &params)
{ {
std::unique_lock<std::mutex> lock(_mtx); std::unique_lock<std::mutex> lock(_mtx);
_objDetectParams = params; _objDetectParams = std::make_shared<ObjDetectParameters>(params);
} }
void PreviewDialog::OCRParametersChanged(const OCRParameters &params) void PreviewDialog::OCRParametersChanged(const OCRParameters &params)
{ {
std::unique_lock<std::mutex> lock(_mtx); std::unique_lock<std::mutex> lock(_mtx);
_ocrParams = params; _ocrParams = std::make_shared<OCRParameters>(params);
} }
void PreviewDialog::VideoSelectionChanged(const VideoInput &video) void PreviewDialog::VideoSelectionChanged(const VideoInput &video)
@ -262,13 +262,13 @@ static void markObjects(QImage &image, std::vector<cv::Rect> &objects)
PreviewImage::PreviewImage(std::mutex &mtx) : _mtx(mtx) {} PreviewImage::PreviewImage(std::mutex &mtx) : _mtx(mtx) {}
void PreviewImage::CreateImage(const VideoInput &video, PreviewType type, void PreviewImage::CreateImage(
const PatternMatchParameters &patternMatchParams, const VideoInput &video, PreviewType type,
const PatternImageData &patternImageData, const PatternMatchParameters &patternMatchParams,
ObjDetectParameters objDetectParams, const PatternImageData &patternImageData,
OCRParameters ocrParams, std::shared_ptr<ObjDetectParameters> objDetectParams,
const AreaParameters &areaParams, std::shared_ptr<OCRParameters> ocrParams,
VideoCondition condition) const AreaParameters &areaParams, VideoCondition condition)
{ {
auto source = obs_weak_source_get_source(video.GetVideo()); auto source = obs_weak_source_get_source(video.GetVideo());
QRect screenshotArea; QRect screenshotArea;
@ -308,61 +308,94 @@ void PreviewImage::CreateImage(const VideoInput &video, PreviewType type,
emit ImageReady(QPixmap::fromImage(screenshot.GetImage())); emit ImageReady(QPixmap::fromImage(screenshot.GetImage()));
} }
void PreviewImage::MarkMatch(QImage &screenshot, void PreviewImage::MarkMatch(
const PatternMatchParameters &patternMatchParams, QImage &screenshot, const PatternMatchParameters &patternMatchParams,
const PatternImageData &patternImageData, const PatternImageData &patternImageData,
ObjDetectParameters &objDetectParams, std::shared_ptr<ObjDetectParameters> objDetectParams,
const OCRParameters &ocrParams, std::shared_ptr<OCRParameters> ocrParams, VideoCondition condition)
VideoCondition condition)
{ {
if (condition == VideoCondition::PATTERN) { if (condition == VideoCondition::PATTERN) {
cv::Mat result; MarkPatternMatch(screenshot, patternMatchParams,
double matchValue = patternImageData);
std::numeric_limits<double>::signaling_NaN();
MatchPattern(screenshot, patternImageData,
patternMatchParams.threshold, result, &matchValue,
patternMatchParams.useAlphaAsMask,
patternMatchParams.matchMode);
emit ValueUpdate(matchValue);
if (result.total() == 0 || countNonZero(result) == 0) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchFail"));
} else if (result.cols == 1 && result.rows == 1) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage"));
} else {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchSuccess"));
markPatterns(result, screenshot,
patternImageData.rgbaPattern);
}
} else if (condition == VideoCondition::OBJECT) { } else if (condition == VideoCondition::OBJECT) {
auto objects = MatchObject(screenshot, objDetectParams.cascade, MarkObjectMatch(screenshot, objDetectParams);
objDetectParams.scaleFactor,
objDetectParams.minNeighbors,
objDetectParams.minSize.CV(),
objDetectParams.maxSize.CV());
if (objects.empty()) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchFail"));
} else {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchSuccess"));
markObjects(screenshot, objects);
}
} else if (condition == VideoCondition::OCR) { } else if (condition == VideoCondition::OCR) {
auto text = RunOCR(ocrParams.GetOCR(), screenshot, MarkOCRMatch(screenshot, ocrParams);
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)));
} }
} }
void PreviewImage::MarkPatternMatch(
QImage &screenshot, const PatternMatchParameters &patternMatchParams,
const PatternImageData &patternImageData)
{
cv::Mat result;
double matchValue = std::numeric_limits<double>::signaling_NaN();
MatchPattern(screenshot, patternImageData, patternMatchParams.threshold,
result, &matchValue, patternMatchParams.useAlphaAsMask,
patternMatchParams.matchMode);
emit ValueUpdate(matchValue);
if (result.total() == 0 || countNonZero(result) == 0) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchFail"));
} else if (result.cols == 1 && result.rows == 1) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage"));
} else {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.patternMatchSuccess"));
markPatterns(result, screenshot, patternImageData.rgbaPattern);
}
}
void PreviewImage::MarkObjectMatch(
QImage &screenshot,
const std::shared_ptr<ObjDetectParameters> &objDetectParams)
{
if (!objDetectParams) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchFail"));
return;
}
auto model = objDetectParams->GetModel();
if (!model) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchFail"));
return;
}
auto objects = MatchObject(screenshot, *model,
objDetectParams->scaleFactor,
objDetectParams->minNeighbors,
objDetectParams->minSize.CV(),
objDetectParams->maxSize.CV());
if (objects.empty()) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchFail"));
} else {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.objectMatchSuccess"));
markObjects(screenshot, objects);
}
}
void PreviewImage::MarkOCRMatch(QImage &screenshot,
const std::shared_ptr<OCRParameters> &ocrParams)
{
if (!ocrParams) {
emit StatusUpdate(obs_module_text(
"AdvSceneSwitcher.condition.video.ocrMatchFail"));
return;
}
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)));
}
} // namespace advss } // namespace advss

View File

@ -26,8 +26,10 @@ public:
public slots: public slots:
void CreateImage(const VideoInput &, PreviewType, void CreateImage(const VideoInput &, PreviewType,
const PatternMatchParameters &, const PatternMatchParameters &,
const PatternImageData &, ObjDetectParameters, const PatternImageData &,
OCRParameters, const AreaParameters &, VideoCondition); std::shared_ptr<ObjDetectParameters>,
std::shared_ptr<OCRParameters>, const AreaParameters &,
VideoCondition);
signals: signals:
void ImageReady(const QPixmap &); void ImageReady(const QPixmap &);
void ValueUpdate(double); void ValueUpdate(double);
@ -35,8 +37,14 @@ signals:
private: private:
void MarkMatch(QImage &screenshot, const PatternMatchParameters &, void MarkMatch(QImage &screenshot, const PatternMatchParameters &,
const PatternImageData &, ObjDetectParameters &, const PatternImageData &,
const OCRParameters &, VideoCondition); std::shared_ptr<ObjDetectParameters>,
std::shared_ptr<OCRParameters>, VideoCondition);
void MarkPatternMatch(QImage &, const PatternMatchParameters &,
const PatternImageData &);
void MarkObjectMatch(QImage &,
const std::shared_ptr<ObjDetectParameters> &);
void MarkOCRMatch(QImage &, const std::shared_ptr<OCRParameters> &);
std::mutex &_mtx; std::mutex &_mtx;
}; };
@ -67,8 +75,9 @@ signals:
void SelectionAreaChanged(QRect area); void SelectionAreaChanged(QRect area);
void NeedImage(const VideoInput &, PreviewType, void NeedImage(const VideoInput &, PreviewType,
const PatternMatchParameters &, const PatternImageData &, const PatternMatchParameters &, const PatternImageData &,
ObjDetectParameters, OCRParameters, std::shared_ptr<ObjDetectParameters>,
const AreaParameters &, VideoCondition); std::shared_ptr<OCRParameters>, const AreaParameters &,
VideoCondition);
private: private:
void Start(); void Start();
@ -81,8 +90,8 @@ private:
VideoInput _video; VideoInput _video;
PatternMatchParameters _patternMatchParams; PatternMatchParameters _patternMatchParams;
PatternImageData _patternImageData; PatternImageData _patternImageData;
ObjDetectParameters _objDetectParams; std::shared_ptr<ObjDetectParameters> _objDetectParams;
OCRParameters _ocrParams; std::shared_ptr<OCRParameters> _ocrParams;
AreaParameters _areaParams; AreaParameters _areaParams;
VideoCondition _condition = VideoCondition::PATTERN; VideoCondition _condition = VideoCondition::PATTERN;