diff --git a/resource/tasks.json b/resource/tasks.json index 37630ab9b5..2c2018635f 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -1263,5 +1263,100 @@ 70, 50 ] + }, + "InfrastClueVacancyNo1": { + "template": "ClueVacancyNo1.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo2": { + "template": "ClueVacancyNo2.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo3": { + "template": "ClueVacancyNo3.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo4": { + "template": "ClueVacancyNo4.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo5": { + "template": "ClueVacancyNo5.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo6": { + "template": "ClueVacancyNo6.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClueVacancyNo7": { + "template": "ClueVacancyNo7.png", + "cache": false, + "maskRange": [ + 250, + 255 + ], + "templThreshold": 0.95 + }, + "InfrastClue": { + "template": "Clue.png", + "cache": false, + "maskRange": [ + 1, + 255 + ] + }, + "InfrastClueOnTheRightSwipeBegin": { + "algorithm": "justReturn", + "action": "clickRect", + "specificRect": [ + 900, + 600, + 300, + 100 + ], + "preDelay": 1000, + "rearDelay": 1000, + "maxTimes": 1, + "Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用,maxTimes作为重复次数使用" + }, + "InfrastClueOnTheRightSwipeEnd": { + "algorithm": "justReturn", + "action": "clickRect", + "specificRect": [ + 900, + 200, + 300, + 100 + ] } } \ No newline at end of file diff --git a/resource/template/Clue.png b/resource/template/Clue.png new file mode 100644 index 0000000000..c01d72c9d7 Binary files /dev/null and b/resource/template/Clue.png differ diff --git a/resource/template/ClueVacancyNo1.png b/resource/template/ClueVacancyNo1.png new file mode 100644 index 0000000000..1a86dcc014 Binary files /dev/null and b/resource/template/ClueVacancyNo1.png differ diff --git a/resource/template/ClueVacancyNo2.png b/resource/template/ClueVacancyNo2.png new file mode 100644 index 0000000000..d6f02c3512 Binary files /dev/null and b/resource/template/ClueVacancyNo2.png differ diff --git a/resource/template/ClueVacancyNo3.png b/resource/template/ClueVacancyNo3.png new file mode 100644 index 0000000000..f88d268d4b Binary files /dev/null and b/resource/template/ClueVacancyNo3.png differ diff --git a/resource/template/ClueVacancyNo4.png b/resource/template/ClueVacancyNo4.png new file mode 100644 index 0000000000..17922e3e66 Binary files /dev/null and b/resource/template/ClueVacancyNo4.png differ diff --git a/resource/template/ClueVacancyNo5.png b/resource/template/ClueVacancyNo5.png new file mode 100644 index 0000000000..d2b21f8022 Binary files /dev/null and b/resource/template/ClueVacancyNo5.png differ diff --git a/resource/template/ClueVacancyNo6.png b/resource/template/ClueVacancyNo6.png new file mode 100644 index 0000000000..288fcfda4e Binary files /dev/null and b/resource/template/ClueVacancyNo6.png differ diff --git a/resource/template/ClueVacancyNo7.png b/resource/template/ClueVacancyNo7.png new file mode 100644 index 0000000000..57d94e3a00 Binary files /dev/null and b/resource/template/ClueVacancyNo7.png differ diff --git a/src/MeoAssistance/Assistance.cpp b/src/MeoAssistance/Assistance.cpp index 2af1e1633b..d2614aabce 100644 --- a/src/MeoAssistance/Assistance.cpp +++ b/src/MeoAssistance/Assistance.cpp @@ -21,6 +21,7 @@ #include "InfrastPowerTask.h" #include "InfrastOfficeTask.h" #include "InfrastInfoTask.h" +#include "InfrastReceptionTask.h" using namespace asst; @@ -228,7 +229,7 @@ bool Assistance::start_debug_task() { constexpr static const char* DebugTaskChain = "Debug"; - auto shift_task_ptr = std::make_shared(task_callback, (void*)this); + auto shift_task_ptr = std::make_shared(task_callback, (void*)this); //shift_task_ptr->set_facility("Mfg"); //shift_task_ptr->set_product("CombatRecord"); shift_task_ptr->set_task_chain(DebugTaskChain); diff --git a/src/MeoAssistance/AsstDef.h b/src/MeoAssistance/AsstDef.h index 8da22eb7d4..35db568366 100644 --- a/src/MeoAssistance/AsstDef.h +++ b/src/MeoAssistance/AsstDef.h @@ -65,7 +65,7 @@ namespace asst { && (y + height) >= (rhs.y + rhs.height); } std::string to_string() const { - return "[" + std::to_string(x) + ", " + return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " + std::to_string(height) + " ]"; diff --git a/src/MeoAssistance/InfrastClueImageAnalyzer.cpp b/src/MeoAssistance/InfrastClueImageAnalyzer.cpp new file mode 100644 index 0000000000..7f241cabe3 --- /dev/null +++ b/src/MeoAssistance/InfrastClueImageAnalyzer.cpp @@ -0,0 +1,38 @@ +#include "InfrastClueImageAnalyzer.h" + +#include "MultiMatchImageAnalyzer.h" +#include "Resource.h" + +bool asst::InfrastClueImageAnalyzer::analyze() +{ + clue_detect(); + if (m_need_detailed) { + clue_analyze(); + } + + return !m_result.empty(); +} + +bool asst::InfrastClueImageAnalyzer::clue_detect() +{ + MultiMatchImageAnalyzer clue_analyzer(m_image); + const auto task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr("InfrastClue")); + clue_analyzer.set_task_info(*task_ptr); + clue_analyzer.set_roi(m_roi); // 改任务以外部设置的roi为准 + if (!clue_analyzer.analyze()) { + return false; + } + clue_analyzer.sort_result(); + for (const auto& res : clue_analyzer.get_result()) { + m_result.emplace_back(res.rect, std::string()); + } + + return !m_result.empty(); +} + +bool asst::InfrastClueImageAnalyzer::clue_analyze() +{ + // todo + return false; +} \ No newline at end of file diff --git a/src/MeoAssistance/InfrastClueImageAnalyzer.h b/src/MeoAssistance/InfrastClueImageAnalyzer.h new file mode 100644 index 0000000000..7283d2d0f4 --- /dev/null +++ b/src/MeoAssistance/InfrastClueImageAnalyzer.h @@ -0,0 +1,23 @@ +#pragma once +#include "AbstractImageAnalyzer.h" + +namespace asst { + class InfrastClueImageAnalyzer : public AbstractImageAnalyzer + { + public: + using AbstractImageAnalyzer::AbstractImageAnalyzer; + virtual ~InfrastClueImageAnalyzer() = default; + + virtual bool analyze() override; + + const std::vector>& get_result() const noexcept { + return m_result; + } + protected: + bool clue_detect(); + bool clue_analyze(); + + bool m_need_detailed = false; // 是否需要详细分析(线索号);false时只检测,不识别 + std::vector> m_result; + }; +} diff --git a/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.cpp b/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.cpp new file mode 100644 index 0000000000..b16331d9e8 --- /dev/null +++ b/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.cpp @@ -0,0 +1,28 @@ +#include "InfrastClueVacancyImageAnalyzer.h" + +#include "MatchImageAnalyzer.h" +#include "Resource.h" +#include "AsstUtils.hpp" + +bool asst::InfrastClueVacancyImageAnalyzer::analyze() +{ + const static std::string clue_vacancy = "InfrastClueVacancy"; + + MatchImageAnalyzer analyzer(m_image); + for (const std::string& suffix : m_to_be_analyzed) { + const auto task_ptr = std::dynamic_pointer_cast( + resource.task().task_ptr(clue_vacancy + suffix)); + analyzer.set_task_info(*task_ptr); + if (!analyzer.analyze()) { + continue; + } + Rect rect = analyzer.get_result().rect; +#ifdef LOG_TRACE + cv::rectangle(m_image_draw, utils::make_rect(rect), cv::Scalar(0, 0, 255), 2); + cv::putText(m_image_draw, suffix, cv::Point(rect.x, rect.y + 1), 0, 1, cv::Scalar(0, 0, 255), 2); +#endif + m_clue_vacancy.emplace(suffix, rect); + } + + return !m_clue_vacancy.empty(); +} \ No newline at end of file diff --git a/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.h b/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.h new file mode 100644 index 0000000000..ad21c8683c --- /dev/null +++ b/src/MeoAssistance/InfrastClueVacancyImageAnalyzer.h @@ -0,0 +1,34 @@ +#pragma once +#include "AbstractImageAnalyzer.h" + +namespace asst { + class InfrastClueVacancyImageAnalyzer final : public AbstractImageAnalyzer + { + public: + using AbstractImageAnalyzer::AbstractImageAnalyzer; + virtual ~InfrastClueVacancyImageAnalyzer() = default; + InfrastClueVacancyImageAnalyzer(const cv::Mat& image, const Rect& roi) = delete; + + virtual bool analyze() override; + constexpr static int MaxNumOfClue = 7; + + void set_to_be_analyzed(std::vector to_be_analyzed) noexcept { + m_to_be_analyzed = std::move(to_be_analyzed); + } + + const std::unordered_map& get_vacancy() const noexcept { + return m_clue_vacancy; + } + private: + // 该分析器不支持外部设置ROI + virtual void set_roi(const Rect& roi) noexcept override { + AbstractImageAnalyzer::set_roi(roi); + } + virtual void set_image(const cv::Mat& image, const Rect& roi) { + AbstractImageAnalyzer::set_image(image, roi); + } + + std::vector m_to_be_analyzed; + std::unordered_map m_clue_vacancy; + }; +} diff --git a/src/MeoAssistance/InfrastReceptionTask.cpp b/src/MeoAssistance/InfrastReceptionTask.cpp new file mode 100644 index 0000000000..a8747403a0 --- /dev/null +++ b/src/MeoAssistance/InfrastReceptionTask.cpp @@ -0,0 +1,65 @@ +#include "InfrastReceptionTask.h" + +#include "Controller.h" +#include "Resource.h" +#include "InfrastClueVacancyImageAnalyzer.h" +#include "InfrastClueImageAnalyzer.h" +#include "Logger.hpp" + +bool asst::InfrastReceptionTask::run() +{ + const static std::string clue_vacancy = "InfrastClueVacancy"; + const static std::vector clue_suffix = { + "No1", "No2", "No3", "No4", "No5", "No6", "No7" }; + + cv::Mat image; + for (const std::string& clue : clue_suffix) { + // 先识别线索的空位 + image = ctrler.get_image(); + InfrastClueVacancyImageAnalyzer vacancy_analyzer(image); + vacancy_analyzer.set_to_be_analyzed({ clue }); + if (!vacancy_analyzer.analyze()) { + continue; + } + // 点开线索的空位 + Rect vacancy = vacancy_analyzer.get_vacancy().cbegin()->second; + ctrler.click(vacancy); + int delay = resource.task().task_ptr(clue_vacancy + clue)->rear_delay; + sleep(delay); + + // 识别右边列表中的线索,然后用最底下的那个(一般都是剩余时间最短的) + swipe_to_the_bottom_of_clue_list_on_the_right(); + image = ctrler.get_image(); + InfrastClueImageAnalyzer clue_analyzer(image); + if (!clue_analyzer.analyze()) { + continue; + } + ctrler.click(clue_analyzer.get_result().back().first); + sleep(delay); + } + // 所有的空位分析一次,看看还缺哪些线索 + InfrastClueVacancyImageAnalyzer vacancy_analyzer(image); + vacancy_analyzer.set_to_be_analyzed(clue_suffix); + if (!vacancy_analyzer.analyze()) { + } + for (auto&& [id, _] : vacancy_analyzer.get_vacancy()) { + log.trace("InfrastReceptionTask | Vacancy", id); + } + + return false; +} + +bool asst::InfrastReceptionTask::swipe_to_the_bottom_of_clue_list_on_the_right() +{ + static Rect begin_rect = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->specific_rect; + static Rect end_rect = resource.task().task_ptr("InfrastClueOnTheRightSwipeEnd")->specific_rect; + static int duration = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->pre_delay; + static int extra_delay = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->rear_delay; + static int loop_times = resource.task().task_ptr("InfrastClueOnTheRightSwipeBegin")->max_times; + + for (int i = 0; i != loop_times; ++i) { + ctrler.swipe(begin_rect, end_rect, duration, true, 0, false); + } + sleep(extra_delay); + return false; +} \ No newline at end of file diff --git a/src/MeoAssistance/InfrastReceptionTask.h b/src/MeoAssistance/InfrastReceptionTask.h new file mode 100644 index 0000000000..bb60b2256d --- /dev/null +++ b/src/MeoAssistance/InfrastReceptionTask.h @@ -0,0 +1,14 @@ +#pragma once +#include "InfrastProductionTask.h" + +namespace asst { + class InfrastReceptionTask : public InfrastProductionTask + { + public: + using InfrastProductionTask::InfrastProductionTask; + virtual ~InfrastReceptionTask() = default; + virtual bool run() override; + private: + bool swipe_to_the_bottom_of_clue_list_on_the_right(); + }; +} diff --git a/src/MeoAssistance/MeoAssistance.vcxproj b/src/MeoAssistance/MeoAssistance.vcxproj index e191b516f3..d3026bc49c 100644 --- a/src/MeoAssistance/MeoAssistance.vcxproj +++ b/src/MeoAssistance/MeoAssistance.vcxproj @@ -25,6 +25,7 @@ + @@ -34,6 +35,8 @@ + + @@ -67,6 +70,7 @@ + @@ -76,6 +80,8 @@ + + diff --git a/src/MeoAssistance/MeoAssistance.vcxproj.filters b/src/MeoAssistance/MeoAssistance.vcxproj.filters index 3174df0b99..55b9aee1a6 100644 --- a/src/MeoAssistance/MeoAssistance.vcxproj.filters +++ b/src/MeoAssistance/MeoAssistance.vcxproj.filters @@ -55,6 +55,12 @@ {d173e449-880b-4064-bbab-97007e3d090b} + + {fc8aa302-89bb-4016-924d-10177dc8b334} + + + {9a6160e3-cd35-4dda-ba04-23ede1878740} + @@ -144,9 +150,6 @@ 头文件\ImageAnalyzer - - 头文件\Task - 头文件\ImageAnalyzer\General @@ -168,35 +171,47 @@ 头文件\Resource - - 头文件\Task - 头文件\ImageAnalyzer\Infrast 头文件\ImageAnalyzer\Infrast - - 头文件\Task - - - 头文件\Task - - - 头文件\Task - - - 头文件\Task - - - 头文件\Task - 头文件 + + 头文件\ImageAnalyzer\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + - 头文件\Task + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\Task\Infrast + + + 头文件\ImageAnalyzer\Infrast @@ -269,9 +284,6 @@ 源文件\ImageAnalyzer - - 源文件\Task - 源文件\ImageAnalyzer\Infrast @@ -293,35 +305,47 @@ 源文件\Resource - - 源文件\Task - 源文件\ImageAnalyzer\Infrast 源文件\ImageAnalyzer\Infrast - - 源文件\Task - - - 源文件\Task - - - 源文件\Task - - - 源文件\Task - - - 源文件\Task - 源文件 + + 源文件\Task\Infrast + + + 源文件\Task\Infrast + - 源文件\Task + 源文件\Task\Infrast + + + 源文件\Task\Infrast + + + 源文件\Task\Infrast + + + 源文件\Task\Infrast + + + 源文件\Task\Infrast + + + 源文件\Task\Infrast + + + 源文件\ImageAnalyzer\Infrast + + + 源文件\ImageAnalyzer\Infrast + + + 源文件\Task\Infrast diff --git a/src/MeoAssistance/MultiMatchImageAnalyzer.cpp b/src/MeoAssistance/MultiMatchImageAnalyzer.cpp index 48d9005930..611705fdfb 100644 --- a/src/MeoAssistance/MultiMatchImageAnalyzer.cpp +++ b/src/MeoAssistance/MultiMatchImageAnalyzer.cpp @@ -82,6 +82,13 @@ bool asst::MultiMatchImageAnalyzer::multi_match_templ(const cv::Mat& templ) } } } + std::string log_str = "[ "; + for (const auto& res : m_result) { + log_str += res.rect.to_string() + " : " + std::to_string(res.score) + "; "; + } + log_str += "]"; + log.trace("multi_match_templ | ", m_templ_name, log_str); + if (!m_result.empty()) { return true; }