perf: update StageDropsImageAnalyzer

This commit is contained in:
Horror Proton
2023-01-05 10:24:23 +08:00
committed by MistEO
parent ef646ff0bb
commit bf02194531
3 changed files with 101 additions and 10 deletions

View File

@@ -6598,8 +6598,8 @@
22
],
"maskRange": [
150,
255
0,
110
]
},
"NumberOcrReplace": {

View File

@@ -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());
}

View File

@@ -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);