diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 5348f40f4a..52f2a7782d 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -3606,10 +3606,10 @@ "bin_expansion", "trim_threshold_low", "trim_threshold_high", - "左侧收缩时检测图的底部收缩", + "左侧收缩时检测图的底部屏蔽高度", "左侧收缩时连续n像素低于bin_thresh" ], - "specialParams": [140, 2, 0, 0, -3, 10] + "specialParams": [140, 2, 0, 0, 3, 10] }, "BattleQuickFormationSkill1": { "algorithm": "JustReturn", diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj index 0346db2ab8..35a6b96cb1 100644 --- a/src/MaaCore/MaaCore.vcxproj +++ b/src/MaaCore/MaaCore.vcxproj @@ -297,6 +297,7 @@ + @@ -492,6 +493,7 @@ + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index b95e37c1a0..cd1a0cccde 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -1334,6 +1334,9 @@ Source\Task\Roguelike + + Source\Vision\Miscellaneous + @@ -1851,6 +1854,9 @@ Source\Task\Roguelike + + Source\Vision\Miscellaneous + diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp index e9076d8b9a..326d0f1b8d 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.cpp @@ -12,6 +12,7 @@ #include "UseSupportUnitTaskPlugin.h" #include "Utils/ImageIo.hpp" #include "Utils/Logger.hpp" +#include "Vision/Miscellaneous/OperNameAnalyzer.h" #include "Vision/MultiMatcher.h" #include "Vision/RegionOCRer.h" @@ -353,7 +354,7 @@ std::vector { const auto& ocr_replace = Task.get("CharsNameOcrReplace"); std::vector opers_result; - cv::Mat select, ocr, gray, bin; + cv::Mat select; for (int i = 0; i < 8; ++i) { std::string task_name = "BattleQuickFormation-OperNameFlag" + std::to_string(i); @@ -364,46 +365,14 @@ std::vector continue; } for (const auto& flag : multi.get_result()) { - auto roi = flag.rect.move(ocr_task->rect_move); - if (roi.x < 0) { - roi.x = 0; - roi.width = roi.width + roi.x; - } - if (roi.y < 0) { - roi.y = 0; - roi.height = roi.height + roi.y; - } - if (roi.x + roi.width > image.cols) { - roi.width = image.cols - roi.x; - } - if (roi.y + roi.height > image.rows) { - roi.height = image.rows - roi.y; - } - ocr = make_roi(image, 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, ocr_task->special_params[4], 0, 0); // 底部收缩排除白线 - int width = ocr_task->special_params[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); + OperNameAnalyzer region(image); region.set_task_info(ocr_task); - region.set_roi(asst::Rect(0, 0, ocr.cols, ocr.rows)); + region.set_roi(flag.rect.move(ocr_task->rect_move)); 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_bottom_line_height(ocr_task->special_params[4]); + region.set_width_threshold(ocr_task->special_params[5]); region.set_replace(ocr_replace->replace_map, ocr_replace->replace_full); region.set_use_raw(true); if (!region.analyze()) [[unlikely]] { diff --git a/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.cpp b/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.cpp new file mode 100644 index 0000000000..734fd52514 --- /dev/null +++ b/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.cpp @@ -0,0 +1,40 @@ +#include "OperNameAnalyzer.h" + +#include "Utils/NoWarningCV.h" +#include "Vision/RegionOCRer.h" + +asst::OperNameAnalyzer::ResultOpt asst::OperNameAnalyzer::analyze() const +{ + cv::Mat gray, bin; + cv::Mat ocr = make_roi(m_image, m_roi); + cv::cvtColor(ocr, gray, cv::COLOR_BGR2GRAY); + cv::inRange(gray, m_params.bin_threshold_lower, m_params.bin_threshold_upper, 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, -m_bottom_line_height, 0, 0); // 底部收缩排除白线 + int move = 0; + for (int r = bin.cols - m_width_threshold - 1; r >= 0; --r) { + if (!cv::hasNonZero(bin.colRange(r, r + m_width_threshold))) { // 左边界排除无文字区域 + move = r + m_width_threshold - 3; + ocr = ocr.adjustROI(0, 0, -move, 0); + break; + } + } + + RegionOCRer region(ocr); + region.set_params(m_params); + region.set_use_raw(true); + if (region.analyze()) { + m_result = region.get_result(); + m_result.rect.x += move; // 修正偏移 + m_result.rect = m_roi.move(m_result.rect); + return m_result; + } + + return std::nullopt; +} diff --git a/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.h b/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.h new file mode 100644 index 0000000000..37f7c27fcf --- /dev/null +++ b/src/MaaCore/Vision/Miscellaneous/OperNameAnalyzer.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include "Vision/Config/OCRerConfig.h" +#include "Vision/VisionHelper.h" +#include "Vision/OCRer.h" + +namespace asst +{ +class OperNameAnalyzer : public VisionHelper, public OCRerConfig +{ +public: + using Result = OCRer::Result; + using ResultOpt = std::optional; + +public: + using VisionHelper::VisionHelper; + virtual ~OperNameAnalyzer() override = default; + + ResultOpt analyze() const; + + void set_use_raw(bool use_raw) { m_use_raw = use_raw; } + + void set_bottom_line_height(int height) { m_bottom_line_height = height; } + + void set_width_threshold(int threshold) { m_width_threshold = threshold; } + + // FIXME: 老接口太难重构了,先弄个这玩意兼容下,后续慢慢全删掉 + const auto& get_result() const noexcept { return m_result; } + +protected: + using OCRerConfig::set_without_det; + + virtual void _set_roi(const Rect& roi) override { set_roi(roi); } + +private: + // FIXME: 老接口太难重构了,先弄个这玩意兼容下,后续慢慢全删掉 + mutable Result m_result; + bool m_use_raw = true; + int m_bottom_line_height = 3; // 底部线条高度 + int m_width_threshold = 5; // 宽度阈值 +}; +}; // namespace asst