diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 3579201bfd..35f5c5c2a5 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -718,7 +718,6 @@ ["^重岳.+", "重岳"], ["(麒.+夜刀|.*麟.*夜刀)$", "麒麟R夜刀"], [".*龙.*黑角$", "火龙S黑角"], - [".*大陆调查团$", "泰拉大陆调查团"], ["[Uu]-[O0o]f{1,2}icial", "U-Official"], [".*威龙陈", "假日威龙陈"], ["青积", "青枳"], @@ -760,7 +759,6 @@ ["^华琳$", "华法琳"], ["^宝箱的肉.*", "宝箱的肉?"], [".*维多利亚$", "维娜·维多利亚"], - [".*芜拉普兰德$", "荒芜拉普兰德"], ["^盥心$", "塑心"], ["^钳铅$", "钼铅"], [".*NFESS-47$", "CONFESS-47"], @@ -3600,7 +3598,7 @@ "algorithm": "OcrDetect", "fullMatch": true, "text": [], - "roi": [9, 232, 107, 20], + "roi": [-2, 233, 118, 22], "postDelay": 200, "specialParams_Doc": "Added for the YostarEN client. Used in BattleFormationTask.cpp for OCR manipulation. CN values are from OCRerConfig.h", "specialParams": [140, 2, 0, 0] diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp index 0be468d404..b2401b1bbb 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp @@ -13,6 +13,7 @@ #include "Utils/ImageIo.hpp" #include "Utils/Logger.hpp" #include "Vision/MultiMatcher.h" +#include "Vision/RegionOCRer.h" asst::BattleFormationTask::BattleFormationTask( const AsstCallback& callback, @@ -256,7 +257,7 @@ bool asst::BattleFormationTask::add_additional() // unknown role means "all" click_role_table(role); - auto opers_result = analyzer_opers(); + auto opers_result = analyzer_opers(ctrler()->get_image()); // TODO 这里要识别一下干员之前有没有被选中过 for (size_t i = 0; i < static_cast(number) && i < opers_result.size(); ++i) { @@ -347,50 +348,76 @@ void asst::BattleFormationTask::report_missing_operators(std::vector& callback(AsstMsg::SubTaskError, info); } -std::vector asst::BattleFormationTask::analyzer_opers() +std::vector + asst::BattleFormationTask::analyzer_opers(const cv::Mat& image) { - auto formation_task_ptr = Task.get("BattleQuickFormationOCR"); - auto image = ctrler()->get_image(); const auto& ocr_replace = Task.get("CharsNameOcrReplace"); - std::vector opers_result; - cv::Mat select; + std::vector opers_result; + cv::Mat select, ocr, gray, bin; for (int i = 0; i < 8; ++i) { std::string task_name = "BattleQuickFormation-OperNameFlag" + std::to_string(i); - const auto& params = Task.get("BattleQuickFormationOCR")->special_params; - TemplDetOCRer name_analyzer(image); - - name_analyzer.set_task_info(task_name, "BattleQuickFormationOCR"); - name_analyzer.set_bin_threshold(params[0]); - name_analyzer.set_bin_expansion(params[1]); - name_analyzer.set_bin_trim_threshold(params[2], params[3]); - name_analyzer.set_replace(ocr_replace->replace_map, ocr_replace->replace_full); - auto cur_opt = name_analyzer.analyze(); - if (!cur_opt) { + const auto& ocr_task = Task.get("BattleQuickFormationOCR"); + MultiMatcher multi(image); + multi.set_task_info(task_name); + if (!multi.analyze()) [[unlikely]] { continue; } - for (auto& res : *cur_opt) { + for (const auto& flag : multi.get_result()) { + ocr = make_roi(image, flag.rect.move(ocr_task->roi)); + cv::cvtColor(ocr, gray, cv::COLOR_BGR2GRAY); + cv::inRange(gray, ocr_task->special_params[0], 255, bin); + for (int r = bin.cols - 1; r >= 0; --r) { + if (cv::hasNonZero(bin.col(r))) { // 右边界向左收缩 + bin = bin.adjustROI(0, 0, 0, -(bin.cols - r - 1)); + break; + } + } + + bin = bin.adjustROI(0, -2, 0, 0); // 底部收缩排除白线 + int width = 5; + for (int r = bin.cols - width - 1; r >= 0; --r) { + if (!cv::hasNonZero(bin.colRange(r, r + width))) { // 左边界排除无文字区域 + ocr = ocr.adjustROI(0, 0, -r - 3, 0); + break; + } + } + + RegionOCRer region(ocr); + region.set_task_info(ocr_task); + region.set_roi(asst::Rect(0, 0, ocr.cols, ocr.rows)); + region.set_bin_threshold(ocr_task->special_params[0]); + region.set_bin_expansion(ocr_task->special_params[1]); + region.set_bin_trim_threshold(ocr_task->special_params[2], ocr_task->special_params[3]); + region.set_replace(ocr_replace->replace_map, ocr_replace->replace_full); + region.set_use_raw(true); + if (!region.analyze()) [[unlikely]] { + continue; + } + + const auto& ocr_result = region.get_result(); + asst::BattleFormationTask::QuickFormationOper res; + res.text = ocr_result.text; + res.rect = ocr_result.rect; + res.score = ocr_result.score; + res.flag_rect = flag.rect; + res.flag_score = flag.score; + constexpr int kMinDistance = 5; - auto find_it = ranges::find_if(opers_result, [&res](const TemplDetOCRer::Result& pre) { - return std::abs(pre.flag_rect.x - res.flag_rect.x) < kMinDistance && - std::abs(pre.flag_rect.y - res.flag_rect.y) < kMinDistance; - }); + auto find_it = + ranges::find_if(opers_result, [&res](const asst::BattleFormationTask::QuickFormationOper& pre) { + return std::abs(pre.flag_rect.x - res.flag_rect.x) < kMinDistance && + std::abs(pre.flag_rect.y - res.flag_rect.y) < kMinDistance; + }); if (find_it != opers_result.end() || res.text.empty()) { continue; } - QuickFormationOper oper; - oper.flag_rect = res.flag_rect; - oper.flag_score = res.flag_score; - oper.text = res.text; - oper.rect = res.rect; - oper.score = res.score; select = make_roi(image, res.flag_rect.move({ 0, -10, 5, 4 })); cv::inRange(select, cv::Scalar(200, 140, 0), cv::Scalar(255, 180, 100), select); - oper.is_selected = cv::hasNonZero(select); - opers_result.emplace_back(std::move(oper)); + res.is_selected = cv::hasNonZero(select); + opers_result.emplace_back(std::move(res)); } } - if (opers_result.empty()) { Log.error("BattleFormationTask: no oper found"); return {}; @@ -408,7 +435,7 @@ bool asst::BattleFormationTask::enter_selection_page(const cv::Mat& img) bool asst::BattleFormationTask::select_opers_in_cur_page(std::vector& groups) { - auto opers_result = analyzer_opers(); + auto opers_result = analyzer_opers(ctrler()->get_image()); static const std::array SkillRectArray = { Task.get("BattleQuickFormationSkill1")->specific_rect, diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h index 69c8cdbd45..8c140d66a5 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h +++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h @@ -3,6 +3,7 @@ #include "Common/AsstBattleDef.h" #include "Task/AbstractTask.h" +#include "Utils/NoWarningCVMat.h" #include "Vision/TemplDetOCRer.h" namespace asst @@ -103,7 +104,7 @@ protected: bool select_random_support_unit(); void report_missing_operators(std::vector& groups); - std::vector analyzer_opers(); + std::vector analyzer_opers(const cv::Mat& image); std::string m_stage_name; std::unordered_map> m_formation;