From b597d0d1c1dd583a76b130ab6ed2b3f665d23b70 Mon Sep 17 00:00:00 2001 From: Status102 <102887808+status102@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:40:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ProcessTask=E4=BB=BB=E5=8A=A1=E5=91=BD?= =?UTF-8?q?=E4=B8=AD=E7=BC=93=E5=AD=98=E7=BB=93=E6=9E=9C=20(#12651)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: ProcessTask任务命中缓存结果 * perf: 加个函数 * perf: 合并直接截图 * feat: 增加匹配模板及文字 * fix: win * fix: ptr check * fix: template func * fix: type * fix: import * fix: empty * perf: early retrun * perf: shared image * fix: import --- src/MaaCore/Common/AsstTypes.h | 79 ++++++++++++++++--- src/MaaCore/Config/Miscellaneous/OcrPack.cpp | 7 +- src/MaaCore/Task/AbstractTaskPlugin.cpp | 13 +++ src/MaaCore/Task/AbstractTaskPlugin.h | 23 ++++++ src/MaaCore/Task/ProcessTask.cpp | 25 ++++-- src/MaaCore/Task/ProcessTask.h | 6 +- src/MaaCore/Vision/FeatureMatcher.cpp | 2 +- .../Miscellaneous/OperBoxImageAnalyzer.cpp | 6 +- src/MaaCore/Vision/TemplDetOCRer.h | 9 +++ 9 files changed, 139 insertions(+), 31 deletions(-) diff --git a/src/MaaCore/Common/AsstTypes.h b/src/MaaCore/Common/AsstTypes.h index a2185aa7d8..1042e13aa2 100644 --- a/src/MaaCore/Common/AsstTypes.h +++ b/src/MaaCore/Common/AsstTypes.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include "Utils/StringMisc.hpp" +#include "meojson/json.hpp" #ifndef NOMINMAX #define NOMINMAX @@ -259,36 +261,91 @@ inline constexpr To make_rect(const From& rect) return To { rect.x, rect.y, rect.width, rect.height }; } -struct TextRect +struct AnalyzerResult { - std::string to_string() const - { - return "{ " + text + ": " + rect.to_string() + ", score: " + std::to_string(score) + " }"; - } + virtual ~AnalyzerResult() = default; + + virtual std::string to_string() const { return {}; }; explicit operator std::string() const { return to_string(); } + virtual json::object to_json() const { return {}; }; + + explicit operator json::object() const { return to_json(); } +}; + +struct TextRect : public AnalyzerResult +{ + TextRect() = default; + + TextRect(Rect r, double s, std::string t) : + rect(r), + score(s), + text(std::move(t)) + { + } + + std::string to_string() const override + { + return std::format("{{ rect: {}, score: {}, text: {} }}", rect.to_string(), score, text); + } + + json::object to_json() const override + { + return { { "rect", json::array { rect.x, rect.y, rect.width, rect.height } }, + { "score", score }, + { "text", text } }; + } + Rect rect; double score = 0.0; std::string text; }; -struct MatchRect +struct MatchRect : public AnalyzerResult { - std::string to_string() const { return "{ rect: " + rect.to_string() + ", score: " + std::to_string(score) + " }"; } + MatchRect() = default; - explicit operator std::string() const { return to_string(); } + MatchRect(Rect r, double s, std::string t) : + rect(r), + score(s), + templ_name(std::move(t)) + { + } + + std::string to_string() const override + { + return std::format("{{ rect: {}, score: {}, template: {} }}", rect.to_string(), score, templ_name); + } + + json::object to_json() const override + { + return { { "rect", json::array { rect.x, rect.y, rect.width, rect.height } }, + { "score", score }, + { "template", templ_name } }; + } Rect rect; double score = 0.0; std::string templ_name; }; -struct FeatureMatchRect +struct FeatureMatchRect : public AnalyzerResult { - std::string to_string() const { return "{ rect: " + rect.to_string() + ", count: " + std::to_string(count) + " }"; } + FeatureMatchRect() = default; - explicit operator std::string() const { return to_string(); } + FeatureMatchRect(Rect r, int c) : + rect(r), + count(c) + { + } + + std::string to_string() const override { return std::format("{{ rect: {}, count: {} }}", rect.to_string(), count); } + + json::object to_json() const override + { + return { { "rect", json::array { rect.x, rect.y, rect.width, rect.height } }, { "count", count } }; + } Rect rect; int count = 0; diff --git a/src/MaaCore/Config/Miscellaneous/OcrPack.cpp b/src/MaaCore/Config/Miscellaneous/OcrPack.cpp index d245b25354..b27275d6e0 100644 --- a/src/MaaCore/Config/Miscellaneous/OcrPack.cpp +++ b/src/MaaCore/Config/Miscellaneous/OcrPack.cpp @@ -120,12 +120,7 @@ asst::OcrPack::ResultsVec asst::OcrPack::recognize(const cv::Mat& image, bool wi #ifdef ASST_DEBUG cv::rectangle(draw, make_rect(det_rect), cv::Scalar(0, 0, 255), 2); #endif - Result result { - .rect = det_rect, - .score = ocr_result.rec_scores.at(i), - .text = std::move(ocr_result.text.at(i)), - }; - raw_results.emplace_back(std::move(result)); + raw_results.emplace_back(Result(det_rect, ocr_result.rec_scores.at(i), std::move(ocr_result.text.at(i)))); } auto costs = diff --git a/src/MaaCore/Task/AbstractTaskPlugin.cpp b/src/MaaCore/Task/AbstractTaskPlugin.cpp index 0926202134..6545e9c9d1 100644 --- a/src/MaaCore/Task/AbstractTaskPlugin.cpp +++ b/src/MaaCore/Task/AbstractTaskPlugin.cpp @@ -1,5 +1,7 @@ #include "AbstractTaskPlugin.h" +#include "Controller/Controller.h" + int asst::AbstractTaskPlugin::priority() const { return m_priority; @@ -34,3 +36,14 @@ bool asst::AbstractTaskPlugin::operator==(const AbstractTaskPlugin& rhs) const { return priority() == rhs.priority(); } + +std::shared_ptr asst::AbstractTaskPlugin::get_hit_image() const +{ + if (auto ptr = dynamic_cast(m_task_ptr); !ptr) { + return nullptr; + } + else if (auto last_hit = ptr->get_last_hit(); last_hit && last_hit->image && !last_hit->image->empty()) { + return last_hit->image; + } + return nullptr; +} diff --git a/src/MaaCore/Task/AbstractTaskPlugin.h b/src/MaaCore/Task/AbstractTaskPlugin.h index 0b517b47a4..74da047220 100644 --- a/src/MaaCore/Task/AbstractTaskPlugin.h +++ b/src/MaaCore/Task/AbstractTaskPlugin.h @@ -4,6 +4,10 @@ #include "AbstractTask.h" #include "Common/AsstMsg.h" +#include "Common/AsstTypes.h" +#include "MaaUtils/NoWarningCVMat.hpp" +#include "ProcessTask.h" +#include "Utils/Logger.hpp" namespace asst { @@ -27,6 +31,25 @@ public: bool operator==(const AbstractTaskPlugin& rhs) const; protected: + std::shared_ptr get_hit_image() const; + + template + requires std::derived_from + std::shared_ptr get_hit_detail() const + { + if (auto ptr = dynamic_cast(m_task_ptr); !ptr) { + return nullptr; + } + else if (auto last_hit = ptr->get_last_hit(); !last_hit || !last_hit->reco_detail) { + return nullptr; + } + else if (auto detail = std::dynamic_pointer_cast(last_hit->reco_detail)) { + return detail; + } + Log.error(__FUNCTION__, "| Unable to get hit detail of type:", typeid(T).name()); + return nullptr; + } + AbstractTask* m_task_ptr = nullptr; int m_priority = 0; bool m_block = false; diff --git a/src/MaaCore/Task/ProcessTask.cpp b/src/MaaCore/Task/ProcessTask.cpp index cfac8b10ad..0d254a7003 100644 --- a/src/MaaCore/Task/ProcessTask.cpp +++ b/src/MaaCore/Task/ProcessTask.cpp @@ -157,29 +157,36 @@ ProcessTask::HitDetail ProcessTask::find_first(const TaskList& list) /* const, e auto res_opt = analyzer.analyze(); if (!res_opt) { - return { .task_ptr = nullptr }; + return { .image = std::make_shared(std::move(image)), .task_ptr = nullptr }; } task_ptr = std::move(res_opt->task_ptr); if (task_ptr->algorithm == AlgorithmType::MatchTemplate) { auto& raw_result = std::get(res_opt->result); - return { .rect = res_opt->rect, .reco_detail = { { "score", raw_result.score } }, .task_ptr = task_ptr }; + return { .image = std::make_shared(std::move(image)), + .rect = res_opt->rect, + .reco_detail = std::make_shared(std::move(raw_result)), + .task_ptr = task_ptr }; } if (task_ptr->algorithm == AlgorithmType::OcrDetect) { auto& raw_result = std::get(res_opt->result); - return { .rect = res_opt->rect, - .reco_detail = { { "score", raw_result.score }, { "text", raw_result.text } }, + return { .image = std::make_shared(std::move(image)), + .rect = res_opt->rect, + .reco_detail = std::make_shared(std::move(raw_result)), .task_ptr = task_ptr }; } if (task_ptr->algorithm == AlgorithmType::FeatureMatch) { auto& raw_result = std::get(res_opt->result); - return { .rect = res_opt->rect, .reco_detail = { { "count", raw_result.count } }, .task_ptr = task_ptr }; + return { .image = std::make_shared(std::move(image)), + .rect = res_opt->rect, + .reco_detail = std::make_shared(std::move(raw_result)), + .task_ptr = task_ptr }; } - return { .rect = res_opt->rect, .task_ptr = task_ptr }; + return { .image = std::make_shared(std::move(image)), .rect = res_opt->rect, .task_ptr = task_ptr }; } // action 为 Stop 时返回 Interrupted, 其它返回 Success @@ -253,7 +260,7 @@ ProcessTask::NodeStatus ProcessTask::run_task(const HitDetail& hits) { "max_times", max_times }, { "action", enum_to_string(task->action) }, { "algorithm", enum_to_string(task->algorithm) }, - { "result", hits.reco_detail }, + { "result", hits.reco_detail != nullptr ? *hits.reco_detail : json::object {} }, }; callback(AsstMsg::SubTaskStart, info); @@ -338,6 +345,7 @@ std::pair ProcessTask::find_and_run_task( } m_pre_task_name = std::move(m_last_task_name); + m_last_hit_detail = nullptr; HitDetail hits; for (int cur_retry = 0; cur_retry <= m_retry_times; ++cur_retry) { @@ -366,7 +374,8 @@ std::pair ProcessTask::find_and_run_task( return { NodeStatus::Interrupted, nullptr }; } - return { run_task(hits), hits.task_ptr }; + m_last_hit_detail = std::make_shared(std::move(hits)); + return { run_task(*m_last_hit_detail), m_last_hit_detail->task_ptr }; } ProcessTask::TimesLimitData ProcessTask::calc_time_limit(TaskConstPtr task) const diff --git a/src/MaaCore/Task/ProcessTask.h b/src/MaaCore/Task/ProcessTask.h index 35ddd3d3f0..d0cf028aa1 100644 --- a/src/MaaCore/Task/ProcessTask.h +++ b/src/MaaCore/Task/ProcessTask.h @@ -39,6 +39,8 @@ public: const std::string& get_last_task_name() const noexcept { return m_last_task_name; } + const auto& get_last_hit() const noexcept { return m_last_hit_detail; } + protected: enum class NodeStatus { @@ -51,8 +53,9 @@ protected: struct HitDetail { + std::shared_ptr image = nullptr; Rect rect; - json::value reco_detail; + std::shared_ptr reco_detail = nullptr; TaskConstPtr task_ptr = nullptr; }; @@ -87,5 +90,6 @@ protected: static constexpr int TaskDelayUnsetted = -1; int m_task_delay = TaskDelayUnsetted; cv::Mat m_reusable; + std::shared_ptr m_last_hit_detail = nullptr; }; } diff --git a/src/MaaCore/Vision/FeatureMatcher.cpp b/src/MaaCore/Vision/FeatureMatcher.cpp index a1cc1569ad..19e7f7a0ba 100644 --- a/src/MaaCore/Vision/FeatureMatcher.cpp +++ b/src/MaaCore/Vision/FeatureMatcher.cpp @@ -186,7 +186,7 @@ asst::FeatureMatcher::ResultsVec asst::FeatureMatcher::feature_postproc( break; } - results.emplace_back(Result { .rect = make_rect(box), .count = static_cast(count) }); + results.emplace_back(Result(make_rect(box), static_cast(count))); // remove inside points size_t compact_idx = 0; diff --git a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp index c7cda34ae4..f1f2e160f8 100644 --- a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp +++ b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp @@ -84,10 +84,8 @@ bool asst::OperBoxImageAnalyzer::opers_analyze() name_analyzer.set_width_threshold(params[5]); [[maybe_unused]] cv::Mat debug_img = make_roi(m_image, flag.rect.move(name_task->rect_move)); if (auto ocr_opt = name_analyzer.analyze()) { - asst::TemplDetOCRer::Result ocr { .flag_rect = flag.rect, .flag_score = flag.score }; - ocr.rect = ocr_opt->rect; - ocr.text = ocr_opt->text; - ocr.score = ocr_opt->score; + TemplDetOCRer::Result + ocr(ocr_opt->rect, ocr_opt->score, std::move(ocr_opt->text), flag.rect, flag.score); list.emplace_back(std::move(ocr)); } else { diff --git a/src/MaaCore/Vision/TemplDetOCRer.h b/src/MaaCore/Vision/TemplDetOCRer.h index 1d81731dd6..66813ae1bb 100644 --- a/src/MaaCore/Vision/TemplDetOCRer.h +++ b/src/MaaCore/Vision/TemplDetOCRer.h @@ -10,6 +10,15 @@ class TemplDetOCRer : public VisionHelper, public OCRerConfig, public MatcherCon public: struct Result : public TextRect { + using TextRect::TextRect; + + Result(Rect r, double s, std::string t, Rect f_r, double f_s) : + TextRect(r, s, std::move(t)), + flag_rect(f_r), + flag_score(f_s) + { + } + Rect flag_rect; double flag_score = .0; };