diff --git a/resource/ocr_config.json b/resource/ocr_config.json new file mode 100644 index 0000000000..04bfe0c4fb --- /dev/null +++ b/resource/ocr_config.json @@ -0,0 +1,76 @@ +{ + "equivalence_classes": [ + [ + "あ", + "ぁ" + ], + [ + "い", + "ぃ" + ], + [ + "う", + "ぅ" + ], + [ + "え", + "ぇ" + ], + [ + "お", + "ぉ" + ], + [ + "つ", + "っ" + ], + [ + "や", + "ゃ" + ], + [ + "ゆ", + "ゅ" + ], + [ + "よ", + "ょ" + ], + [ + "ア", + "ァ" + ], + [ + "イ", + "ィ" + ], + [ + "ウ", + "ゥ" + ], + [ + "エ", + "ェ" + ], + [ + "オ", + "ォ" + ], + [ + "ツ", + "ッ" + ], + [ + "ヤ", + "ャ" + ], + [ + "ユ", + "ュ" + ], + [ + "ヨ", + "ョ" + ] + ] +} \ No newline at end of file diff --git a/src/MaaCore/Config/Miscellaneous/OcrConfig.cpp b/src/MaaCore/Config/Miscellaneous/OcrConfig.cpp new file mode 100644 index 0000000000..251c7a475d --- /dev/null +++ b/src/MaaCore/Config/Miscellaneous/OcrConfig.cpp @@ -0,0 +1,28 @@ +#include "OcrConfig.h" + +#include + +#include "Utils/Logger.hpp" + +std::string asst::OcrConfig::process_equivalence_class(const std::string& str) +{ + std::string result = str; + for (const auto& eq_class : m_eq_classes) { + ranges::for_each(eq_class.begin() + 1, eq_class.end(), [&](const std::string& elem) { + utils::string_replace_all_in_place(result, elem, eq_class.front()); + }); + } + return result; +} + +bool asst::OcrConfig::parse(const json::value& json) +{ + for (const json::value& eq_class : json.at("equivalence_classes").as_array()) { + equivalence_class eq_class_tmp; + for (const json::value& eq_element : eq_class.as_array()) { + eq_class_tmp.emplace_back(eq_element.as_string()); + } + m_eq_classes.emplace_back(std::move(eq_class_tmp)); + } + return true; +} diff --git a/src/MaaCore/Config/Miscellaneous/OcrConfig.h b/src/MaaCore/Config/Miscellaneous/OcrConfig.h new file mode 100644 index 0000000000..e4aed6f819 --- /dev/null +++ b/src/MaaCore/Config/Miscellaneous/OcrConfig.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Config/AbstractConfig.h" + +#include "Utils/Ranges.hpp" +#include +#include +#include +#include +#include + +#include "Common/AsstTypes.h" + +namespace asst +{ + class OcrConfig final : public SingletonHolder, public AbstractConfig + { + public: + virtual ~OcrConfig() override = default; + + std::string process_equivalence_class(const std::string& str); + + protected: + virtual bool parse(const json::value& json) override; + + using equivalence_class = std::vector; + + std::vector m_eq_classes; + }; + inline static auto& OcrData = OcrConfig::get_instance(); + +} // namespace asst diff --git a/src/MaaCore/Config/ResourceLoader.cpp b/src/MaaCore/Config/ResourceLoader.cpp index fb265bb74b..7203c27f65 100644 --- a/src/MaaCore/Config/ResourceLoader.cpp +++ b/src/MaaCore/Config/ResourceLoader.cpp @@ -13,6 +13,7 @@ #include "Miscellaneous/RecruitConfig.h" #include "Miscellaneous/StageDropsConfig.h" #include "Miscellaneous/TilePack.h" +#include "Miscellaneous/OcrConfig.h" #include "Roguelike/RoguelikeCopilotConfig.h" #include "Roguelike/RoguelikeRecruitConfig.h" #include "Roguelike/RoguelikeShoppingConfig.h" @@ -64,6 +65,7 @@ bool asst::ResourceLoader::load(const std::filesystem::path& path) LoadResourceAndCheckRet(RoguelikeRecruitConfig, "roguelike"_p / "recruitment.json"_p); LoadResourceAndCheckRet(RoguelikeShoppingConfig, "roguelike"_p / "shopping.json"_p); LoadResourceAndCheckRet(BattleDataConfig, "battle_data.json"_p); + LoadResourceAndCheckRet(OcrConfig, "ocr_config.json"_p); /* load resource with json and template files*/ LoadResourceWithTemplAndCheckRet(TaskData, "tasks.json"_p, "template"_p); diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj index 763116e97b..519770df00 100644 --- a/src/MaaCore/MaaCore.vcxproj +++ b/src/MaaCore/MaaCore.vcxproj @@ -29,6 +29,7 @@ + @@ -159,6 +160,7 @@ + diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index a6c1c8f235..5aea742d34 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -507,6 +507,9 @@ 源文件\Task\Reclamation + + 源文件\Config\Miscellaneous + @@ -836,5 +839,8 @@ 源文件\Task\Reclamation + + 源文件\Config\Miscellaneous + \ No newline at end of file diff --git a/src/MaaCore/Vision/OcrImageAnalyzer.cpp b/src/MaaCore/Vision/OcrImageAnalyzer.cpp index 120261f822..d0c311d138 100644 --- a/src/MaaCore/Vision/OcrImageAnalyzer.cpp +++ b/src/MaaCore/Vision/OcrImageAnalyzer.cpp @@ -4,6 +4,7 @@ #include #include "Config/Miscellaneous/OcrPack.h" +#include "Config/Miscellaneous/OcrConfig.h" #include "Config/TaskData.h" #include "Utils/Logger.hpp" @@ -16,7 +17,7 @@ bool asst::OcrImageAnalyzer::analyze() std::vector preds_vec; preds_vec.emplace_back([](TextRect& tr) -> bool { - tr.text = equivalent_class_preprocess(tr.text); + tr.text = OcrData.process_equivalence_class(tr.text); return true; }); @@ -98,7 +99,7 @@ void asst::OcrImageAnalyzer::set_use_cache(bool is_use) noexcept void asst::OcrImageAnalyzer::set_required(std::vector required) noexcept { - ranges::for_each(required, [](std::string& str) { str = equivalent_class_preprocess(str); }); + ranges::for_each(required, [](std::string& str) { str = OcrData.process_equivalence_class(str); }); m_required = std::move(required); } @@ -106,8 +107,8 @@ void asst::OcrImageAnalyzer::set_replace(const std::unordered_map& asst::OcrImageAnalyzer::get_result() noexcept return m_ocr_result; } -std::string asst::OcrImageAnalyzer::equivalent_class_preprocess(const std::string& in) -{ - using equivalent_class = std::vector; - static const std::vector classes { - // hiragana - { "あ", "ぁ" }, - { "い", "ぃ" }, - { "う", "ぅ" }, - { "え", "ぇ" }, - { "お", "ぉ" }, - { "つ", "っ" }, - { "や", "ゃ" }, - { "ゆ", "ゅ" }, - { "よ", "ょ" }, - { "わ", "ゎ" }, - // katakana - { "ア", "ァ" }, - { "イ", "ィ" }, - { "ウ", "ゥ" }, - { "エ", "ェ" }, - { "オ", "ォ" }, - { "ツ", "ッ" }, - { "ヤ", "ャ" }, - { "ユ", "ュ" }, - { "ヨ", "ョ" }, - { "ワ", "ヮ" }, - }; // TODO: store this into a file - - auto result = in; - for (const auto& cls : classes) { - // replace the elements in group into the first one - ranges::for_each(cls.begin() + 1, cls.end(), - [&](const std::string& elem) { utils::string_replace_all_in_place(result, elem, cls.front()); }); - } - - return result; -} - void asst::OcrImageAnalyzer::set_task_info(std::shared_ptr task_ptr) { set_task_info(*std::dynamic_pointer_cast(task_ptr)); diff --git a/src/MaaCore/Vision/OcrImageAnalyzer.h b/src/MaaCore/Vision/OcrImageAnalyzer.h index 139a3ac97a..90e1f8037a 100644 --- a/src/MaaCore/Vision/OcrImageAnalyzer.h +++ b/src/MaaCore/Vision/OcrImageAnalyzer.h @@ -38,9 +38,6 @@ namespace asst virtual const std::vector& get_result() const noexcept; virtual std::vector& get_result() noexcept; - // normalize similar characters into the same one - static std::string equivalent_class_preprocess(const std::string& in); - protected: virtual void set_task_info(OcrTaskInfo task_info) noexcept;