mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-19 10:32:19 +08:00
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:
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user