From a2c49d2febb4f72f70fdb542f6f9528fd72fa934 Mon Sep 17 00:00:00 2001 From: MistEO Date: Fri, 17 Dec 2021 21:20:40 +0800 Subject: [PATCH] =?UTF-8?q?feat.=E6=9A=82=E6=97=B6=E5=BA=9F=E5=BC=83?= =?UTF-8?q?=E7=99=BE=E5=BA=A6=20OCR=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/config.json | 14 +++--- src/MeoAssistant/AipOcr.cpp | 64 ++++++++++++++++++--------- src/MeoAssistant/AipOcr.h | 9 ++-- src/MeoAssistant/Assistant.cpp | 4 +- src/MeoAssistant/GeneralConfiger.cpp | 28 +++++++----- src/MeoAssistant/GeneralConfiger.h | 28 ++++++++---- src/MeoAssistant/OcrImageAnalyzer.cpp | 22 +++++++-- src/MeoAssistant/PenguinUploader.cpp | 6 +-- src/MeoAssistant/ProcessTask.cpp | 12 ++--- src/MeoAssistant/Resource.cpp | 2 +- 10 files changed, 123 insertions(+), 66 deletions(-) diff --git a/resource/config.json b/resource/config.json index 63ed461ae9..93a1df5696 100644 --- a/resource/config.json +++ b/resource/config.json @@ -5,12 +5,6 @@ "connectType_Doc": "连接类型:0-连接电脑上的模拟器;1-连接自定义端口,请手动修改'emulator.Custom'中的相关字段。默认0", "taskDelay": 2000, "taskDelay_Doc": "识别的延迟:越快识别频率越快,但会增加CPU消耗。单位毫秒,默认2000", - "printWindow": false, - "printWindow_Doc": "截图功能:开启后每次结算界面会截图到screenshot目录下。true-开启,false-关闭,默认false", - "penguinReport": true, - "penguinReport_Doc": "企鹅数据汇报:每次到结算界面,是否汇报掉落数据至企鹅数据 https://penguin-stats.cn/。true-开启,false-关闭,默认true", - "penguinReportCmdLine": "curl -H \"Content-Type: application/json\" -d \"[body]\" \"https://penguin-stats.cn/PenguinStats/api/v2/report\" [extra]", - "penguinReportCmdLine_Doc": "企鹅数据汇报的命令,想打印详细信息可以尝试添加 -v -i", "controlDelayRange": [ 0, 0 @@ -19,7 +13,13 @@ "adbExtraSwipeDist": 50, "adbExtraSwipeDist_Doc": "额外的滑动距离:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来", "adbExtraSwipeDuration": 1000, - "adbExtraSwipeDuration_Doc": "额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能" + "adbExtraSwipeDuration_Doc": "额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能", + "penguinReport": { + "Doc": "企鹅数据汇报:每次到结算界面,汇报掉落数据至企鹅数据 https://penguin-stats.cn/。true-开启,false-关闭,默认true", + "enable": true, + "cmdFormat": "curl -H \"Content-Type: application/json\" -d \"[body]\" \"https://penguin-stats.cn/PenguinStats/api/v2/report\" [extra]", + "cmdFormat_Doc": "命令格式,想打印详细信息可以尝试添加 -v -i" + } }, "emulator_Doc": "下面的和模拟器窗口捕获逻辑有关,不需要修改", "emulator": { diff --git a/src/MeoAssistant/AipOcr.cpp b/src/MeoAssistant/AipOcr.cpp index 1486ad84b1..f0db597b0f 100644 --- a/src/MeoAssistant/AipOcr.cpp +++ b/src/MeoAssistant/AipOcr.cpp @@ -8,6 +8,7 @@ #include "AsstUtils.hpp" #include "Logger.hpp" +#include "Resource.h" bool asst::AipOcr::request_access_token(const std::string& client_id, const std::string& client_secret) { @@ -16,7 +17,7 @@ bool asst::AipOcr::request_access_token(const std::string& client_id, const std: m_access_token.clear(); std::string_view cmd_fmt = - R"(curl -k \"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s\")"; + R"(curl -s -k "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s")"; constexpr int cmd_len = 256; char cmd[cmd_len] = { 0 }; @@ -42,22 +43,43 @@ bool asst::AipOcr::request_access_token(const std::string& client_id, const std: return true; } -std::vector asst::AipOcr::request_ocr_accurate(const cv::Mat& image, const TextRectProc& pred) +bool asst::AipOcr::request_ocr_general(const cv::Mat& image, std::vector& out_result, const TextRectProc& pred) { LogTraceFunction; - std::string_view cmd_fmt = - R"(curl -k \"https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%s\" --data \"image=%s\" -H \"Content-Type:application/x-www-form-urlencoded\")"; - - return request_ocr_and_parse(cmd_fmt, image, pred); -} - -std::vector asst::AipOcr::request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, const TextRectProc& pred) -{ if (m_access_token.empty()) { - return std::vector(); + auto& cfg = Resrc.cfg().get_options().aip_ocr; + request_access_token(cfg.client_id, cfg.client_secret); } + std::string_view cmd_fmt = + R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/general?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")"; + + return request_ocr_and_parse(cmd_fmt, image, out_result, pred); +} + +bool asst::AipOcr::request_ocr_accurate(const cv::Mat& image, std::vector& out_result, const TextRectProc& pred) +{ + LogTraceFunction; + + if (m_access_token.empty()) { + auto& cfg = Resrc.cfg().get_options().aip_ocr; + request_access_token(cfg.client_id, cfg.client_secret); + } + + std::string_view cmd_fmt = + R"(curl -s -k "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=%s" --data "image=%s" -H "Content-Type:application/x-www-form-urlencoded")"; + + return request_ocr_and_parse(cmd_fmt, image, out_result, pred); +} + +bool asst::AipOcr::request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, std::vector& out_result, const TextRectProc& pred) +{ + if (m_access_token.empty()) { + return false; + } + // CreateProcess 最大只能接受 32767 chars,一张图片随便就超过了 + // 这个功能暂时没法用,得集成下 libcurl 或者别的 std::vector buf; cv::imencode(".png", image, buf); auto* enc_msg = reinterpret_cast(buf.data()); @@ -66,7 +88,7 @@ std::vector asst::AipOcr::request_ocr_and_parse(std::string_view size_t cmd_len = encoded.size() + cmd_fmt.size() + m_access_token.size(); char* cmd = new char[cmd_len]; memset(cmd, 0, cmd_len); - sprintf_s(cmd, cmd_len, cmd_fmt.data(), encoded.c_str(), m_access_token.c_str()); + sprintf_s(cmd, cmd_len, cmd_fmt.data(), m_access_token.c_str(), encoded.c_str()); Log.trace("call cmd:", cmd); std::string response = utils::callcmd(cmd); @@ -75,21 +97,21 @@ std::vector asst::AipOcr::request_ocr_and_parse(std::string_view auto parse_res = json::parse(response); if (!parse_res) { - return std::vector(); + return false; } try { auto json = parse_res.value(); - return parse_response(json); + return parse_response(json, out_result, pred); } catch (...) { - return std::vector(); + return false; } } -std::vector asst::AipOcr::parse_response(const json::value& json, const TextRectProc& pred) +bool asst::AipOcr::parse_response(const json::value& json, std::vector& out_result, const TextRectProc& pred) { if (!json.exist("words_result")) { - return std::vector(); + return false; } std::vector result; @@ -115,7 +137,9 @@ std::vector asst::AipOcr::parse_response(const json::value& json } } - Log.trace("OcrPack::recognize | raw : ", log_str_raw); - Log.trace("OcrPack::recognize | proc : ", log_str_proc); - return result; + Log.trace("AipOcr::parse_response | raw : ", log_str_raw); + Log.trace("AipOcr::parse_response | proc : ", log_str_proc); + + out_result = result; + return true; } diff --git a/src/MeoAssistant/AipOcr.h b/src/MeoAssistant/AipOcr.h index fec7616b9b..284a9d7c28 100644 --- a/src/MeoAssistant/AipOcr.h +++ b/src/MeoAssistant/AipOcr.h @@ -20,22 +20,23 @@ namespace asst public: ~AipOcr() = default; - AipOcr& get_instance() + static AipOcr& get_instance() { static AipOcr unique_instance; return unique_instance; } bool request_access_token(const std::string& client_id, const std::string& client_secret); - std::vector request_ocr_accurate(const cv::Mat& image, const TextRectProc& pred = nullptr); + bool request_ocr_general(const cv::Mat& image, std::vector& out_result, const TextRectProc& pred = nullptr); + bool request_ocr_accurate(const cv::Mat& image, std::vector& out_result, const TextRectProc& pred = nullptr); private: AipOcr() = default; AipOcr(const AipOcr&) = default; AipOcr(AipOcr&&) noexcept = default; - std::vector request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, const TextRectProc& pred = nullptr); - std::vector parse_response(const json::value& json, const TextRectProc& pred = nullptr); + bool request_ocr_and_parse(std::string_view cmd_fmt, const cv::Mat& image, std::vector& out_result, const TextRectProc& pred = nullptr); + bool parse_response(const json::value& json, std::vector& out_result, const TextRectProc& pred = nullptr); std::string m_access_token; }; diff --git a/src/MeoAssistant/Assistant.cpp b/src/MeoAssistant/Assistant.cpp index 5d53f734fd..1869f4ab2a 100644 --- a/src/MeoAssistant/Assistant.cpp +++ b/src/MeoAssistant/Assistant.cpp @@ -402,10 +402,10 @@ void asst::Assistant::set_penguin_id(const std::string& id) { auto& opt = Resrc.cfg().get_options(); if (id.empty()) { - opt.penguin_report_extra_param.clear(); + opt.penguin_report.extra_param.clear(); } else { - opt.penguin_report_extra_param = "-H \"authorization: PenguinID " + id + "\""; + opt.penguin_report.extra_param = "-H \"authorization: PenguinID " + id + "\""; } } diff --git a/src/MeoAssistant/GeneralConfiger.cpp b/src/MeoAssistant/GeneralConfiger.cpp index 5931ae1193..a39dda4cce 100644 --- a/src/MeoAssistant/GeneralConfiger.cpp +++ b/src/MeoAssistant/GeneralConfiger.cpp @@ -6,22 +6,28 @@ bool asst::GeneralConfiger::parse(const json::value& json) { m_version = json.at("version").as_string(); - const json::value& options_json = json.at("options"); { + const json::value& options_json = json.at("options"); m_options.connect_type = static_cast(options_json.at("connectType").as_integer()); m_options.task_delay = options_json.at("taskDelay").as_integer(); m_options.control_delay_lower = options_json.at("controlDelayRange")[0].as_integer(); m_options.control_delay_upper = options_json.at("controlDelayRange")[1].as_integer(); - m_options.print_window = options_json.at("printWindow").as_boolean(); - m_options.penguin_report = options_json.at("penguinReport").as_boolean(); - m_options.penguin_report_cmd_line = options_json.at("penguinReportCmdLine").as_string(); - m_options.penguin_report_server = options_json.get("penguinReportServer", "CN"); - - //m_options.ocr_gpu_index = options_json.get("ocrGpuIndex", -1); - //m_options.ocr_thread_number = options_json.at("ocrThreadNumber").as_integer(); - + //m_options.print_window = options_json.at("printWindow").as_boolean(); m_options.adb_extra_swipe_dist = options_json.get("adbExtraSwipeDist", 100); - m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1); + m_options.adb_extra_swipe_duration = options_json.get("adbExtraSwipeDuration", -1); + + auto& penguin_report = options_json.at("penguinReport"); + m_options.penguin_report.enable = penguin_report.get("enable", true); + m_options.penguin_report.cmd_format = penguin_report.get("cmdFormat", std::string()); + m_options.penguin_report.server = penguin_report.get("server", "CN"); + + if (options_json.exist("aipOcr")) { + auto& aip_ocr = options_json.at("aipOcr"); + m_options.aip_ocr.enable = aip_ocr.get("enable", false); + m_options.aip_ocr.accurate = aip_ocr.get("accurate", false); + m_options.aip_ocr.client_id = aip_ocr.get("clientId", std::string()); + m_options.aip_ocr.client_secret = aip_ocr.get("clientSerect", std::string()); + } } for (const auto& [name, emulator_json] : json.at("emulator").as_object()) { @@ -52,4 +58,4 @@ bool asst::GeneralConfiger::parse(const json::value& json) } return true; -} +} diff --git a/src/MeoAssistant/GeneralConfiger.h b/src/MeoAssistant/GeneralConfiger.h index d9b6a8ec8a..73573f894f 100644 --- a/src/MeoAssistant/GeneralConfiger.h +++ b/src/MeoAssistant/GeneralConfiger.h @@ -14,6 +14,22 @@ namespace asst { Emulator, Custom + }; + + struct AipOcrCfg // 百度 OCR API 的配置 + { + bool enable = false; + bool accurate = false; // 是否使用高精度识别 + std::string client_id; + std::string client_secret; + }; + + struct PenguinReportCfg // 企鹅物流数据汇报 的配置 + { + bool enable = false; + std::string cmd_format; // 命令格式 + std::string extra_param; // 额外参数 + std::string server; // 上传参数中"server"字段,"CN", "US", "JP" and "KR". }; struct Options @@ -22,15 +38,11 @@ namespace asst int task_delay = 0; // 任务间延时:越快操作越快,但会增加CPU消耗 int control_delay_lower = 0; // 点击随机延时下限:每次点击操作会进行随机延时 int control_delay_upper = 0; // 点击随机延时上限:每次点击操作会进行随机延时 - bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下 - bool penguin_report = false; // 企鹅数据汇报:每次到结算界面,是否汇报掉落数据至企鹅数据 https://penguin-stats.cn/ - std::string penguin_report_cmd_line; // 企鹅数据汇报的命令 - std::string penguin_report_extra_param; // 企鹅数据汇报的命令 - std::string penguin_report_server; // 企鹅数据汇报接口"server"字段,"CN", "US", "JP" and "KR". - //int ocr_gpu_index = -1; // OcrLite使用GPU编号,-1(使用CPU)/0(使用GPU0)/1(使用GPU1)/... - //int ocr_thread_number = 0; // OcrLite线程数量 + //bool print_window = false; // 截图功能:开启后每次结算界面会截图到screenshot目录下 int adb_extra_swipe_dist = 0; // 额外的滑动距离:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来 - int adb_extra_swipe_duration = -1; // 额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能 + int adb_extra_swipe_duration = -1; // 额外的滑动持续时间:adb有bug,同样的参数,偶尔会划得非常远。额外做一个短程滑动,把之前的停下来。若小于0,则关闭额外滑动功能 + PenguinReportCfg penguin_report; // 企鹅数据汇报:每次到结算界面,汇报掉落数据至企鹅数据 https://penguin-stats.cn/ + AipOcrCfg aip_ocr; // 百度 OCR API 的配置 }; class GeneralConfiger : public AbstractConfiger diff --git a/src/MeoAssistant/OcrImageAnalyzer.cpp b/src/MeoAssistant/OcrImageAnalyzer.cpp index dde277210a..0fc6811bc8 100644 --- a/src/MeoAssistant/OcrImageAnalyzer.cpp +++ b/src/MeoAssistant/OcrImageAnalyzer.cpp @@ -3,7 +3,8 @@ #include #include "Logger.hpp" -#include "Resource.h" +#include "Resource.h" +#include "AipOcr.h" bool asst::OcrImageAnalyzer::analyze() { @@ -48,8 +49,21 @@ bool asst::OcrImageAnalyzer::analyze() } } return true; - }; - m_ocr_result = Resrc.ocr().recognize(m_image, m_roi, all_pred, m_without_det); + }; + + auto& aip_ocr = Resrc.cfg().get_options().aip_ocr; + bool need_local = true; + if (aip_ocr.enable) { + if (aip_ocr.accurate) { + need_local = !AipOcr::get_instance().request_ocr_accurate(m_image, m_ocr_result, all_pred); + } + else { + need_local = !AipOcr::get_instance().request_ocr_general(m_image, m_ocr_result, all_pred); + } + } + if (need_local) { + m_ocr_result = Resrc.ocr().recognize(m_image, m_roi, all_pred, m_without_det); + } //log.trace("ocr result", m_ocr_result); return !m_ocr_result.empty(); -} +} diff --git a/src/MeoAssistant/PenguinUploader.cpp b/src/MeoAssistant/PenguinUploader.cpp index b21a4a03bd..75dd39365e 100644 --- a/src/MeoAssistant/PenguinUploader.cpp +++ b/src/MeoAssistant/PenguinUploader.cpp @@ -26,7 +26,7 @@ std::string asst::PenguinUploader::cvt_json(const std::string& rec_res) // Doc: https://developer.penguin-stats.io/public-api/api-v2-instruction/report-api json::value body; auto& opt = Resrc.cfg().get_options(); - body["server"] = opt.penguin_report_server; + body["server"] = opt.penguin_report.server; body["stageId"] = rec["stage"]["stageId"]; // To fix: https://github.com/MistEO/MeoAssistantArknights/issues/40 body["drops"] = json::array(); @@ -45,8 +45,8 @@ bool asst::PenguinUploader::request_penguin(const std::string& body) { auto& opt = Resrc.cfg().get_options(); std::string body_escape = utils::string_replace_all(body, "\"", "\\\""); - std::string cmd_line = utils::string_replace_all(opt.penguin_report_cmd_line, "[body]", body_escape); - cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report_extra_param); + std::string cmd_line = utils::string_replace_all(opt.penguin_report.cmd_format, "[body]", body_escape); + cmd_line = utils::string_replace_all(cmd_line, "[extra]", opt.penguin_report.extra_param); Log.trace("request_penguin |", cmd_line); diff --git a/src/MeoAssistant/ProcessTask.cpp b/src/MeoAssistant/ProcessTask.cpp index 9304882410..536a96c6a0 100644 --- a/src/MeoAssistant/ProcessTask.cpp +++ b/src/MeoAssistant/ProcessTask.cpp @@ -133,11 +133,11 @@ bool ProcessTask::_run() m_callback(AsstMsg::StageDrops, json::parse(res).value(), m_callback_arg); auto& opt = Resrc.cfg().get_options(); - if (opt.print_window) { - //static const std::string dirname = utils::get_cur_dir() + "screenshot\\"; - //save_image(image, dirname); - } - if (opt.penguin_report) { + //if (opt.print_window) { + // //static const std::string dirname = utils::get_cur_dir() + "screenshot\\"; + // //save_image(image, dirname); + //} + if (opt.penguin_report.enable) { PenguinUploader::upload(res); } } break; @@ -208,4 +208,4 @@ void asst::ProcessTask::exec_swipe_task(ProcessTaskAction action) default: // 走不到这里,TODO 报个错 break; } -} \ No newline at end of file +} diff --git a/src/MeoAssistant/Resource.cpp b/src/MeoAssistant/Resource.cpp index e15bc2a6aa..f0a05a630d 100644 --- a/src/MeoAssistant/Resource.cpp +++ b/src/MeoAssistant/Resource.cpp @@ -71,7 +71,7 @@ bool asst::Resource::load(const std::string& dir) return false; } /* 加载企鹅数据识别库所需要的资源 */ - m_penguin_pack_unique_ins.set_language(opt.penguin_report_server); + m_penguin_pack_unique_ins.set_language(opt.penguin_report.server); if (!m_penguin_pack_unique_ins.load(dir + PenguinResourceFilename)) { m_last_error = m_penguin_pack_unique_ins.get_last_error(); return false;