mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-19 18:47:55 +08:00
完成“精英化”识别demo
This commit is contained in:
@@ -28,9 +28,10 @@ namespace asst {
|
||||
// return tuple< algorithmType, suitability, matched asst::rect>
|
||||
std::tuple<AlgorithmType, double, asst::Rect> find_image(const cv::Mat& image, const std::string& templ, double templ_threshold);
|
||||
|
||||
// return pair< suitability, raw opencv::point>
|
||||
std::pair<double, cv::Point> match_template(const cv::Mat& cur, const cv::Mat& templ);
|
||||
|
||||
std::optional<TextArea> feature_match(const cv::Mat& mat, const std::string& key);
|
||||
// for debug
|
||||
std::vector<TextArea> feature_match_all(const cv::Mat& mat);
|
||||
|
||||
void clear_cache();
|
||||
|
||||
@@ -49,9 +50,13 @@ namespace asst {
|
||||
|
||||
// return pair<特征点s,特征点描述子(向量)>
|
||||
std::pair<std::vector<cv::KeyPoint>, cv::Mat> surf_detect(const cv::Mat& mat);
|
||||
|
||||
// return pair< suitability, raw opencv::point>
|
||||
std::pair<double, cv::Point> match_template(const cv::Mat& cur, const cv::Mat& templ);
|
||||
std::optional<Rect> feature_match(
|
||||
const std::vector<cv::KeyPoint>& query_keypoints, const cv::Mat& query_mat_vector,
|
||||
const std::vector<cv::KeyPoint>& train_keypoints, const cv::Mat& train_mat_vector
|
||||
#ifdef LOG_TRACE
|
||||
, const cv::Mat query_mat = cv::Mat(), const cv::Mat train_mat = cv::Mat()
|
||||
#endif
|
||||
);
|
||||
|
||||
std::unordered_map<std::string, cv::Mat> m_mat_map;
|
||||
bool m_use_cache = true;
|
||||
|
||||
@@ -68,13 +68,28 @@ Assistance::Assistance(AsstCallback callback, void* callback_arg)
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::string& name : InfrastConfiger::get_instance().m_mfg_opers) {
|
||||
for (const auto& [key, name] : InfrastConfiger::get_instance().m_mfg_feat) {
|
||||
ret = m_identify_ptr->add_text_image(name, GetResourceDir() + "operators\\" + Utf8ToGbk(name) + ".png");
|
||||
if (!ret) {
|
||||
callback_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (const auto& name : InfrastConfiger::get_instance().m_mfg_feat_whatever) {
|
||||
ret = m_identify_ptr->add_text_image(name, GetResourceDir() + "operators\\" + Utf8ToGbk(name) + ".png");
|
||||
if (!ret) {
|
||||
callback_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 精一和精二的图片,调试用
|
||||
ret = m_identify_ptr->add_text_image("Elite1", GetResourceDir() + "operators\\Elite1.png");
|
||||
ret &= m_identify_ptr->add_text_image("Elite2", GetResourceDir() + "operators\\Elite2.png");
|
||||
if (!ret) {
|
||||
callback_error();
|
||||
return;
|
||||
}
|
||||
|
||||
m_working_thread = std::thread(working_proc, this);
|
||||
m_msg_thread = std::thread(msg_proc, this);
|
||||
@@ -289,7 +304,7 @@ void Assistance::working_proc(Assistance* p_this)
|
||||
int retry_times = 0;
|
||||
while (!p_this->m_thread_exit)
|
||||
{
|
||||
DebugTraceScope("Assistance::working_proc Loop");
|
||||
//DebugTraceScope("Assistance::working_proc Loop");
|
||||
std::unique_lock<std::mutex> lock(p_this->m_mutex);
|
||||
if (!p_this->m_thread_idle && !p_this->m_tasks_queue.empty())
|
||||
{
|
||||
@@ -360,7 +375,7 @@ void Assistance::msg_proc(Assistance* p_this)
|
||||
|
||||
while (!p_this->m_thread_exit)
|
||||
{
|
||||
DebugTraceScope("Assistance::msg_proc Loop");
|
||||
//DebugTraceScope("Assistance::msg_proc Loop");
|
||||
std::unique_lock<std::mutex> lock(p_this->m_msg_mutex);
|
||||
if (!p_this->m_msg_queue.empty())
|
||||
{
|
||||
|
||||
@@ -94,6 +94,145 @@ std::pair<std::vector<cv::KeyPoint>, cv::Mat> asst::Identify::surf_detect(const
|
||||
return std::make_pair(std::move(keypoints), std::move(mat_vector));
|
||||
}
|
||||
|
||||
std::optional<asst::Rect> asst::Identify::feature_match(
|
||||
const std::vector<cv::KeyPoint>& query_keypoints, const cv::Mat& query_mat_vector,
|
||||
const std::vector<cv::KeyPoint>& train_keypoints, const cv::Mat& train_mat_vector
|
||||
#ifdef LOG_TRACE
|
||||
, const cv::Mat query_mat, const cv::Mat train_mat
|
||||
#endif
|
||||
)
|
||||
{
|
||||
std::vector<cv::DMatch> matches;
|
||||
static FlannBasedMatcher matcher;
|
||||
matcher.match(query_mat_vector, train_mat_vector, matches);
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
std::cout << matches.size() << " / " << query_keypoints.size() << std::endl;
|
||||
cv::Mat allmatch_mat;
|
||||
cv::drawMatches(query_mat, query_keypoints, train_mat, train_keypoints, matches, allmatch_mat);
|
||||
#endif
|
||||
|
||||
// 最大的距离
|
||||
auto max_iter = std::max_element(matches.cbegin(), matches.cend(),
|
||||
[](const cv::DMatch& lhs, const cv::DMatch& rhs) ->bool {
|
||||
return lhs.distance < rhs.distance;
|
||||
}); // 描述符欧式距离(knn)
|
||||
if (max_iter == matches.cend()) {
|
||||
return std::nullopt;;
|
||||
}
|
||||
float maxdist = max_iter->distance;
|
||||
|
||||
std::vector<cv::DMatch> approach_matches;
|
||||
std::vector<cv::KeyPoint> train_approach_keypoints;
|
||||
std::vector<cv::KeyPoint> query_approach_keypoints;
|
||||
std::vector<cv::Point> train_approach_points;
|
||||
std::vector<cv::Point> query_approach_points;
|
||||
// 利用距离进行一次逼近
|
||||
constexpr static const double MatchRatio = 0.4;
|
||||
int approach_index = 0;
|
||||
for (const cv::DMatch dmatch : matches) {
|
||||
if (dmatch.distance < maxdist * MatchRatio) {
|
||||
// 按理说不会越界,以防万一还是检查一下
|
||||
if (dmatch.queryIdx >= 0 && dmatch.queryIdx < query_keypoints.size()
|
||||
&& dmatch.trainIdx >= 0 && dmatch.trainIdx < train_keypoints.size()) {
|
||||
approach_matches.emplace_back(dmatch);
|
||||
train_approach_points.emplace_back(train_keypoints.at(dmatch.trainIdx).pt);
|
||||
query_approach_points.emplace_back(query_keypoints.at(dmatch.queryIdx).pt);
|
||||
train_approach_keypoints.emplace_back(train_keypoints.at(dmatch.trainIdx));
|
||||
query_approach_keypoints.emplace_back(query_keypoints.at(dmatch.queryIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
cv::Mat approach_mat;
|
||||
cv::drawMatches(query_mat, query_keypoints, train_mat, train_keypoints, approach_matches, approach_mat);
|
||||
#endif
|
||||
|
||||
if (query_approach_points.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 使用RANSAC剔除异常值
|
||||
std::vector<uchar> ransac_status;
|
||||
cv::Mat fundametal = cv::findFundamentalMat(query_approach_points, train_approach_points, ransac_status, cv::FM_RANSAC);
|
||||
|
||||
std::vector<cv::DMatch> ransac_matchs;
|
||||
std::vector<cv::KeyPoint> train_ransac_keypoints;
|
||||
std::vector<cv::KeyPoint> query_ransac_keypoints;
|
||||
int index = 0;
|
||||
for (size_t i = 0; i != ransac_status.size(); ++i) {
|
||||
if (ransac_status.at(i) != 0) {
|
||||
train_ransac_keypoints.emplace_back(train_approach_keypoints.at(i));
|
||||
query_ransac_keypoints.emplace_back(query_approach_keypoints.at(i));
|
||||
cv::DMatch dmatch = approach_matches.at(i);
|
||||
ransac_matchs.emplace_back(std::move(dmatch));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// 做一次算数均值滤波,过滤异常的点。这个算法有点蠢,TODO可以看下怎么改
|
||||
size_t point_size = train_ransac_keypoints.size();
|
||||
if (point_size == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
cv::Point sum_point = std::accumulate(
|
||||
train_ransac_keypoints.cbegin(), train_ransac_keypoints.cend(), cv::Point(),
|
||||
[](cv::Point sum, const cv::KeyPoint& rhs) -> cv::Point {
|
||||
return cv::Point(sum.x + rhs.pt.x, sum.y + rhs.pt.y);
|
||||
});
|
||||
cv::Point avg_point(sum_point.x / point_size, sum_point.y / point_size);
|
||||
std::vector<cv::DMatch> good_matchs;
|
||||
std::vector<cv::Point> good_points;
|
||||
// TODO,这个阈值需要根据分辨率进行缩放,而且最好写到配置文件里
|
||||
constexpr static int DistanceThreshold = 200;
|
||||
for (size_t i = 0; i != train_ransac_keypoints.size(); ++i) {
|
||||
// 没必要算距离,x y各算一下就行了,省点CPU时间
|
||||
//int distance = std::sqrt(std::pow(avg_point.x - cur_x, 2) + std::pow(avg_point.y - cur_y, 2));
|
||||
cv::Point2f& pt = train_ransac_keypoints.at(i).pt;
|
||||
int x_distance = std::abs(avg_point.x - pt.x);
|
||||
int y_distance = std::abs(avg_point.y - pt.y);
|
||||
if (x_distance < DistanceThreshold && y_distance < DistanceThreshold) {
|
||||
good_matchs.emplace_back(ransac_matchs.at(i));
|
||||
good_points.emplace_back(pt);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
|
||||
cv::Mat ransac_mat;
|
||||
cv::drawMatches(query_mat, query_keypoints, train_mat, train_keypoints, ransac_matchs, ransac_mat);
|
||||
|
||||
cv::Mat good_mat;
|
||||
cv::drawMatches(query_mat, query_keypoints, train_mat, train_keypoints, good_matchs, good_mat);
|
||||
|
||||
#endif
|
||||
|
||||
constexpr static const double MatchSizeRatioThreshold = 0.075;
|
||||
if (good_points.size() >= query_keypoints.size() * MatchSizeRatioThreshold) {
|
||||
Rect dst;
|
||||
int left = 0, right = 0, top = 0, bottom = 0;
|
||||
for (const cv::Point& pt : good_points) {
|
||||
if (pt.x < left || left == 0) {
|
||||
left = pt.x;
|
||||
}
|
||||
if (pt.x > right || right == 0) {
|
||||
right = pt.x;
|
||||
}
|
||||
if (pt.y < top || top == 0) {
|
||||
top = pt.y;
|
||||
}
|
||||
if (pt.y > bottom || bottom == 0) {
|
||||
bottom = pt.y;
|
||||
}
|
||||
}
|
||||
dst = { left, top, right - left, bottom - top };
|
||||
return dst;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<TextArea> asst::Identify::ocr_detect(const cv::Mat& mat)
|
||||
{
|
||||
OcrResult ocr_results = m_ocr_lite.detect(mat,
|
||||
@@ -166,253 +305,25 @@ std::optional<TextArea> asst::Identify::feature_match(const cv::Mat& mat, const
|
||||
if (m_feature_map.find(key) == m_feature_map.cend()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
static FlannBasedMatcher matcher;
|
||||
auto&& [train_keypoints, train_mat_vector] = surf_detect(mat);
|
||||
auto&& [query_keypoints, query_mat_vector] = m_feature_map[key];
|
||||
std::vector<cv::DMatch> matches;
|
||||
matcher.match(query_mat_vector, train_mat_vector, matches);
|
||||
|
||||
// 最大的距离
|
||||
auto max_iter = std::max_element(matches.cbegin(), matches.cend(),
|
||||
[](const cv::DMatch& lhs, const cv::DMatch& rhs) ->bool {
|
||||
return lhs.distance < rhs.distance;
|
||||
}); // 描述符欧式距离(knn)
|
||||
if (max_iter == matches.cend()) {
|
||||
return std::nullopt;;
|
||||
}
|
||||
float maxdist = max_iter->distance;
|
||||
|
||||
std::vector<cv::DMatch> approach_matches;
|
||||
std::vector<cv::KeyPoint> train_approach_keypoints;
|
||||
std::vector<cv::KeyPoint> query_approach_keypoints;
|
||||
std::vector<cv::Point> train_approach_points;
|
||||
std::vector<cv::Point> query_approach_points;
|
||||
// 利用距离进行一次逼近
|
||||
constexpr static const double MatchRatio = 0.4;
|
||||
int approach_index = 0;
|
||||
for (const cv::DMatch dmatch : matches) {
|
||||
if (dmatch.distance < maxdist * MatchRatio) {
|
||||
// 按理说不会越界,以防万一还是检查一下
|
||||
if (dmatch.queryIdx >= 0 && dmatch.queryIdx < query_keypoints.size()
|
||||
&& dmatch.trainIdx >= 0 && dmatch.trainIdx < train_keypoints.size()) {
|
||||
approach_matches.emplace_back(dmatch);
|
||||
train_approach_points.emplace_back(train_keypoints.at(dmatch.trainIdx).pt);
|
||||
query_approach_points.emplace_back(query_keypoints.at(dmatch.queryIdx).pt);
|
||||
train_approach_keypoints.emplace_back(train_keypoints.at(dmatch.trainIdx));
|
||||
query_approach_keypoints.emplace_back(query_keypoints.at(dmatch.queryIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用RANSAC剔除异常值
|
||||
std::vector<uchar> ransac_status;
|
||||
cv::Mat fundametal = cv::findFundamentalMat(query_approach_points, train_approach_points, ransac_status, cv::FM_RANSAC);
|
||||
|
||||
std::vector<cv::DMatch> ransac_matchs;
|
||||
std::vector<cv::KeyPoint> train_ransac_keypoints;
|
||||
std::vector<cv::KeyPoint> query_ransac_keypoints;
|
||||
int index = 0;
|
||||
for (size_t i = 0; i != approach_matches.size(); ++i) {
|
||||
if (ransac_status.at(i) != 0) {
|
||||
train_ransac_keypoints.emplace_back(train_approach_keypoints.at(i));
|
||||
query_ransac_keypoints.emplace_back(query_approach_keypoints.at(i));
|
||||
cv::DMatch dmatch = approach_matches.at(i);
|
||||
ransac_matchs.emplace_back(std::move(dmatch));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// 做一次算数均值滤波,过滤异常的点。这个算法有点蠢,TODO可以想象怎么改
|
||||
size_t point_size = train_ransac_keypoints.size();
|
||||
if (point_size == 0) {
|
||||
return std::nullopt;;
|
||||
}
|
||||
cv::Point sum_point = std::accumulate(
|
||||
train_ransac_keypoints.cbegin(), train_ransac_keypoints.cend(), cv::Point(),
|
||||
[](cv::Point sum, const cv::KeyPoint& rhs) -> cv::Point {
|
||||
return cv::Point(sum.x + rhs.pt.x, sum.y + rhs.pt.y);
|
||||
});
|
||||
cv::Point avg_point(sum_point.x / point_size, sum_point.y / point_size);
|
||||
std::vector<cv::DMatch> good_matchs;
|
||||
std::vector<cv::Point> good_points;
|
||||
// TODO,这个阈值需要根据分辨率进行缩放,而且最好写到配置文件里
|
||||
constexpr static int DistanceThreshold = 200;
|
||||
for (size_t i = 0; i != train_ransac_keypoints.size(); ++i) {
|
||||
// 没必要算距离,x y各算一下就行了,省点CPU时间
|
||||
//int distance = std::sqrt(std::pow(avg_point.x - cur_x, 2) + std::pow(avg_point.y - cur_y, 2));
|
||||
cv::Point2f& pt = train_ransac_keypoints.at(i).pt;
|
||||
int x_distance = std::abs(avg_point.x - pt.x);
|
||||
int y_distance = std::abs(avg_point.y - pt.y);
|
||||
if (x_distance < DistanceThreshold && y_distance < DistanceThreshold) {
|
||||
good_matchs.emplace_back(ransac_matchs.at(i));
|
||||
good_points.emplace_back(pt);
|
||||
}
|
||||
}
|
||||
auto&& [train_keypoints, train_mat_vector] = surf_detect(mat);
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
std::cout << Utf8ToGbk(key) << " " << good_points.size() << " / " << query_keypoints.size() << std::endl;
|
||||
// for debug
|
||||
cv::Mat text_mat = cv::imread(GetResourceDir() + "operators\\" + Utf8ToGbk(key) + ".png");
|
||||
cv::Mat approach_mat;
|
||||
cv::drawMatches(text_mat, query_keypoints, mat, train_keypoints, ransac_matchs, approach_mat);
|
||||
cv::Mat good_mat;
|
||||
cv::drawMatches(text_mat, query_keypoints, mat, train_keypoints, good_matchs, good_mat);
|
||||
cv::Mat query_mat = cv::imread(GetResourceDir() + "operators\\" + Utf8ToGbk(key) + ".png");
|
||||
auto&& ret = feature_match(query_keypoints, query_mat_vector, train_keypoints, train_mat_vector,
|
||||
query_mat, mat);
|
||||
#else
|
||||
auto&& ret = feature_match(query_keypoints, query_mat_vector, train_keypoints, train_mat_vector);
|
||||
#endif
|
||||
|
||||
constexpr static const double MatchSizeRatioThreshold = 0.075;
|
||||
if (good_points.size() >= query_keypoints.size() * MatchSizeRatioThreshold) {
|
||||
if (ret) {
|
||||
TextArea dst;
|
||||
dst.text = key;
|
||||
int left = 0, right = 0, top = 0, bottom = 0;
|
||||
for (const cv::Point& pt : good_points) {
|
||||
if (pt.x < left || left == 0) {
|
||||
left = pt.x;
|
||||
}
|
||||
if (pt.x > right || right == 0) {
|
||||
right = pt.x;
|
||||
}
|
||||
if (pt.y < top || top == 0) {
|
||||
top = pt.y;
|
||||
}
|
||||
if (pt.y > bottom || bottom == 0) {
|
||||
bottom = pt.y;
|
||||
}
|
||||
}
|
||||
dst.rect = { left, top, right - left, bottom - top };
|
||||
dst.rect = std::move(ret.value());
|
||||
return dst;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<TextArea> asst::Identify::feature_match_all(const cv::Mat& mat)
|
||||
{
|
||||
DebugTraceFunction;
|
||||
|
||||
auto&& [train_keypoints, train_mat_vector] = surf_detect(mat);
|
||||
|
||||
static FlannBasedMatcher matcher;
|
||||
|
||||
std::vector<TextArea> matched_text_area;
|
||||
for (auto&& [key, feature] : m_feature_map) {
|
||||
auto&& [query_keypoints, query_mat_vector] = feature;
|
||||
std::vector<cv::DMatch> matches;
|
||||
matcher.match(query_mat_vector, train_mat_vector, matches);
|
||||
|
||||
// 最大的距离
|
||||
auto max_iter = std::max_element(matches.cbegin(), matches.cend(),
|
||||
[](const cv::DMatch& lhs, const cv::DMatch& rhs) ->bool {
|
||||
return lhs.distance < rhs.distance;
|
||||
}); // 描述符欧式距离(knn)
|
||||
if (max_iter == matches.cend()) {
|
||||
continue;
|
||||
}
|
||||
float maxdist = max_iter->distance;
|
||||
|
||||
std::vector<cv::DMatch> approach_matches;
|
||||
std::vector<cv::KeyPoint> train_approach_keypoints;
|
||||
std::vector<cv::KeyPoint> query_approach_keypoints;
|
||||
std::vector<cv::Point> train_approach_points;
|
||||
std::vector<cv::Point> query_approach_points;
|
||||
// 利用距离进行一次逼近
|
||||
constexpr static const double MatchRatio = 0.4;
|
||||
int approach_index = 0;
|
||||
for (const cv::DMatch dmatch : matches) {
|
||||
if (dmatch.distance < maxdist * MatchRatio) {
|
||||
// 按理说不会越界,以防万一还是检查一下
|
||||
if (dmatch.queryIdx >= 0 && dmatch.queryIdx < query_keypoints.size()
|
||||
&& dmatch.trainIdx >= 0 && dmatch.trainIdx < train_keypoints.size()) {
|
||||
approach_matches.emplace_back(dmatch);
|
||||
train_approach_points.emplace_back(train_keypoints.at(dmatch.trainIdx).pt);
|
||||
query_approach_points.emplace_back(query_keypoints.at(dmatch.queryIdx).pt);
|
||||
train_approach_keypoints.emplace_back(train_keypoints.at(dmatch.trainIdx));
|
||||
query_approach_keypoints.emplace_back(query_keypoints.at(dmatch.queryIdx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用RANSAC剔除异常值
|
||||
std::vector<uchar> ransac_status;
|
||||
cv::Mat fundametal = cv::findFundamentalMat(query_approach_points, train_approach_points, ransac_status, cv::FM_RANSAC);
|
||||
|
||||
std::vector<cv::DMatch> ransac_matchs;
|
||||
std::vector<cv::KeyPoint> train_ransac_keypoints;
|
||||
std::vector<cv::KeyPoint> query_ransac_keypoints;
|
||||
int index = 0;
|
||||
for (size_t i = 0; i != approach_matches.size(); ++i) {
|
||||
if (ransac_status.at(i) != 0) {
|
||||
train_ransac_keypoints.emplace_back(train_approach_keypoints.at(i));
|
||||
query_ransac_keypoints.emplace_back(query_approach_keypoints.at(i));
|
||||
cv::DMatch dmatch = approach_matches.at(i);
|
||||
ransac_matchs.emplace_back(std::move(dmatch));
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// 做一次算数均值滤波,过滤异常的点
|
||||
size_t point_size = train_ransac_keypoints.size();
|
||||
if (point_size == 0) {
|
||||
continue;
|
||||
}
|
||||
cv::Point sum_point = std::accumulate(
|
||||
train_ransac_keypoints.cbegin(), train_ransac_keypoints.cend(), cv::Point(),
|
||||
[](cv::Point sum, const cv::KeyPoint& rhs) -> cv::Point {
|
||||
return cv::Point(sum.x + rhs.pt.x, sum.y + rhs.pt.y);
|
||||
});
|
||||
cv::Point avg_point(sum_point.x / point_size, sum_point.y / point_size);
|
||||
std::vector<cv::DMatch> good_matchs;
|
||||
std::vector<cv::Point> good_points;
|
||||
// TODO,这个阈值需要根据分辨率进行缩放,而且最好写到配置文件里
|
||||
constexpr static int DistanceThreshold = 300;
|
||||
for (size_t i = 0; i != train_ransac_keypoints.size(); ++i) {
|
||||
// 没必要算距离,x y各算一下就行了,省点CPU时间
|
||||
//int distance = std::sqrt(std::pow(avg_point.x - cur_x, 2) + std::pow(avg_point.y - cur_y, 2));
|
||||
cv::Point2f& pt = train_ransac_keypoints.at(i).pt;
|
||||
int x_distance = std::abs(avg_point.x - pt.x);
|
||||
int y_distance = std::abs(avg_point.y - pt.y);
|
||||
if (x_distance < DistanceThreshold && y_distance < DistanceThreshold) {
|
||||
good_matchs.emplace_back(ransac_matchs.at(i));
|
||||
good_points.emplace_back(pt);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << Utf8ToGbk(key) << " " << good_points.size() << " / " << query_keypoints.size() << std::endl;
|
||||
constexpr static const double MatchSizeRatioThreshold = 0.075;
|
||||
if (good_points.size() >= query_keypoints.size() * MatchSizeRatioThreshold) {
|
||||
TextArea textarea;
|
||||
textarea.text = key;
|
||||
int left = 0, right = 0, top = 0, bottom = 0;
|
||||
for (const cv::Point& pt : good_points) {
|
||||
if (pt.x < left || left == 0) {
|
||||
left = pt.x;
|
||||
}
|
||||
if (pt.x > right || right == 0) {
|
||||
right = pt.x;
|
||||
}
|
||||
if (pt.y < top || top == 0) {
|
||||
top = pt.y;
|
||||
}
|
||||
if (pt.y > bottom || bottom == 0) {
|
||||
bottom = pt.y;
|
||||
}
|
||||
}
|
||||
textarea.rect = { left, top, right - left, bottom - top };
|
||||
//draw_rect = { left + 129, top, right - left, bottom - top };
|
||||
matched_text_area.emplace_back(std::move(textarea));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for debug
|
||||
cv::Mat text_mat = cv::imread(GetResourceDir() + "operators\\" + Utf8ToGbk(key) + ".png");
|
||||
|
||||
cv::Mat approach_mat;
|
||||
cv::drawMatches(text_mat, query_keypoints, mat, train_keypoints, ransac_matchs, approach_mat);
|
||||
|
||||
cv::Mat good_mat;
|
||||
cv::drawMatches(text_mat, query_keypoints, mat, train_keypoints, good_matchs, good_mat);
|
||||
else {
|
||||
return std::nullopt;
|
||||
}
|
||||
return matched_text_area;
|
||||
}
|
||||
|
||||
void Identify::clear_cache()
|
||||
|
||||
@@ -372,7 +372,7 @@ std::shared_ptr<TaskInfo> ProcessTask::match_image(Rect* matched_rect)
|
||||
break;
|
||||
}
|
||||
|
||||
callback_json["rect"] = json::array({ rect.x, rect.y, rect.width, rect.height });
|
||||
callback_json["elite_rect"] = json::array({ rect.x, rect.y, rect.width, rect.height });
|
||||
callback_json["name"] = task_name;
|
||||
if (matched_rect != NULL) {
|
||||
*matched_rect = std::move(rect);
|
||||
@@ -630,7 +630,7 @@ bool OpenRecruitTask::run()
|
||||
task_json["type"] = "ClickTask";
|
||||
for (const TextArea& text_area : all_tags) {
|
||||
if (std::find(final_tags_name.cbegin(), final_tags_name.cend(), text_area.text) != final_tags_name.cend()) {
|
||||
task_json["rect"] = json::array({ text_area.rect.x, text_area.rect.y, text_area.rect.width, text_area.rect.height });
|
||||
task_json["elite_rect"] = json::array({ text_area.rect.x, text_area.rect.y, text_area.rect.width, text_area.rect.height });
|
||||
task_json["retry_times"] = m_retry_times;
|
||||
task_json["task_chain"] = m_task_chain;
|
||||
m_callback(AsstMsg::AppendTask, task_json, m_callback_arg);
|
||||
@@ -685,6 +685,53 @@ bool TestOcrTask::run()
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> all_oper_combs; // 所有的干员组合
|
||||
std::unordered_set<std::string> all_oper_name; // 所有干员名
|
||||
std::string oper_end_flag; // 干员名结束标记,识别到这个string就认为识别完成了
|
||||
std::unordered_map<std::string, std::string> feature_cond_default; // 特征检测关键字,如果OCR识别到了key的内容但是却没有value的内容,则进行特征检测进一步确认
|
||||
std::unordered_set<std::string> feature_whatever_default; // 无论如何都进行特征检测的
|
||||
|
||||
all_oper_combs = InfrastConfiger::get_instance().m_mfg_combs;
|
||||
all_oper_name = InfrastConfiger::get_instance().m_mfg_opers;
|
||||
oper_end_flag = InfrastConfiger::get_instance().m_mfg_end;
|
||||
feature_cond_default = InfrastConfiger::get_instance().m_mfg_feat;
|
||||
feature_whatever_default = InfrastConfiger::get_instance().m_mfg_feat_whatever;
|
||||
|
||||
std::unordered_map<std::string, std::string> feature_cond = feature_cond_default;
|
||||
std::unordered_set<std::string> feature_whatever = feature_whatever_default;
|
||||
|
||||
auto detect_foo = [&](const cv::Mat& image) -> std::vector<TextArea> {
|
||||
std::vector<TextArea> all_text_area = ocr_detect(image);
|
||||
/* 过滤出所有制造站中的干员名 */
|
||||
std::vector<TextArea> cur_name_textarea = text_search(
|
||||
all_text_area,
|
||||
all_oper_name,
|
||||
Configer::get_instance().m_infrast_ocr_replace);
|
||||
return cur_name_textarea;
|
||||
};
|
||||
|
||||
const cv::Mat& image = get_format_image(true);
|
||||
auto cur_name_textarea = detect_foo(image);
|
||||
|
||||
// for debug
|
||||
cv::Mat elite1 = cv::imread(GetResourceDir() + "operators\\Elite1.png");
|
||||
cv::Mat elite2 = cv::imread(GetResourceDir() + "operators\\Elite2.png");
|
||||
for (const TextArea& textarea : cur_name_textarea)
|
||||
{
|
||||
cv::Rect elite_rect;
|
||||
elite_rect.x = textarea.rect.x - 200;
|
||||
elite_rect.y = textarea.rect.y - 200;
|
||||
elite_rect.width = 200;
|
||||
elite_rect.height = 150;
|
||||
auto&& [socre1, point1] = m_identify_ptr->match_template(image(elite_rect), elite1);
|
||||
auto&& [socre2, point2] = m_identify_ptr->match_template(image(elite_rect), elite2);
|
||||
|
||||
std::cout << Utf8ToGbk(textarea.text) << " elite1: " << socre1 << ", eilte2: " << socre2 << std::endl;
|
||||
|
||||
//m_identify_ptr->feature_match(image(elite_rect), "Elite1");
|
||||
//m_identify_ptr->feature_match(image(elite_rect), "Elite2");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using namespace asst;
|
||||
|
||||
void test_dorm(Assistance* ptr);
|
||||
void test_ocr(Assistance* ptr);
|
||||
void test_swipe(Assistance* ptr);
|
||||
void test_infrast(Assistance* ptr);
|
||||
|
||||
@@ -24,7 +24,7 @@ int main(int argc, char** argv)
|
||||
char ch = 0;
|
||||
while (ch != 'q') {
|
||||
|
||||
test_infrast(ptr);
|
||||
test_ocr(ptr);
|
||||
//test_swipe(ptr);
|
||||
|
||||
ch = getchar();
|
||||
@@ -43,7 +43,7 @@ void test_swipe(Assistance* ptr)
|
||||
AsstTestSwipe(ptr, 1000, 300, 500, 300);
|
||||
}
|
||||
|
||||
void test_dorm(Assistance* ptr)
|
||||
void test_ocr(Assistance* ptr)
|
||||
{
|
||||
const char* text_array[] = { "×¢ÒâÁ¦" };
|
||||
|
||||
|
||||
BIN
resource/operators/Elite1.png
Normal file
BIN
resource/operators/Elite1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
resource/operators/Elite2.png
Normal file
BIN
resource/operators/Elite2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Reference in New Issue
Block a user