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