From 037ee70e640fccdcefcced32ccbb44994be30bb3 Mon Sep 17 00:00:00 2001 From: GD-GK <44790784+GD-GK@users.noreply.github.com> Date: Tue, 25 Apr 2023 20:08:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B9=B2=E5=91=98=E8=AF=86=E5=88=AB?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AD=89=E7=BA=A7=E5=92=8C=E7=B2=BE=E8=8B=B1?= =?UTF-8?q?=E5=BA=A6=20(#4438)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core返回json object * fix:冲突 * 等级ok * 等级和精英度 * core:等级,精英度识别 * 优化识别方式 * fix:ci * 添加潜能模板,fix ci * 潜能识别 * clang * fix:直接使用stoi * 修改识别完成条件 * 修复等级判断条件 * fix * 修改类继承,使用char_model,函数拆分 * 缩小名字识别框,添加替换字符。权宜之计 ( * 纠错,优化代码 --- resource/tasks.json | 74 +++++- resource/template/OperBoxFlagElite1.png | Bin 0 -> 1240 bytes resource/template/OperBoxFlagElite2.png | Bin 0 -> 1425 bytes resource/template/OperBoxPotential1.png | Bin 0 -> 1045 bytes resource/template/OperBoxPotential2.png | Bin 0 -> 1133 bytes resource/template/OperBoxPotential3.png | Bin 0 -> 1158 bytes resource/template/OperBoxPotential4.png | Bin 0 -> 1258 bytes resource/template/OperBoxPotential5.png | Bin 0 -> 1156 bytes .../Miscellaneous/OperBoxRecognitionTask.cpp | 24 +- .../Miscellaneous/OperBoxImageAnalyzer.cpp | 240 ++++++++++++++++-- .../Miscellaneous/OperBoxImageAnalyzer.h | 20 +- 11 files changed, 322 insertions(+), 36 deletions(-) create mode 100644 resource/template/OperBoxFlagElite1.png create mode 100644 resource/template/OperBoxFlagElite2.png create mode 100644 resource/template/OperBoxPotential1.png create mode 100644 resource/template/OperBoxPotential2.png create mode 100644 resource/template/OperBoxPotential3.png create mode 100644 resource/template/OperBoxPotential4.png create mode 100644 resource/template/OperBoxPotential5.png diff --git a/resource/tasks.json b/resource/tasks.json index f088d2264c..4a76d56392 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -2327,6 +2327,30 @@ "[Uu]-[O0o]f{1,2}icial", "U-Official" ], + [ + "^4", + "" + ], + [ + "^α", + "" + ], + [ + "^-", + "" + ], + [ + "—", + "" + ], + [ + ".*12F", + "12F" + ], + [ + "^_", + "" + ], [ ".*威龙陈", "假日威龙陈" @@ -9745,18 +9769,64 @@ 327 ] }, + "OperBoxFlagElite1": { + "doc": "精英一 模板" + }, + "OperBoxFlagElite2": { + "doc": "精英二 模板" + }, + "OperBoxFlagElite": { + "doc": "偏移,识别精英度,扩大两个像素点", + "template": "empty.png", + "templThreshold": 0.9, + "roi": [ + -7, + -52, + 24, + 35 + ] + }, + "OperBoxPotential": { + "doc": "偏移,识别潜能,扩大两个像素点", + "template": "empty.png", + "templThreshold": 0.85, + "roi": [ + 81, + -29, + 24, + 24 + ] + }, + "OperBoxPotential1": {}, + "OperBoxPotential2": {}, + "OperBoxPotential3": {}, + "OperBoxPotential4": {}, + "OperBoxPotential5": {}, "OperBoxNameOCR": { "algorithm": "OcrDetect", "fullMatch": true, "text": [], "roi": [ - -10, + 5, 42, - 120, + 105, 20 ], "postDelay": 100 }, + "OperBoxLevelOCR": { + "algorithm": "OcrDetect", + "fullMatch": true, + "isAscii": true, + "text": [], + "roi": [ + -13, + 7, + 37, + 23 + ], + "postDelay": 100 + }, "RoguelikeRecruitSwipeMaxTime": { "algorithm": "JustReturn", "maxTimes_Doc": "这个参数是肉鸽招募时,向右划动的最大次数", diff --git a/resource/template/OperBoxFlagElite1.png b/resource/template/OperBoxFlagElite1.png new file mode 100644 index 0000000000000000000000000000000000000000..3f78e0712e4a3e465f2c8f72b5b2c0b289eab40f GIT binary patch literal 1240 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 P00000NkvXXu0mjfq~z|o literal 0 HcmV?d00001 diff --git a/resource/template/OperBoxPotential2.png b/resource/template/OperBoxPotential2.png new file mode 100644 index 0000000000000000000000000000000000000000..1c677fcf6f6e870fcaf840d1f4e60c92fc0aa63f GIT binary patch literal 1133 zcmV-z1d{uSP)i1!-%-u#aUM7b#row-Qi z^>Li8OcGC}(`2&UbaiLR75mX|e?)8YD`c~d^eRcWs^NuV+BbG_{Q)pB(%;6c%_0TKP+3=^ZAB#Ed0Ug; zGs3=!gPcA60UuuY7~l6b8E)RZiLWi({4g>%f-LOC_MhTb{zAu5f_4W;r7VdQ7O#zt zF?s$HQ#-2 zb?y_6pZpN7(O~K2weH=Sp|xAZ+o@uwdq^o4p(Dar5{FSjk)2$govmuZM|JAlB`#gL zMsKdj^3p$)X6~`Duz+pb6noQ{S{=)kgh8EVyNxIwfo7f5+I<2YkSPqZwOu1Npsrl| zmax_0-{nPS@Bhux(gJ;beaV}3xsp9OmnhO0VKdivfaBgov-Zt2Xgci!O z$Q25R&p*9jEE8c95uu2T%fRp`Z;VecK0eOw?hcFP$Fv6aGuwNXY<-b^>%Wl8NNgeb zUs^P(&uM_sU<8ga_*(FEW0jqqU8&!9< zL0W30_7U6bbQcEDef?DC@6grqaD|5vt%UI%9gK~6*DLOV>UK!IU~Iq$<~_J`HPmF#5ieevd9>wVS|moH4|QmI6?FU$Fh zm$2;=opy(My@BWX2w{9kQQgc=(g#gYmw1l5BB zv{a;0J#;5+x{gE;+QIW2q>#KYs5K1ab4Kjgv2h+em}hTykKW!4>S!Xy?%qDWZ{hmz z*KUn{*+V*c1eu6~*G4wWgq0$f>n9WnVJXGf*f^O?mhJ5=HaDN)dJewtqMFSnp6i-c zloTkf@fsDHGDJ9*AQFvnd~%X2uT7E5<&49HALq&T^<&#M^Yio6Y6nO#W09`onITK* zBZY@$XK0OHCY0_+wyIowd5qg{-DG5Bgy+w<`Qr1>xPSj1+CQ9Up|DJ?TEX{x6Q;71 zz%sM(kEz= z@kA`>GC;#KVxT#dkF#pqlyeypCz7;Ub!KK}SX^Ah^E@Jv2!lhzq*5sgg#z{30lw#& z|MGBbK9_u7I)La|ta6VZlt|8ku zK&q$Lgi|a&p<1n)S-MW!F!-pjg!uH6kM;V~ZOZ#)GCfDRe(iN$xpJMm)fC_TDR|>p zh_^=|t+Z)RN{Qn*M&Q2^<}H9;y!*~=9WWRTV=T8_$n+1>b@B$Qu_=V5IOqJz3ESh< zb5jPFg@py4mevms&!H4T3c^aFM*0L!+d(ObVRqoI@nZy}5!|ZaA-Dr*B z{GefPdU~3*wN?IKfqRvRTGX{L7bIjscTCe2b~xyia4JRI+$p4;CD)&3`H$b3ox4l5 zyh*If|JR*)v@q961Kn8hyZAl*>~7s->ESQ5YGvXPKRAab zS*^7(6ZCJ}Atb>E0b|0%Zz;>PAGRQNP{i6_rxVXp*mLokW$dU=DD+PNFM<$(h(-wb Y8`wh5>;sF_oB#j-07*qoM6N<$f=56+r~m)} literal 0 HcmV?d00001 diff --git a/resource/template/OperBoxPotential4.png b/resource/template/OperBoxPotential4.png new file mode 100644 index 0000000000000000000000000000000000000000..6496c75638dc999cfc3ca917db15c01511743aa9 GIT binary patch literal 1258 zcmV3$&C1 z1(gIMP(?@(@**=sLgtmsOwXfdy8Bw)K~B}VcXRGn_k8DkpZ3wkNmVXaP@z_wmO-c% zQJDo)y^K;03UCj#eR<*74z}Z9Sr)dXh(ua2N_nqBW;1E>g#t>X2<#Xjbns59{-H!$5#mMe-9Z9Bc+dEC`4pu6QOX3Bcr2ybNMoZLqjAINh*~Jng&wWHFTk& z6xgKRvJ8xj&@(v5uTRqCvt?eFf~eL@92hb2 zwZ>RkSs|H-V_S9fH=Rnkec&h;JwQiSH<4)6%WSd0v)QM_|N0Y|*u;!XP-!3IUOfs) zK}RA%d~F@avAj75O+!kd;bu6zgOSk*j*cJW|M+)qp6l1H@p5Sa$8iWYFVhvaFe9g# zUvA)GCPG$55V{Un2mvw}@YCG9m+|A1oH_Riot-htp8`#1Y;26~?k>7I zTUd+FVp$5!_VZ4xgL5OzWRo*2tY;8SA$-v`sO0eI`}FfK*|&d$OeV#P7cZE7I!8Dh zrmwG$?pP1UPn-hkC|e`eyO;j{0Z-H|Vw1MQ6B^svNRJF7+Z(AB3usRsKTz4+77I%& zlu8DN-W{R0w~w~n?OxlPxh&c2h6mERtDR_bi)Rd}bc(WJxKg89DO0c4c=3E5`Qz2A zHvMHZJ|F>x%(*|Q(e+1bh5+&q~~hSQU0F^m#-@7`r)dCB#lw;Q26 zJ2R2HnkxVi%pTy_-q9;QQzf=TejdUtWB9WlGXAdQ#$kg9=C}iU_=oNgz+D_d1uYb7qJA?RHBkZK)UyaVrphS`tgOP!l4WA_PQ8lt|)@8gIPT3lbqABqj)Y zc5`6=v{{sGIj+wRWp&df10{KPLgb7tn8yyyGg_x+Bx z_}L{&2!U?se12d*QPbq~$sUd$`;kK4!V9I8Kfs&4C)Cx}60eN&=C-Yz`>U6Mi+>}f z5NJXW35S@T&GG8`^{i}a!Y!5P?*5IL>@-Sg{{wU}41-8C!uub7!17fqId}ddW-y3e zJ-=p;rfDcmLz9Bm*0oeuSJSj=1@-myTpJuB7!3ItdLV&-Nkv5k`@T59h7B9I{cw)+ zfAnx~atf&n%}-qeGLut$bF_!eZ*QeB7N=uV2dyu+^3|ck)GVm+iuCsyQqtbmM%i|_ zGVm`}!NRgEq{o*RLMbxi6HE+Uz?xda<$Rcy#S5vdtYq)Ly$D^$Rf@}ZGF%@@qXhyK z@>%ZP9AqZ*0LQiwhBS~uNB2s#6}2@rG}c$~+b_pCGo13t4o4ycgF!|ulV5*6#q!lj z99MCDYMQ%u(xh&U;JPkS>N?630p+W+qN$mArpYJo>>!ayAT*69v7}PxvyZnE3Wb?1 zm$^F7&saL`ALwlpzAbcb=)_`CY8N&5@743GJVN<%5E`4t76ygT^u}okjh2%%mV$X32tTbI7-pDbUC(VQxS zO~j)??$4AM7`#FzJ40Q49Whh-YHHorrhF$3^!NGw*1qC-V&Nb`q47jVM}hPBBk=g2 ztDaWu)AC?Ci`MbpM+(=*lp4xWB%51kX} zTzXvMqdUoV9i(SaA#{}M`b2mwC8VM-Im+eX+q5??qit;~M>{*|>FPpR7EW#!-=<38 zD%a1@Kzr1i-qqsy#+!91{gbThG^x}bU!}%|1@!fvM=KU7=H@6DN|f>z#W{;YZjQpt z9L2eU*LnutkY2&kL-=@>G=wSj)}#WF?P^?^#W1(fYIv_zM>-*(cwC=7{|I{yLp Wg34^5BEF0O0000get_image()); @@ -33,10 +35,12 @@ bool asst::OperBoxRecognitionTask::swipe_and_analyze() break; } const auto& opers_result = analyzer.get_result(); - if (opers_result.back().name == current_page_last_oper_name) { + if (opers_result.back().name == current_page_last_oper_name && + opers_result.front().name == current_page_first_oper_name) { break; } else { + current_page_first_oper_name = opers_result.front().name; current_page_last_oper_name = opers_result.back().name; for (const auto& box_info : opers_result) { m_own_opers.emplace(box_info.name, box_info); @@ -72,13 +76,17 @@ void asst::OperBoxRecognitionTask::callback_analyze_result(bool done) { "name", name }, { "own", own }, }); - if (own) { - own_opers.emplace_back(json::object { - { "id", BattleData.get_id(name) }, { "name", name }, { "own", own }, - // TODO - // { "elite", 0 }, { "level", 0 }, - }); - } + } + for (const auto& [name,box_info] : m_own_opers) { + own_opers.emplace_back(json::object { + { "id", box_info.id }, + { "name", box_info.name }, + { "own", box_info.own }, + { "elite", box_info.elite }, + { "level", box_info.level }, + { "potential", box_info.potential }, + // TODO + }); } callback(AsstMsg::SubTaskExtraInfo, info); diff --git a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp index 0cc72e6656..a0c74b60d7 100644 --- a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp +++ b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.cpp @@ -5,48 +5,244 @@ #include "Config/Miscellaneous/BattleDataConfig.h" #include "Config/TaskData.h" #include "Utils/Logger.hpp" +#include "Vision/BestMatchImageAnalyzer.h" #include "Vision/MatchImageAnalyzer.h" -#include "Vision/OcrWithFlagTemplImageAnalyzer.h" +#include "Vision/MultiMatchImageAnalyzer.h" #include "Vision/OcrWithPreprocessImageAnalyzer.h" bool asst::OperBoxImageAnalyzer::analyze() { LogTraceFunction; + m_current_page_opers.clear(); - bool oper_box = analyzer_opers(); -#ifdef ASST_DEBUG - m_image_draw = m_image_draw_oper; -#endif + bool oper_box = analyzer_oper_box(); save_img(utils::path("debug") / utils::path("oper")); return oper_box; } -bool asst::OperBoxImageAnalyzer::analyzer_opers() +int asst::OperBoxImageAnalyzer::level_num(const std::string &level) { - std::vector oper_names_result; - const auto& ocr_replace = Task.get("CharsNameOcrReplace"); + if (level.empty() || !ranges::all_of(level, [](const char& c) -> bool { return std::isdigit(c); })) { + return 1; + } + return std::stoi(level); +} - OcrWithFlagTemplImageAnalyzer oper_name_analyzer(m_image); +bool asst::OperBoxImageAnalyzer::analyzer_oper_box() +{ + LogTraceFunction; - oper_name_analyzer.set_task_info("OperBoxFlagLV", "OperBoxNameOCR"); - oper_name_analyzer.set_replace(ocr_replace->replace_map, ocr_replace->replace_full); - const auto& all_opers = BattleData.get_all_oper_names(); - oper_name_analyzer.set_required(std::vector(all_opers.begin(), all_opers.end())); - if (!oper_name_analyzer.analyze()) { +#ifdef ASST_DEBUG + m_image_draw_oper = m_image_draw; +#endif // ASST_DEBUG + + if (!lv_flag_analyzer()) { return false; } - for (auto& opername : oper_name_analyzer.get_result()) { - OperBoxInfo oper_info; - oper_info.name = std::move(opername.text); - m_current_page_opers.emplace_back(oper_info); + if (!names_analyzer()) { + return false; + } + + if (!level_analyzer()) { + return false; + } + + if (!elite_analyzer()) { + return false; + } + + if (!potential_analyzer()) { + return false; + } + + sort_oper_horizontal(m_current_page_opers); + for (const auto& box : m_current_page_opers) { + Log.trace("operBox{", "\"rect_lv\":[", box.rect.x, box.rect.y, box.rect.width, box.rect.height, + "], \"id\": ", box.id, ", \"name\": ", box.name, ", \"elite\": ", box.elite, + ", \"level\": ", box.level, ", \"potential\": ", box.potential, "}"); + } #ifdef ASST_DEBUG - m_image_draw_oper = m_image; - cv::rectangle(m_image_draw_oper, make_rect(opername.rect), cv::Scalar(0, 255, 0), 2); - cv::putText(m_image_draw_oper, opername.text, cv::Point(opername.rect.x, opername.rect.y - 10), - cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2); + m_image_draw = m_image_draw_oper; #endif + + return !m_current_page_opers.empty(); +} + +// 获取lv_flag,必须是第一步 +bool asst::OperBoxImageAnalyzer::lv_flag_analyzer() +{ + MultiMatchImageAnalyzer m_multi_match_image_analyzer(m_image); + m_multi_match_image_analyzer.set_task_info("OperBoxFlagLV"); + m_multi_match_image_analyzer.analyze(); + const auto& m_lv_flags = m_multi_match_image_analyzer.get_result(); + + if (m_lv_flags.empty()) { + return false; + } + + // 填入rect + for (const auto& lv_flag : m_lv_flags) { + OperBoxInfo box; + box.rect = lv_flag.rect; + box.own = true; + m_current_page_opers.emplace_back(box); + +#ifdef ASST_DEBUG + cv::rectangle(m_image_draw_oper, make_rect(lv_flag.rect), cv::Scalar(0, 255, 0), 1); +#endif // ASST_DEBUG } return true; } + +// 识别名字 +bool asst::OperBoxImageAnalyzer::names_analyzer() +{ + OcrWithPreprocessImageAnalyzer name_analyzer(m_image); + name_analyzer.set_task_info("OperBoxNameOCR"); + const Rect name_roi = Task.get("OperBoxNameOCR")->roi; + + const auto& ocr_replace = Task.get("CharsNameOcrReplace"); + + name_analyzer.set_replace(ocr_replace->replace_map, ocr_replace->replace_full); + + for (auto& box : m_current_page_opers) { + Rect roi = box.rect.move(name_roi); + if (roi.x + roi.width >= WindowWidthDefault) { + // 超出范围提示,框width该缩小。 + Log.error("name rect:[", roi.x, roi.y, roi.width, roi.height, " out of range "); + return false; + } + name_analyzer.set_roi(roi); + if (name_analyzer.analyze()) { + const auto& ocr_result = name_analyzer.get_result().front(); + std::string name = ocr_result.text; + box.id = BattleData.get_id(name); + box.name = std::move(name); +#ifdef ASST_DEBUG + cv::rectangle(m_image_draw_oper, make_rect(ocr_result.rect), cv::Scalar(0, 255, 0), 1); + cv::putText(m_image_draw_oper, box.id, cv::Point(roi.x, roi.y + 35), cv::FONT_HERSHEY_SIMPLEX, 0.5, + cv::Scalar(0, 0, 255), 2); +#endif // ASST_DEBUG + } + } + return true; +} + +// 识别等级 +bool asst::OperBoxImageAnalyzer::level_analyzer() +{ + OcrWithPreprocessImageAnalyzer level_analyzer(m_image); + level_analyzer.set_task_info("OperBoxLevelOCR"); + const Rect level_roi = Task.get("OperBoxLevelOCR")->roi; + + const auto& ocr_replace_num = Task.get("NumberOcrReplace"); + level_analyzer.set_replace(ocr_replace_num->replace_map, ocr_replace_num->replace_full); + + for (auto& box : m_current_page_opers) { + Rect roi = box.rect.move(level_roi); + if (roi.x < 0) { + // 等级在lv的左,lv的识别框x该右移 + Log.error("level rect:[", roi.x, roi.y, roi.width, roi.height, " out of range "); + return false; + } + level_analyzer.set_roi(roi); + if (level_analyzer.analyze()) { + const auto& ocr_result = level_analyzer.get_result().front(); + std::string level = ocr_result.text; + box.level = std::move(level_num(level)); +#ifdef ASST_DEBUG + cv::rectangle(m_image_draw_oper, make_rect(ocr_result.rect), cv::Scalar(0, 255, 0), 1); + cv::putText(m_image_draw_oper, level, cv::Point(roi.x, roi.y - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, + cv::Scalar(0, 0, 255), 2); +#endif // ASST_DEBUG + } + } + return true; +} +// 识别精英度 +bool asst::OperBoxImageAnalyzer::elite_analyzer() +{ + const std::string task_name = "OperBoxFlagElite"; + const Rect elite_roi = Task.get(task_name)->roi; + BestMatchImageAnalyzer elite_analyzer(m_image); + elite_analyzer.set_task_info(task_name); + elite_analyzer.append_templ("OperBoxFlagElite1.png"); + elite_analyzer.append_templ("OperBoxFlagElite2.png"); + for (auto& box : m_current_page_opers) { + Rect roi = box.rect.move(elite_roi); + if (roi.x < 0) { + // 等级在lv的左,lv的识别框x该右移 + Log.error("elite rect:[", roi.x, roi.y, roi.width, roi.height, " out of range "); + return false; + } + elite_analyzer.set_roi(roi); + if (!elite_analyzer.analyze()) { + box.elite = 0; + } + else { + const auto& elite_templ = elite_analyzer.get_result(); + std::string elite = elite_templ.name.substr(task_name.size(), 1); + box.elite = std::stoi(elite); +#ifdef ASST_DEBUG + cv::rectangle(m_image_draw_oper, make_rect(roi), cv::Scalar(0, 255, 0), 1); +#endif // ASST_DEBUG + } +#ifdef ASST_DEBUG + cv::putText(m_image_draw_oper, std::to_string(box.elite), cv::Point(roi.x, roi.y - 10), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2); +#endif // ASST_DEBUG + } + return true; +} +// 识别潜能 +bool asst::OperBoxImageAnalyzer::potential_analyzer() +{ + const std::string task_name_p = "OperBoxPotential"; + const Rect potential_roi = Task.get(task_name_p)->roi; + BestMatchImageAnalyzer potential_analyzer(m_image); + potential_analyzer.set_task_info(task_name_p); + for (int i = 1; i < 6; i++) { + std::string potential_temp_name = task_name_p + std::to_string(i) + ".png"; + potential_analyzer.append_templ(potential_temp_name); + } + for (auto& box : m_current_page_opers) { + Rect roi = box.rect.move(potential_roi); + if (roi.x + roi.width < 0) { + // 潜能在lv的右,lv的识别框width该缩小 + Log.error("level rect:[", roi.x, roi.y, roi.width, roi.height, " out of range "); + return false; + } + potential_analyzer.set_roi(roi); + if (!potential_analyzer.analyze()) { + box.potential = 0; + } + else { + const auto& poten_templ = potential_analyzer.get_result(); + std::string potential = poten_templ.name.substr(task_name_p.size(), 1); + box.potential = std::stoi(potential); +#ifdef ASST_DEBUG + cv::rectangle(m_image_draw_oper, make_rect(roi), cv::Scalar(0, 255, 0), 1); +#endif // ASST_DEBUG + } +#ifdef ASST_DEBUG + cv::putText(m_image_draw_oper, std::to_string(box.potential), cv::Point(roi.x, roi.y - 10), + cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 255), 2); +#endif // ASST_DEBUG + } + return true; +} + +void asst::OperBoxImageAnalyzer::sort_oper_horizontal(std::vector m_oper_boxs) +{ + // 按位置排个序 + ranges::sort(m_oper_boxs, [](const OperBoxInfo& lhs, const OperBoxInfo& rhs) -> bool { + if (std::abs(lhs.rect.y - rhs.rect.y) < 5) { // y差距较小则理解为是同一排的,按x排序 + return lhs.rect.x < rhs.rect.x; + } + else { + return lhs.rect.y < rhs.rect.y; + } + }); +} diff --git a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.h b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.h index 2bb5e3c7bb..31a7c533ae 100644 --- a/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.h +++ b/src/MaaCore/Vision/Miscellaneous/OperBoxImageAnalyzer.h @@ -6,11 +6,13 @@ namespace asst { struct OperBoxInfo { - std::string name; std::string id; + std::string name; int level = 0; // 等级 int elite = 0; // 精英度 bool own = false; + int potential = 0; // 潜能 + Rect rect; }; class OperBoxImageAnalyzer final : public AbstractImageAnalyzer { @@ -21,9 +23,19 @@ namespace asst const auto& get_result() const noexcept { return m_current_page_opers; } private: - bool analyzer_opers(); - - std::vector m_current_page_opers; + int level_num(const std::string& level); + bool analyzer_oper_box(); + // 获取lv rect + bool lv_flag_analyzer(); + bool names_analyzer(); + bool level_analyzer(); + bool elite_analyzer(); + bool potential_analyzer(); + // 按位置排序 + // 1 - 2 - 3 + // 4 - 5 - 6 + void sort_oper_horizontal(std::vector m_oper_boxs); + std::vector m_current_page_opers; #ifdef ASST_DEBUG cv::Mat m_image_draw_oper; #endif