适配干员名识别参数

This commit is contained in:
MistEO
2021-08-21 23:57:04 +08:00
parent d6868e9439
commit a4a8b0cfb0
7 changed files with 86 additions and 21 deletions

View File

@@ -256,7 +256,7 @@ bool asst::Assistance::start_to_identify_opers()
auto task_ptr = std::make_shared<IdentifyOperTask>(task_callback, (void*)this);
// TODO 这个参数写到配置文件里TODO 滑动位置要根据分辨率缩放
task_ptr->set_swipe_param(Rect(800, 600, 0, 0), Rect(600, 600, 0, 0), 200);
task_ptr->set_swipe_param(Rect(2400, 800, 0, 0), Rect(400, 800, 0, 0), 2000);
task_ptr->set_task_chain("IdentifyOpers");
m_tasks_queue.emplace(task_ptr);

View File

@@ -42,14 +42,17 @@ bool asst::IdentifyOperTask::run()
std::unordered_set<std::string> feature_whatever = InfrastConfiger::get_instance().m_oper_name_feat_whatever;
std::unordered_set<OperInfrastInfo> detected_opers;
int times = 0;
bool reverse = false;
// 一边识别一边滑动,把所有干员名字抓出来
// 异步进行滑动操作
m_keep_swipe = true;
std::future<bool> swipe_future = std::async(
std::launch::async, &IdentifyOperTask::keep_swipe, this, false);
// 正向完整滑一遍,再反向完整滑一遍,提高识别率
while (true) {
const cv::Mat& image = OcrAbstractTask::get_format_image(true);
// 异步进行滑动操作
std::future<bool> swipe_future = std::async(
std::launch::async, &IdentifyOperTask::swipe, this, reverse);
auto cur_name_textarea = detect_opers(image, feature_cond, feature_whatever);
int oper_numer = detected_opers.size();
@@ -77,17 +80,35 @@ bool asst::IdentifyOperTask::run()
opers_json["all"] = json::array(opers_json_vec);
m_callback(AsstMsg::InfrastOpers, opers_json, m_callback_arg);
// 说明本次识别一个新的都没识别到,应该是滑动到最后了,直接结束循环
if (oper_numer == detected_opers.size()) {
break;
// 正向滑动的时候
if (!reverse) {
++times;
// 说明本次识别一个新的都没识别到,应该是滑动到最后了,直接结束循环
if (oper_numer == detected_opers.size()) {
reverse = true;
}
}
if (need_exit()) {
else { // 反向滑动的时候
if (--times <= 0) {
break;
}
}
// 阻塞等待本次滑动结束
if (!swipe_future.get()) {
return false;
}
}
// 等待滑动结束
m_keep_swipe = false;
swipe_future.wait();
#ifdef LOG_TRACE
for (const std::string& name : InfrastConfiger::get_instance().m_all_opers_name) {
auto iter = std::find_if(detected_opers.cbegin(), detected_opers.cend(),
[&](const OperInfrastInfo& oper) -> bool {
return oper.name == name;
});
if (iter == detected_opers.cend()) {
std::cout << "未检测到:" << Utf8ToGbk(name) << std::endl;
}
}
#endif // LOG_TRACE
return true;
}
@@ -96,8 +117,8 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
{
// 裁剪出来干员名的一个长条形图片,没必要把整张图片送去识别
// TODO这个参数要根据分辨率调整
constexpr static int cropped_height = 100;
constexpr static int cropped_upper_y = 665;
constexpr static int cropped_height = 60;
constexpr static int cropped_upper_y = 695;
cv::Mat upper_part_name_image = image(cv::Rect(0, cropped_upper_y, image.cols, cropped_height));
std::vector<TextArea> upper_text_area = ocr_detect(upper_part_name_image); // 所有文字
@@ -110,11 +131,19 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
upper_text_area,
InfrastConfiger::get_instance().m_all_opers_name,
Configer::get_instance().m_infrast_ocr_replace);
// 把这一块涂黑,避免后面被特征检测的误识别了
cv::Mat draw_image = image;
for (const TextArea& textarea : upper_part_names) {
cv::Rect rect(textarea.rect.x, textarea.rect.y, textarea.rect.width, textarea.rect.height);
// 注意这里是浅拷贝原图image也会被涂黑
cv::rectangle(draw_image, rect, cv::Scalar(0, 0, 0), -1);
}
// 下半部分的干员
// TODO这个y参数要根据分辨率调整
constexpr static int cropped_lower_y = 1300;
constexpr static int cropped_lower_y = 1335;
cv::Mat lower_part_name_image = image(cv::Rect(0, cropped_lower_y, image.cols, cropped_height));
std::vector<TextArea> lower_text_area = ocr_detect(lower_part_name_image); // 所有文字
// 因为图片是裁剪过的,所以对应原图的坐标要加上裁剪的参数
for (TextArea& textarea : lower_text_area) {
@@ -125,6 +154,12 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
lower_text_area,
InfrastConfiger::get_instance().m_all_opers_name,
Configer::get_instance().m_infrast_ocr_replace);
// 把这一块涂黑,避免后面被特征检测的误识别了
for (const TextArea& textarea : lower_part_names) {
cv::Rect rect(textarea.rect.x, textarea.rect.y, textarea.rect.width, textarea.rect.height);
// 注意这里是浅拷贝原图image也会被涂黑
cv::rectangle(draw_image, rect, cv::Scalar(0, 0, 0), -1);
}
// 上下两部分识别结果合并
std::vector<TextArea> all_text_area = std::move(upper_text_area);
@@ -188,6 +223,9 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
if (whatever_iter != feature_whatever.end()) {
feature_whatever.erase(whatever_iter);
}
// 顺便再涂黑了避免后面被whatever特征检测的误识别
// 注意这里是浅拷贝原图image也会被涂黑
cv::rectangle(draw_image, cv_rect, cv::Scalar(0, 0, 0), -1);
}
}
}
@@ -198,8 +236,13 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
// 上半部分长条形的图片
auto&& upper_ret = OcrAbstractTask::m_identify_ptr->feature_match(upper_part_name_image, *iter);
if (upper_ret) {
// 因为图片是裁剪过的,所以对应原图的坐标要加上裁剪的参数
TextArea temp = std::move(upper_ret.value());
#ifdef LOG_TRACE // 也顺便涂黑一下,方便看谁没被识别出来
cv::Rect draw_rect(temp.rect.x, temp.rect.y, temp.rect.width, temp.rect.height);
// 注意这里是浅拷贝原图image也会被涂黑
cv::rectangle(upper_part_name_image, draw_rect, cv::Scalar(0, 0, 0), -1);
#endif
// 因为图片是裁剪过的,所以对应原图的坐标要加上裁剪的参数
temp.rect.y += cropped_upper_y;
all_opers_textarea.emplace_back(std::move(temp));
iter = feature_whatever.erase(iter);
@@ -209,8 +252,13 @@ std::vector<TextArea> asst::IdentifyOperTask::detect_opers(const cv::Mat& image,
// 下半部分长条形的图片
auto&& lower_ret = OcrAbstractTask::m_identify_ptr->feature_match(lower_part_name_image, *iter);
if (lower_ret) {
// 因为图片是裁剪过的,所以对应原图的坐标要加上裁剪的参数
TextArea temp = std::move(lower_ret.value());
#ifdef LOG_TRACE // 也顺便涂黑一下,方便看谁没被识别出来
cv::Rect draw_rect(temp.rect.x, temp.rect.y, temp.rect.width, temp.rect.height);
// 注意这里是浅拷贝原图image也会被涂黑
cv::rectangle(lower_part_name_image, draw_rect, cv::Scalar(0, 0, 0), -1);
#endif
// 因为图片是裁剪过的,所以对应原图的坐标要加上裁剪的参数
temp.rect.y += cropped_lower_y;
all_opers_textarea.emplace_back(std::move(temp));
iter = feature_whatever.erase(iter);
@@ -252,9 +300,22 @@ int asst::IdentifyOperTask::detect_elite(const cv::Mat& image, const asst::Rect
}
}
bool IdentifyOperTask::swipe(bool reverse)
{
bool ret = true;
if (!reverse) {
ret &= m_control_ptr->swipe(m_swipe_begin, m_swipe_end, m_swipe_duration);
}
else {
ret &= m_control_ptr->swipe(m_swipe_end, m_swipe_begin, m_swipe_duration);
}
ret &= sleep(SwipeExtraDelay);
return ret;
}
bool IdentifyOperTask::keep_swipe(bool reverse)
{
bool ret = false;
bool ret = true;
while (m_keep_swipe && !ret) {
if (!reverse) {
ret &= m_control_ptr->swipe(m_swipe_begin, m_swipe_end, m_swipe_duration);

View File

@@ -22,12 +22,14 @@ namespace asst {
protected:
constexpr static int SwipeExtraDelay = 0;
virtual bool keep_swipe(bool reverse = false);
std::vector<TextArea> detect_opers(const cv::Mat& image,
std::unordered_map<std::string, std::string>& feature_cond,
std::unordered_set<std::string>& feature_whatever);
int detect_elite(const cv::Mat& image, const asst::Rect name_rect);
virtual bool swipe(bool reverse = false);
virtual bool keep_swipe(bool reverse = false);
Rect m_swipe_begin;
Rect m_swipe_end;
int m_swipe_duration = 0;

View File

@@ -36,6 +36,8 @@
[ "莱思哈特", "莱恩哈特" ],
[ "深能", "深靛" ],
[ "叫米", "古米" ],
[ "叶米", "古米" ],
[ "节草", "苇草" ],
[ "粹兰", "梓兰" ],
[ "艾丝菜尔", "艾丝黛尔" ],
[ "艾丝莱尔", "艾丝黛尔" ],

View File

@@ -63,7 +63,7 @@
[ "狮", "狮蝎" ]
],
"featureWhatever_Doc": "这里面的无论如何都进行特征检测",
"featureWhatever": [ "砾", "煌", "山", "黑", "W", "夕", "红", "芬", "梅", "宴", "孑", "吽" ],
"featureWhatever": [ "砾", "煌", "山", "黑", "W", "夕", "红", "芬", "梅", "宴", "孑", "吽", "空", "阿" ],
"allNames": [
"桃金娘",
"食铁兽",
@@ -190,7 +190,7 @@
"玫兰莎",
"空爆",
"安德切尔",
"安尔",
"安尔",
"芙蓉",
"翎羽",
"梓兰",

BIN
resource/operators/空.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
resource/operators/阿.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB