mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
perf: update StageDropsImageAnalyzer
This commit is contained in:
@@ -6598,8 +6598,8 @@
|
||||
22
|
||||
],
|
||||
"maskRange": [
|
||||
150,
|
||||
255
|
||||
0,
|
||||
110
|
||||
]
|
||||
},
|
||||
"NumberOcrReplace": {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Config/Miscellaneous/ItemConfig.h"
|
||||
#include "Config/Miscellaneous/StageDropsConfig.h"
|
||||
#include "Config/TaskData.h"
|
||||
#include "Config/TemplResource.h"
|
||||
#include "Utils/ImageIo.hpp"
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Vision/MatchImageAnalyzer.h"
|
||||
@@ -192,9 +193,9 @@ bool asst::StageDropsImageAnalyzer::analyze_drops()
|
||||
|
||||
std::string item = match_item(item_roi, drop_type, size - i, size);
|
||||
bool use_word_model = item == LMD_ID;
|
||||
int quantity = match_quantity(item_roi, use_word_model);
|
||||
int quantity = match_quantity(item_roi, item, use_word_model);
|
||||
if (use_word_model && quantity == 0) {
|
||||
quantity = match_quantity(item_roi, false);
|
||||
quantity = match_quantity(item_roi, item, false);
|
||||
}
|
||||
Log.info("Item id:", item, ", quantity:", quantity);
|
||||
#ifdef ASST_DEBUG
|
||||
@@ -462,7 +463,8 @@ std::string asst::StageDropsImageAnalyzer::match_item(const Rect& roi, StageDrop
|
||||
return result;
|
||||
}
|
||||
|
||||
int asst::StageDropsImageAnalyzer::match_quantity(const Rect& roi, bool use_word_model)
|
||||
std::optional<asst::TextRect> asst::StageDropsImageAnalyzer::match_quantity_string(const asst::Rect& roi,
|
||||
bool use_word_model)
|
||||
{
|
||||
auto task_ptr = Task.get<MatchTaskInfo>("StageDrops-Quantity");
|
||||
|
||||
@@ -508,7 +510,7 @@ int asst::StageDropsImageAnalyzer::match_quantity(const Rect& roi, bool use_word
|
||||
}
|
||||
|
||||
if (contours.empty()) {
|
||||
return 0;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 前面的 split 算法经过了大量的测试集验证,分割效果一切正常
|
||||
@@ -525,10 +527,94 @@ int asst::StageDropsImageAnalyzer::match_quantity(const Rect& roi, bool use_word
|
||||
analyzer.set_use_char_model(!use_word_model);
|
||||
|
||||
if (!analyzer.analyze()) {
|
||||
return 0;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto& result = analyzer.get_result().front();
|
||||
return analyzer.get_result().front();
|
||||
}
|
||||
|
||||
std::optional<asst::TextRect> asst::StageDropsImageAnalyzer::match_quantity_string(const asst::Rect& roi,
|
||||
const std::string& item,
|
||||
bool use_word_model)
|
||||
{
|
||||
auto task_ptr = Task.get<MatchTaskInfo>("StageDrops-Quantity");
|
||||
auto templ = TemplResource::get_instance().get_templ(item).clone();
|
||||
if (templ.empty()) {
|
||||
Log.error("templ is empty: ", item);
|
||||
return std::nullopt;
|
||||
}
|
||||
cv::resize(templ, templ, cv::Size {}, 0.975, 0.975); // make it more accurate
|
||||
|
||||
MatchImageAnalyzer analyzer(m_image);
|
||||
analyzer.set_templ(templ);
|
||||
analyzer.set_mask_range(1, 255);
|
||||
analyzer.set_mask_with_close(true);
|
||||
analyzer.set_roi(roi);
|
||||
if (!analyzer.analyze()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
Rect new_roi = analyzer.get_result().rect;
|
||||
cv::Mat item_img = m_image(make_rect<cv::Rect>(new_roi));
|
||||
|
||||
// ref: DepotImageAnalyzer::match_quantity
|
||||
cv::Mat quotient;
|
||||
cv::divide(item_img + cv::Scalar { 1, 1, 1 }, templ + cv::Scalar { 1, 1, 1 }, quotient, 255);
|
||||
|
||||
cv::Mat mask_r;
|
||||
cv::Mat mask_g;
|
||||
cv::Mat mask_b;
|
||||
static constexpr int lb = 60;
|
||||
static constexpr int ub = 140;
|
||||
cv::inRange(quotient, cv::Scalar { lb, 0, 0 }, cv::Scalar { ub, 255, 255 }, mask_r);
|
||||
cv::inRange(quotient, cv::Scalar { 0, lb, 0 }, cv::Scalar { 255, ub, 255 }, mask_g);
|
||||
cv::inRange(quotient, cv::Scalar { 0, 0, lb }, cv::Scalar { 255, 255, ub }, mask_b);
|
||||
cv::Mat mask;
|
||||
cv::bitwise_or(mask_r, mask_g, mask);
|
||||
cv::bitwise_or(mask, mask_b, mask);
|
||||
|
||||
cv::Mat templ_mask;
|
||||
cv::inRange(templ, cv::Scalar { 0, 0, 0 }, cv::Scalar { 0, 0, 0 }, templ_mask);
|
||||
cv::bitwise_not(templ_mask, templ_mask);
|
||||
cv::bitwise_and(mask, templ_mask, mask);
|
||||
mask(cv::Rect { 0, 0, mask.cols / 4, mask.rows }) = cv::Scalar { 0, 0, 0 };
|
||||
cv::morphologyEx(mask, mask, cv::MORPH_OPEN, cv::getStructuringElement(cv::MORPH_RECT, { 4, 4 }));
|
||||
|
||||
auto mask_rect = cv::boundingRect(mask);
|
||||
if (mask_rect.height < 20) mask_rect.height = 20;
|
||||
|
||||
cv::Mat ocr_img = m_image.clone();
|
||||
cv::subtract(ocr_img(make_rect<cv::Rect>(new_roi)), templ * 0.41, ocr_img(make_rect<cv::Rect>(new_roi)));
|
||||
|
||||
OcrWithPreprocessImageAnalyzer ocr(ocr_img);
|
||||
ocr.set_task_info("NumberOcrReplace");
|
||||
Rect ocr_roi { new_roi.x + mask_rect.x, new_roi.y + mask_rect.y, mask_rect.width, mask_rect.height };
|
||||
ocr.set_roi(ocr_roi);
|
||||
ocr.set_expansion(0);
|
||||
ocr.set_use_char_model(!use_word_model);
|
||||
|
||||
ocr.set_threshold(task_ptr->mask_range.first, task_ptr->mask_range.second);
|
||||
|
||||
if (!ocr.analyze()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return ocr.get_result().front();
|
||||
}
|
||||
|
||||
int asst::StageDropsImageAnalyzer::match_quantity(const asst::Rect& roi, const std::string& item, bool use_word_model)
|
||||
{
|
||||
TextRect result;
|
||||
// is furniture?
|
||||
if (item.empty() || item == "furni") {
|
||||
auto opt = match_quantity_string(roi, use_word_model);
|
||||
if (!opt) return 0;
|
||||
result = opt.value();
|
||||
}
|
||||
else {
|
||||
auto opt = match_quantity_string(roi, item, use_word_model);
|
||||
if (!opt) return 0;
|
||||
result = opt.value();
|
||||
}
|
||||
|
||||
#ifdef ASST_DEBUG
|
||||
cv::rectangle(m_image_draw, make_rect<cv::Rect>(result.rect), cv::Scalar(0, 0, 255));
|
||||
@@ -548,7 +634,7 @@ int asst::StageDropsImageAnalyzer::match_quantity(const Rect& roi, bool use_word
|
||||
multiple = 10000;
|
||||
digit_str.erase(w_pos, digit_str.size());
|
||||
}
|
||||
else if (size_t k_pos = digit_str.find("k"); k_pos != std::string::npos) {
|
||||
else if (size_t k_pos = digit_str.find('k'); k_pos != std::string::npos) {
|
||||
multiple = 1000;
|
||||
digit_str.erase(k_pos, digit_str.size());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "Vision/AbstractImageAnalyzer.h"
|
||||
#include "Config/Miscellaneous/StageDropsConfig.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class StageDropsImageAnalyzer final : public AbstractImageAnalyzer
|
||||
@@ -27,7 +29,10 @@ namespace asst
|
||||
bool analyze_baseline();
|
||||
bool analyze_drops();
|
||||
|
||||
int match_quantity(const Rect& roi, bool use_word_model = false);
|
||||
int match_quantity(const Rect& roi, const std::string& item, bool use_word_model = false);
|
||||
std::optional<TextRect> match_quantity_string(const Rect& roi, bool use_word_model = false);
|
||||
std::optional<TextRect> match_quantity_string(const Rect& roi, const std::string& item, bool use_word_model = false);
|
||||
|
||||
StageDropType match_droptype(const Rect& roi);
|
||||
std::string match_item(const Rect& roi, StageDropType type, int index, int size);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user