perf: 自动战斗编队优化干员识别, 修复roi未包含完整干员名 (#12740)

* perf: 自动战斗编队优化干员识别

* chore: Auto update by pre-commit hooks [skip changelog]

* perf: task

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
status102
2025-05-20 14:31:35 +08:00
committed by GitHub
parent 9d85c3c3b4
commit 49d4dc78b1
3 changed files with 61 additions and 35 deletions

View File

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

View File

@@ -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<size_t>(number) && i < opers_result.size(); ++i) {
@@ -347,50 +348,76 @@ void asst::BattleFormationTask::report_missing_operators(std::vector<OperGroup>&
callback(AsstMsg::SubTaskError, info);
}
std::vector<asst::BattleFormationTask::QuickFormationOper> asst::BattleFormationTask::analyzer_opers()
std::vector<asst::BattleFormationTask::QuickFormationOper>
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<OcrTaskInfo>("CharsNameOcrReplace");
std::vector<QuickFormationOper> opers_result;
cv::Mat select;
std::vector<asst::BattleFormationTask::QuickFormationOper> 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<OperGroup>& groups)
{
auto opers_result = analyzer_opers();
auto opers_result = analyzer_opers(ctrler()->get_image());
static const std::array<Rect, 3> SkillRectArray = {
Task.get("BattleQuickFormationSkill1")->specific_rect,

View File

@@ -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<OperGroup>& groups);
std::vector<QuickFormationOper> analyzer_opers();
std::vector<QuickFormationOper> analyzer_opers(const cv::Mat& image);
std::string m_stage_name;
std::unordered_map<battle::Role, std::vector<OperGroup>> m_formation;