feat.新增ProcessTask单张图片ocr缓存的功能,原先的区域缓存更名为历史区域功能

This commit is contained in:
MistEO
2021-09-29 17:57:42 +08:00
parent d60ff2bb77
commit 5e2f421616
4 changed files with 119 additions and 64 deletions

View File

@@ -72,6 +72,10 @@ namespace asst {
}
Rect& operator=(const Rect&) noexcept = default;
Rect& operator=(Rect&&) noexcept = default;
bool operator==(const Rect& rhs) const noexcept
{
return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
}
int x = 0;
int y = 0;
@@ -93,6 +97,10 @@ namespace asst {
operator std::string() const { return text; }
TextArea& operator=(const TextArea&) = default;
TextArea& operator=(TextArea&&) noexcept = default;
bool operator==(const TextArea& rhs) const noexcept
{
return text == rhs.text && rect == rhs.rect;
}
std::string text;
Rect rect;
@@ -150,8 +158,8 @@ namespace asst {
bool need_match = false; // 是否需要全匹配,否则搜索到子串就算匹配上了
std::unordered_map<std::string, std::string>
replace_map; // 部分文字容易识别错字符串强制replace之后再进行匹配
bool cache = false; // 是否使用缓存区域上次处理该任务时在一些rect里识别到过text这次优先在这些rect里识别省点性能
std::vector<Rect> cache_area; // 识别缓存区域
bool cache = false; // 是否使用历史区域
std::vector<Rect> history_area; // 历史区域上次处理该任务时在一些rect里识别到过text这次优先在这些rect里识别省点性能
};
// 图片匹配任务的信息
@@ -231,4 +239,24 @@ namespace std {
return std::hash<std::string>()(info.name);
}
};
template<>
class hash<asst::Rect> {
public:
size_t operator()(const asst::Rect& rect) const
{
return std::hash<int>()(rect.x)
^ std::hash<int>()(rect.y)
^ std::hash<int>()(rect.width)
^ std::hash<int>()(rect.height);
}
};
template<>
class hash<asst::TextArea> {
public:
size_t operator()(const asst::TextArea& textarea) const
{
return std::hash<std::string>()(textarea.text)
^ std::hash<asst::Rect>()(textarea.rect);
}
};
}

View File

@@ -20,10 +20,12 @@ namespace asst {
bool click_text(const cv::Mat& image, const std::string& text);
// 文字匹配,要求相等
template<typename FilterArray, typename ReplaceMap>
std::vector<TextArea> text_match(const std::vector<TextArea>& src,
template<typename TextAreaArray, typename FilterArray, typename ReplaceMap>
std::vector<TextArea> text_match(const TextAreaArray& src,
const FilterArray& filter_array, const ReplaceMap& replace_map)
{
static_assert(std::is_constructible<TextArea, TextAreaArray::value_type>::value,
"Parameter can't be used to construct a asst::TextArea");
std::vector<TextArea> dst;
for (const TextArea& text_area : src) {
TextArea temp = text_area;
@@ -39,10 +41,12 @@ namespace asst {
return dst;
}
// 文字匹配,要求相等
template<typename FilterArray>
std::vector<TextArea> text_match(const std::vector<TextArea>& src,
template<typename TextAreaArray, typename FilterArray>
std::vector<TextArea> text_match(const TextAreaArray& src,
const FilterArray& filter_array)
{
static_assert(std::is_constructible<TextArea, TextAreaArray::value_type>::value,
"Parameter can't be used to construct a asst::TextArea");
std::vector<TextArea> dst;
for (const TextArea& text_area : src) {
for (const auto& text : filter_array) {
@@ -55,10 +59,12 @@ namespace asst {
}
// 文字搜索,是子串即可
template<typename FilterArray, typename ReplaceMap>
std::vector<TextArea> text_search(const std::vector<TextArea>& src,
template<typename TextAreaArray, typename FilterArray, typename ReplaceMap>
std::vector<TextArea> text_search(const TextAreaArray& src,
const FilterArray& filter_array, const ReplaceMap& replace_map)
{
static_assert(std::is_constructible<TextArea, TextAreaArray::value_type>::value,
"Parameter can't be used to construct a asst::TextArea");
std::vector<TextArea> dst;
for (const TextArea& text_area : src) {
TextArea temp = text_area;
@@ -73,10 +79,12 @@ namespace asst {
}
return dst;
}
template<typename FilterArray>
std::vector<TextArea> text_search(const std::vector<TextArea>& src,
template<typename TextAreaArray, typename FilterArray>
std::vector<TextArea> text_search(const TextAreaArray& src,
const FilterArray& filter_array)
{
static_assert(std::is_constructible<TextArea, TextAreaArray::value_type>::value,
"Parameter can't be used to construct a asst::TextArea");
std::vector<TextArea> dst;
for (const TextArea& text_area : src) {
for (const auto& text : filter_array) {

View File

@@ -33,6 +33,9 @@ bool ProcessTask::run()
Rect rect;
task_info_ptr = match_image(&rect);
if (need_exit()) {
return false;
}
if (!task_info_ptr) {
m_callback(AsstMsg::ProcessTaskNotMatched, task_start_json, m_callback_arg);
return false;
@@ -60,8 +63,7 @@ bool ProcessTask::run()
}
// 前置固定延时
if (!sleep(task_info_ptr->pre_delay))
{
if (!sleep(task_info_ptr->pre_delay)) {
return false;
}
@@ -132,13 +134,17 @@ bool ProcessTask::run()
std::shared_ptr<TaskInfo> ProcessTask::match_image(Rect* matched_rect)
{
const cv::Mat& cur_image = m_controller_ptr->get_image();
if (cur_image.empty() || cur_image.rows < 100) {
if (cur_image.empty()) {
m_callback(AsstMsg::ImageIsEmpty, json::value(), m_callback_arg);
return nullptr;
}
std::unordered_set<TextArea> ocr_cache;
// 逐个匹配当前可能的任务
for (const std::string& task_name : m_cur_tasks_name) {
if (need_exit()) {
return nullptr;
}
std::shared_ptr<TaskInfo> task_info_ptr = TaskConfiger::get_instance().m_all_tasks_info[task_name];
if (task_info_ptr == nullptr) { // 说明配置文件里没这个任务
m_callback(AsstMsg::PtrIsNull, json::value(), m_callback_arg);
@@ -198,71 +204,84 @@ std::shared_ptr<TaskInfo> ProcessTask::match_image(Rect* matched_rect)
{
std::shared_ptr<OcrTaskInfo> ocr_task_info_ptr =
std::dynamic_pointer_cast<OcrTaskInfo>(task_info_ptr);
std::vector<TextArea> match_result;
auto identify_roi = [&](const cv::Mat& roi) -> bool {
std::vector<TextArea> all_text_area = ocr_detect(roi);
if (ocr_task_info_ptr->need_match) {
match_result = text_match(all_text_area,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
else {
match_result = text_search(all_text_area,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
if (!match_result.empty()) {
return true;
}
else {
return false;
}
};
// 先在缓存的区域里识别
Rect roi_area;
for (const auto& cache_area : ocr_task_info_ptr->cache_area) {
Rect roi_rect = cache_area.center_zoom(2.0, Configer::WindowWidthDefault, Configer::WindowHeightDefault);
cv::Mat roi_image = cur_image(make_rect<cv::Rect>(roi_rect));
if (identify_roi(roi_image)) {
roi_area = roi_rect;
callback_json["algorithm"] = "OcrDetectRoi";
callback_json["roi"] = make_rect<json::array>(roi_rect);
break;
}
if (ocr_task_info_ptr->need_match) {
match_result = text_match(ocr_cache,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
// 如果缓存的区域里没识别到,那再在用完整的/默认区域识别一次
else {
match_result = text_search(ocr_cache,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
Rect matched_roi_rect;
if (match_result.empty()) {
const auto& identify_area = m_controller_ptr->shaped_correct(ocr_task_info_ptr->identify_area);
if (identify_area.width == 0) {
if (identify_roi(cur_image)) {
roi_area = Rect(0, 0, cur_image.cols, cur_image.rows);
auto identify_roi = [&](const Rect roi) -> bool {
cv::Mat roi_image = cur_image(make_rect<cv::Rect>(roi));
std::vector<TextArea> all_text_area = ocr_detect(roi_image);
// 加入ocr识别缓存
for (const TextArea& textarea : all_text_area) {
Rect cor_rect = textarea.rect;
cor_rect.x += roi.x;
cor_rect.y += roi.y;
ocr_cache.emplace(textarea.text, cor_rect);
}
if (ocr_task_info_ptr->need_match) {
match_result = text_match(all_text_area,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
else {
match_result = text_search(all_text_area,
ocr_task_info_ptr->text, ocr_task_info_ptr->replace_map);
}
if (!match_result.empty()) {
matched_roi_rect = roi;
return true;
}
else {
return false;
}
};
// 先在历史区域里识别
for (const auto& history_area : ocr_task_info_ptr->history_area) {
Rect roi_rect = history_area.center_zoom(2.0, Configer::WindowWidthDefault, Configer::WindowHeightDefault);
if (identify_roi(roi_rect)) {
callback_json["algorithm"] = "OcrDetectRoi";
callback_json["roi"] = make_rect<json::array>(roi_rect);
break;
}
}
else {
cv::Mat roi_image = cur_image(make_rect<cv::Rect>(identify_area));
if (identify_roi(roi_image)) {
roi_area = identify_area;
// 如果历史区域里没识别到,那再在用完整的/默认区域识别一次
if (match_result.empty()) {
const auto& identify_area = m_controller_ptr->shaped_correct(ocr_task_info_ptr->identify_area);
if (identify_area.width == 0) {
Rect full(0, 0, cur_image.cols, cur_image.rows);
identify_roi(full);
}
}
// 把本次识别到的区域加入到缓存里
if (ocr_task_info_ptr->cache) {
for (const auto& textarea : match_result) {
Rect cache_area = textarea.rect;
cache_area.x += roi_area.x;
cache_area.y += roi_area.y;
ocr_task_info_ptr->cache_area.emplace_back(std::move(cache_area));
else {
identify_roi(identify_area);
}
// 把本次识别到的区域加入历史区域
if (ocr_task_info_ptr->cache) {
for (const auto& textarea : match_result) {
Rect history_area = textarea.rect;
history_area.x += matched_roi_rect.x;
history_area.y += matched_roi_rect.y;
ocr_task_info_ptr->history_area.emplace_back(std::move(history_area));
}
}
callback_json["algorithm"] = "OcrDetect";
}
callback_json["algorithm"] = "OcrDetect";
}
// TODO如果搜出来多个结果怎么处理
// 暂时通过配置文件保证尽量只搜出来一个结果or一个都搜不到
if (!match_result.empty()) {
callback_json["text"] = match_result.at(0).text;
rect = match_result.at(0).rect;
rect.x += roi_area.x;
rect.y += roi_area.y;
rect.x += matched_roi_rect.x;
rect.y += matched_roi_rect.y;
matched = true;
}
}

View File

@@ -5,7 +5,7 @@
#include <unordered_map>
namespace asst {
class TaskInfo;
struct TaskInfo;
class TaskConfiger : public AbstractConfiger
{