初始化公开招募Tags的读取和识别

This commit is contained in:
MistEO
2021-07-28 21:44:59 +08:00
parent 8cb23c48cf
commit 34f20ed129
17 changed files with 285 additions and 66 deletions

View File

@@ -27,7 +27,9 @@
<ClInclude Include="include\Configer.h" />
<ClInclude Include="include\Identify.h" />
<ClInclude Include="include\Logger.hpp" />
<ClInclude Include="include\RecruitConfiger.h" />
<ClInclude Include="include\Updater.h" />
<ClInclude Include="include\Version.h" />
<ClInclude Include="include\WinMacro.h" />
</ItemGroup>
<ItemGroup>
@@ -35,11 +37,12 @@
<ClCompile Include="src\AsstCaller.cpp" />
<ClCompile Include="src\Configer.cpp" />
<ClCompile Include="src\Identify.cpp" />
<ClCompile Include="src\RecruitConfiger.cpp" />
<ClCompile Include="src\Updater.cpp" />
<ClCompile Include="src\WinMacro.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="..\resource\akhr.json" />
<None Include="..\resource\operInfo.json" />
<None Include="..\resource\config.json" />
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@@ -45,6 +45,12 @@
<ClInclude Include="include\AsstPort.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\RecruitConfiger.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\Version.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Configer.cpp">
@@ -65,12 +71,15 @@
<ClCompile Include="src\Updater.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\RecruitConfiger.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\resource\config.json">
<Filter>资源文件</Filter>
</None>
<None Include="..\resource\akhr.json">
<None Include="..\resource\operInfo.json">
<Filter>资源文件</Filter>
</None>
</ItemGroup>

View File

@@ -7,9 +7,10 @@
#include <optional>
#include <unordered_map>
#include "AsstPort.h"
#include "AsstDef.h"
#include "Configer.h"
#include "AsstPort.h"
#include "RecruitConfiger.h"
namespace cv {
class Mat;
@@ -37,6 +38,8 @@ namespace asst {
// for debug
bool find_text_and_click(const std::string& text, bool block = true);
// for debug
std::vector<std::string> find_tags();
private:
static void working_proc(Assistance* pThis);
@@ -58,6 +61,7 @@ namespace asst {
std::vector<std::string> m_next_tasks;
Configer m_configer;
RecruitConfiger m_recruit_configer;
};
}

View File

@@ -46,13 +46,37 @@ namespace asst {
return buff;
}
static std::wstring Utf8ToGBK(const std::string& src)
static std::string GbkToUtf8(const std::string & gbk_str)
{
wchar_t* wbuff = NULL;
size_t len = (src.size() + 1) * 2;
wbuff = new wchar_t[len];
memset(wbuff, 0, len);
::MultiByteToWideChar(CP_UTF8, 0, src.c_str(), -1, wbuff, len);
return wbuff;
const char * src_str = gbk_str.c_str();
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
std::string strTemp = str;
if (wstr) delete[] wstr;
if (str) delete[] str;
return strTemp;
}
static std::string Utf8ToGbk(const std::string & utf8_str)
{
const char* src_str = utf8_str.c_str();
int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0);
wchar_t* wszGBK = new wchar_t[len + 1];
memset(wszGBK, 0, len * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len);
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
char* szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
std::string strTemp(szGBK);
if (wszGBK) delete[] wszGBK;
if (szGBK) delete[] szGBK;
return strTemp;
}
}

View File

@@ -2,13 +2,12 @@
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <ostream>
namespace asst {
const static std::string Version = "release.beta.04";
enum class HandleType
{
Window = 1,
@@ -101,10 +100,17 @@ namespace asst {
struct TextArea {
TextArea() = default;
TextArea(const TextArea&) = default;
TextArea(TextArea&&) = default;
template<typename TextArg, typename ...RectArgs>
TextArea(TextArg&& text_arg, RectArgs &&... rect_args)
: text(std::forward<TextArg>(text_arg)),
rect(std::forward<RectArgs>(rect_args)...) {}
rect(std::forward<RectArgs>(rect_args)...) {
static_assert(std::is_constructible<std::string, TextArg>::value,
"Parameter can't be used to construct a std::string");
static_assert(std::is_constructible<asst::Rect, RectArgs...>::value,
"Parameter can't be used to construct a asst::Rect");
}
std::string text;
Rect rect;
};
@@ -165,4 +171,15 @@ namespace asst {
int ocr_gpu_index = -1; // OcrLite使用GPU编号-1(使用CPU)/0(使用GPU0)/1(使用GPU1)/...
int ocr_thread_number = 0; // OcrLite线程数量
};
// 干员信息
struct OperInfo {
std::string name;
std::string type;
int level = 0;
std::string sex;
std::unordered_set<std::string> tags;
bool hidden = false;
std::string name_en;
};
}

View File

@@ -14,18 +14,18 @@ namespace asst {
Configer() = default;
~Configer() = default;
Configer(const Configer& rhs);
Configer(Configer&& rhs) noexcept;
Configer(const Configer& rhs) = default;
Configer(Configer&& rhs) noexcept = default;
bool reload(const std::string& filename);
bool load(const std::string& filename);
bool set_param(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> get_param(const std::string& type, const std::string& param);
void clear_exec_times();
Configer& operator=(const Configer& rhs);
Configer& operator=(Configer&& rhs) noexcept;
Configer& operator=(const Configer& rhs) = default;
Configer& operator=(Configer&& rhs) noexcept = default;
constexpr static int DefaultWindowWidth = 1280;
constexpr static int DefaultWindowHeight = 720;

View File

@@ -1,6 +1,7 @@
#pragma once
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <tuple>
#include <optional>
@@ -34,6 +35,8 @@ namespace asst {
void set_ocr_param(int gpu_index, int thread_number);
bool ocr_init_models(const std::string& dir);
std::optional<Rect> find_text(const cv::Mat& mat, const std::string& text);
std::vector<TextArea> find_text(const cv::Mat& mat, const std::vector<std::string>& texts);
std::vector<TextArea> find_text(const cv::Mat& mat, const std::unordered_set<std::string>& texts);
private:
cv::Mat image_2_hist(const cv::Mat& src);

View File

@@ -6,6 +6,7 @@
#include "AsstAux.h"
#include "AsstPort.h"
#include "Version.h"
namespace asst {
class MEOAPI_PORT Logger {
@@ -41,7 +42,7 @@ namespace asst {
Logger() {
log_trace("-----------------------------");
log_trace("MeoAssistance Process Start");
log_trace("Version", Version);
log_trace("Version", asst::Version);
log_trace("Build DataTime", __DATE__, __TIME__);
log_trace("Working Path", GetCurrentDir());
log_trace("Resource Path", GetResourceDir());

View File

@@ -0,0 +1,34 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_set>
#include "AsstDef.h"
namespace asst {
class RecruitConfiger
{
public:
RecruitConfiger() = default;
~RecruitConfiger() = default;
RecruitConfiger(const RecruitConfiger& rhs) = default;
RecruitConfiger(RecruitConfiger&& rhs) noexcept = default;
bool load(const std::string& filename);
RecruitConfiger& operator=(const RecruitConfiger& rhs) = default;
RecruitConfiger& operator=(RecruitConfiger&& rhs) noexcept = default;
std::unordered_set<std::string> m_all_tags;
std::unordered_set<std::string> m_all_types;
std::vector<OperInfo> m_opers;
private:
};
}

View File

@@ -0,0 +1,5 @@
#pragma once
namespace asst {
constexpr static const char* Version = "release.beta.04";
}

View File

@@ -17,7 +17,8 @@ Assistance::Assistance()
{
DebugTraceFunction;
m_configer.reload(GetResourceDir() + "config.json");
m_configer.load(GetResourceDir() + "config.json");
m_recruit_configer.load(GetResourceDir() + "operInfo.json");
m_pIder = std::make_shared<Identify>();
for (auto&& [name, info] : m_configer.m_tasks)
@@ -179,22 +180,40 @@ bool asst::Assistance::print_window(const std::string& filename, bool block)
bool asst::Assistance::find_text_and_click(const std::string& text, bool block)
{
DebugTraceFunction;
DebugTrace("find_text_and_click |", text, block ? "block" : "non block");
DebugTrace("find_text_and_click |", Utf8ToGbk(text), block ? "block" : "non block");
std::unique_lock<std::mutex> lock;
if (block) { // 外部调用
lock = std::unique_lock<std::mutex>(m_mutex);
}
auto&& image = get_format_image();
const auto& image = get_format_image();
auto&& result = m_pIder->find_text(image, text);
if (!result) {
DebugTrace("Cannot found", text);
DebugTrace("Cannot found", Utf8ToGbk(text));
return false;
}
set_control_scale(image.cols, image.rows);
return m_pCtrl->click(result.value());
}
std::vector<std::string> asst::Assistance::find_tags()
{
DebugTraceFunction;
const auto& image = get_format_image();
auto&& result = m_pIder->find_text(image, m_recruit_configer.m_all_tags);
std::vector<std::string> dst;
std::string dst_str;
for (auto&& t_a : result) {
dst.emplace_back(t_a.text);
dst_str += t_a.text + ", ";
}
DebugTrace(Utf8ToGbk(dst_str));
return dst;
}
void Assistance::working_proc(Assistance* pThis)

View File

@@ -9,26 +9,26 @@
using namespace asst;
Configer::Configer(const Configer& rhs)
: m_version(rhs.m_version),
m_options(rhs.m_options),
m_tasks(rhs.m_tasks),
m_handles(rhs.m_handles)
{
}
//Configer::Configer(const Configer& rhs)
// : m_version(rhs.m_version),
// m_options(rhs.m_options),
// m_tasks(rhs.m_tasks),
// m_handles(rhs.m_handles)
//{
//}
//
//Configer::Configer(Configer&& rhs) noexcept
// : m_version(std::move(rhs.m_version)),
// m_options(std::move(rhs.m_options)),
// m_tasks(std::move(rhs.m_tasks)),
// m_handles(std::move(rhs.m_handles))
//{
//}
Configer::Configer(Configer&& rhs) noexcept
: m_version(std::move(rhs.m_version)),
m_options(std::move(rhs.m_options)),
m_tasks(std::move(rhs.m_tasks)),
m_handles(std::move(rhs.m_handles))
{
}
bool Configer::reload(const std::string& filename)
bool Configer::load(const std::string& filename)
{
DebugTraceFunction;
DebugTrace("Configer::reload | ", filename);
DebugTrace("Configer::load | ", filename);
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
@@ -63,7 +63,7 @@ bool Configer::reload(const std::string& filename)
temp.m_options.ocr_gpu_index = options_obj["ocrGpuIndex"].as_integer();
temp.m_options.ocr_thread_number = options_obj["ocrThreadNumber"].as_integer();
}
DebugTrace("Options", options_obj.to_string());
DebugTrace("Options", Utf8ToGbk(options_obj.to_string()));
auto tasks_obj = root["tasks"].as_object();
for (auto&& [name, task_json] : tasks_obj) {
@@ -261,22 +261,22 @@ void Configer::clear_exec_times()
}
}
Configer& asst::Configer::operator=(const Configer& rhs)
{
m_version = rhs.m_version;
m_options = rhs.m_options;
m_tasks = rhs.m_tasks;
m_handles = rhs.m_handles;
return *this;
}
Configer& asst::Configer::operator=(Configer&& rhs) noexcept
{
m_version = std::move(rhs.m_version);
m_options = std::move(rhs.m_options);
m_tasks = std::move(rhs.m_tasks);
m_handles = std::move(rhs.m_handles);
return *this;
}
//Configer& asst::Configer::operator=(const Configer& rhs)
//{
// m_version = rhs.m_version;
// m_options = rhs.m_options;
// m_tasks = rhs.m_tasks;
// m_handles = rhs.m_handles;
//
// return *this;
//}
//
//Configer& asst::Configer::operator=(Configer&& rhs) noexcept
//{
// m_version = std::move(rhs.m_version);
// m_options = std::move(rhs.m_options);
// m_tasks = std::move(rhs.m_tasks);
// m_handles = std::move(rhs.m_handles);
//
// return *this;
//}

View File

@@ -71,7 +71,6 @@ std::vector<TextArea> asst::Identify::ocr_detect(const cv::Mat& mat)
int y = text_block.boxPoint.at(0).y;
int width = text_block.boxPoint.at(1).x - x;
int height = text_block.boxPoint.at(3).y - y;
result.emplace_back(text_block.text, x, y, width, height);
}
return result;
@@ -142,15 +141,42 @@ bool asst::Identify::ocr_init_models(const std::string& dir)
std::optional<asst::Rect> asst::Identify::find_text(const cv::Mat& mat, const std::string& text)
{
auto results = ocr_detect(mat);
for (auto&& res : results) {
for (const auto& res : results) {
if (res.text == text) {
return res.rect;
}
}
return std::nullopt;
}
std::vector<TextArea> asst::Identify::find_text(const cv::Mat& mat, const std::vector<std::string>& texts)
{
std::vector<TextArea> dst;
auto detect_result = ocr_detect(mat);
for (const auto& res : detect_result) {
for (const auto& t : texts) {
if (res.text == t) {
dst.emplace_back(res);
}
}
}
return dst;
}
std::vector<TextArea> asst::Identify::find_text(const cv::Mat& mat, const std::unordered_set<std::string>& texts)
{
std::vector<TextArea> dst;
auto detect_result = ocr_detect(mat);
for (const auto& res : detect_result) {
for (const auto& t : texts) {
if (res.text == t) {
dst.emplace_back(res);
}
}
}
return dst;
}
/*
std::pair<double, asst::Rect> Identify::findImageWithFile(const cv::Mat& cur, const std::string& filename)
{

View File

@@ -0,0 +1,75 @@
#include "RecruitConfiger.h"
#include <fstream>
#include <sstream>
#include "json.h"
#include "Logger.hpp"
using namespace asst;
bool RecruitConfiger::load(const std::string& filename)
{
DebugTraceFunction;
DebugTrace("RecruitConfiger::load | ", filename);
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
return false;
}
std::stringstream iss;
iss << ifs.rdbuf();
ifs.close();
std::string content(iss.str());
auto ret = json::parser::parse(content);
if (!ret) {
DebugTrace("parse error", content);
return false;
}
auto root = std::move(ret).value();
RecruitConfiger temp;
try {
auto opers_array = root.as_array();
for (auto&& oper : opers_array) {
OperInfo oper_temp;
oper_temp.name = oper["name"].as_string();
oper_temp.type = oper["type"].as_string();
temp.m_all_types.emplace(oper_temp.type);
// 职业类型也作为tag之一加上"干员"两个字
std::string type_as_tag = oper_temp.type + GbkToUtf8("干员");
oper_temp.tags.emplace(type_as_tag);
temp.m_all_tags.emplace(type_as_tag);
oper_temp.level = oper["level"].as_integer();
oper_temp.sex = oper["sex"].as_string();
auto tags_arr = oper["tags"].as_array();
for (const auto& tag_value : tags_arr) {
std::string tag = tag_value.as_string();
oper_temp.tags.emplace(tag);
temp.m_all_tags.emplace(tag);
}
oper_temp.hidden = oper["hidden"].as_boolean();
oper_temp.name_en = oper["name-en"].as_string();
temp.m_opers.emplace_back(std::move(oper_temp));
}
}
catch (json::exception& e) {
DebugTraceError("Load config json error!", e.what());
return false;
}
*this = std::move(temp);
#ifdef LOG_TRACE
for (auto&& tag : m_all_tags) {
std::cout << Utf8ToGbk(tag) << std::endl;
}
#endif
DebugTrace("Load config succeed");
return true;
}

View File

@@ -7,6 +7,7 @@
#include "json.h"
#include "AsstDef.h"
#include "Logger.hpp"
#include "Version.h"
using namespace asst;

View File

@@ -42,7 +42,7 @@ void asst_ocr_test()
std::string person_name;
ifs >> person_name;
asst.find_text_and_click(person_name);
asst.find_tags();
c = getchar();
}
@@ -81,6 +81,4 @@ void raw_ocr_test()
auto end = std::chrono::system_clock::now();
std::cout << "Time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << std::endl;
std::wcout << Utf8ToGBK(result.strRes) << std::endl;
}