表格线识别通用库文档
载入中...
搜索中...
未找到
debug.hpp
浏览该文件的文档.
1/*
2 * @Description: 调试类 头文件及其实现
3 * @Version:
4 * @Autor: dreamy-xay
5 * @date: 2023-12-06
6 * @LastEditors: dreamy-xay
7 * @LastEditTime: 2024-07-01
8 */
9
10#ifndef COMMON_DEBUG_HPP
11#define COMMON_DEBUG_HPP
12
13#include <iostream>
14#include <opencv2/core.hpp>
15#include <opencv2/imgcodecs.hpp>
16#include <opencv2/opencv.hpp>
17#include <string>
18
19#include "common/base/line.hpp"
20#include "common/base/rect.hpp"
21#include "common/base/scope.hpp"
23#include "common/enum.h"
24#include "common/macro.h"
25#include "common/type.h"
27
28namespace cm {
29
37class Debug {
38 private:
39 /* 计数器结构体 */
40 struct Counter {
41 private:
42 size_t count; // 计数器当前计数
43 size_t step; // 计数器自增步长
44
45 public:
46 Counter(size_t init_count = 0, size_t step = 1);
47 size_t GetCount();
48 };
49
50 mutable Scope<Counter> counter; // 多作用域下计数器
51 mutable Scope<std::string> output_image_name_suffix; // 多作用域下输出文件名后缀
52
53 bool is_enable_image_output; // 是否启用图片输出
54
55 public:
57 std::string output_image_path;
59 std::string image_name;
60
61 static Printer Print Cm_WEAK_ATTRIBUTE ; // 简单打印器
62 static ComplexPrinter CPrint Cm_WEAK_ATTRIBUTE ; // 复杂打印器,可以打印参数名
63
71 struct ConfigLines {
72 private:
73 const std::vector<Line> lines;
74 bool output_seq_num;
75 bool is_arrowed;
76 cv::Scalar line_color;
77 int line_thickness;
78 cv::Scalar text_color;
79 int text_thickness;
80
81 public:
82 ConfigLines(const std::vector<Line>& lines, bool output_seq_num = true, bool is_arrowed = true, const cv::Scalar& line_color = cv::Scalar(255, 0, 0), int line_thickness = 1, const cv::Scalar& text_color = cv::Scalar(0, 0, 255), int text_thickness = 1);
83 const ConfigLines& DrawLines(cv::Mat& image) const;
84 };
85
93 struct ConfigRects {
94 private:
95 const std::vector<Rect> rects;
96 bool output_seq_num;
97 cv::Scalar rect_color;
98 int rect_thickness;
99 cv::Scalar text_color;
100 int text_thickness;
101
102 public:
103 ConfigRects(const std::vector<Rect>& rects, bool output_seq_num = true, const cv::Scalar& rect_color = cv::Scalar(255, 0, 0), int rect_thickness = 2, const cv::Scalar& text_color = cv::Scalar(0, 0, 255), int text_thickness = 1);
104 const ConfigRects& DrawRects(cv::Mat& image) const;
105 };
106
107 /* Debug 类公有方法声明 */
108 Debug(const std::string& output_image_path = "", const std::string& image_name = "debug", bool is_enable_image_output = true);
109 ~Debug();
110
111 Debug& SetImageOutputStatus(bool is_enable_image_output);
112
113 const Debug& CounterStart(const std::string& counter_name = "__INITIAL__", size_t start = 0, size_t step = 1) const;
114 const Debug& CounterEnd() const;
115
116 const Debug& NamedStart(const std::string& image_name_suffix) const;
117 const Debug& NamedEnd() const;
118
119 const Debug& OutputImage(const std::string& image_name_suffix, const cv::Mat& image, const std::vector<ConfigLines>& lines_list = {}, const std::vector<ConfigRects>& rects_list = {}, bool is_print_image_path = false) const;
120 const Debug& OutputImage(const cv::Mat& image, const std::vector<ConfigLines>& lines_list = {}, const std::vector<ConfigRects>& rects_list = {}, bool is_print_image_path = false) const;
121 const Debug& OutputHistogram(const std::string& image_name_suffix, const cv::Mat& histogram, int item_width = 4, bool is_print_image_path = false) const;
122 const Debug& OutputHistogram(const cv::Mat& histogram, int item_width = 4, bool is_print_image_path = false) const;
123};
124
135inline Debug::Counter::Counter(size_t init_count, size_t step) : count(init_count), step(step) {}
136
146inline size_t Debug::Counter::GetCount() {
147 size_t current_count = count; // 报存原计数器值
148 count += step; // 自增计数器
149 return current_count;
150}
151
177Printer Debug::Print;
178
207ComplexPrinter Debug::CPrint;
208
224inline Debug::ConfigLines::ConfigLines(const std::vector<Line>& lines, bool output_seq_num, bool is_arrowed, const cv::Scalar& line_color, int line_thickness, const cv::Scalar& text_color, int text_thickness) : lines(lines), output_seq_num(output_seq_num), is_arrowed(is_arrowed), line_color(line_color), line_thickness(line_thickness), text_color(text_color), text_thickness(text_thickness) {}
225
238 // 遍历所有线
239 for (int i = int(lines.size()) - 1; i >= 0; --i) {
240 if (output_seq_num)
241 cv::putText(image, std::to_string(i), lines[i].pt1, 1, 1, text_color, text_thickness); // 显示线的序号
242
243 if (is_arrowed)
244 cv::arrowedLine(image, lines[i].pt1, lines[i].pt2, line_color, line_thickness, 8, 0, 0.01); // 使用箭头线
245 else
246 cv::line(image, lines[i].pt1, lines[i].pt2, line_color, line_thickness); // 使用直线
247 }
248
249 return *this;
250}
251
266inline Debug::ConfigRects::ConfigRects(const std::vector<Rect>& rects, bool output_seq_num, const cv::Scalar& rect_color, int rect_thickness, const cv::Scalar& text_color, int text_thickness) : rects(rects), output_seq_num(output_seq_num), rect_color(rect_color), rect_thickness(rect_thickness), text_color(text_color), text_thickness(text_thickness) {}
267
280 // 遍历所有矩形
281 for (int i = int(rects.size()) - 1; i >= 0; --i) {
282 if (output_seq_num)
283 cv::putText(image, std::to_string(i), cv::Point(rects[i].x, rects[i].y), 1, 1, text_color, text_thickness); // 显示矩形的序号
284
285 cv::rectangle(image, rects[i], rect_color, rect_thickness); // 绘制矩形
286 }
287
288 return *this;
289}
290
302inline Debug::Debug(const std::string& output_image_path, const std::string& image_name, bool is_enable_image_output) : output_image_path(output_image_path), image_name(image_name), is_enable_image_output(is_enable_image_output), counter("__INITIAL__"), output_image_name_suffix("__INITIAL__") {}
303
311inline Debug::~Debug() {}
312
324inline Debug& Debug::SetImageOutputStatus(bool is_enable_image_output) {
325 this->is_enable_image_output = is_enable_image_output;
326}
327
348inline const Debug& Debug::CounterStart(const std::string& counter_name, size_t start, size_t step) const {
349 // 如果不存在计数器则创建
350 if (!counter.Has(counter_name))
351 counter.Set(counter_name, Counter(start, step));
352
353 // 存在计数器则切换
354 counter.Switch(counter_name);
355
356 return *this;
357}
358
425inline const Debug& Debug::CounterEnd() const {
426 // 完成当前计数器计数工作
427 counter.Finish();
428
429 return *this;
430}
431
449inline const Debug& Debug::NamedStart(const std::string& image_name_suffix) const {
450 // 断言默认图片名称不能为 "__INITIAL__"
451 Cm_Assert(image_name_suffix != "__INITIAL__", "image name cannot be \"__INITIAL__\"!");
452
453 // 如果不存在默认输出图片名则创建
454 if (!output_image_name_suffix.Has(image_name_suffix))
455 output_image_name_suffix.Set(image_name_suffix, image_name_suffix);
456
457 // 存在默认输出图片名则切换
458 output_image_name_suffix.Switch(image_name_suffix);
459
460 return *this;
461}
462
530inline const Debug& Debug::NamedEnd() const {
531 // 完成当前输出默认图片名工作
532 output_image_name_suffix.Finish();
533
534 return *this;
535}
536
554inline const Debug& Debug::OutputImage(const std::string& image_name_suffix, const cv::Mat& image, const std::vector<Debug::ConfigLines>& lines_list, const std::vector<Debug::ConfigRects>& rects_list, bool is_print_image_path) const {
555 // 如果不启用图片输出,则直接返回
556 if (!is_enable_image_output)
557 return *this;
558
559 cv::Mat output_image = image.clone(); // 克隆一份图片
560
561 for (auto& lines : lines_list) // 图片上画线
562 lines.DrawLines(output_image);
563
564 for (auto& rects : rects_list) // 图片上画矩形
565 rects.DrawRects(output_image);
566
567 bool use_counter = !counter.IsInitial(); // 图片名是否使用计数器
568
569 // 输出的图片路径
570 auto image_path = std::move(Sprintf("%s/%s%s%s%s%s.jpg", output_image_path.c_str(), image_name.c_str(), image_name_suffix.empty() ? "" : "_", image_name_suffix.c_str(), use_counter ? "_" : "", use_counter ? std::to_string(counter.Value().GetCount()).c_str() : ""));
571
573 CPrint("Output Image Path", image_path) << '\n';
574
575 // 输出图片
576 cv::imwrite(image_path, output_image);
577
578 return *this;
579}
580
599inline const Debug& Debug::OutputImage(const cv::Mat& image, const std::vector<Debug::ConfigLines>& lines_list, const std::vector<Debug::ConfigRects>& rects_list, bool is_print_image_path) const {
600 // 断言是否使用了NamedStart
601 Cm_Assert(!output_image_name_suffix.IsInitial(), "please call the \"NamedStart\"(or \"NamedSwitch\") function to set the name of the output image!!!");
602
603 this->OutputImage(output_image_name_suffix.Value(), image, lines_list, rects_list, is_print_image_path); // 使用 默认输出图片名 输出图片
604
605 return *this;
606}
607
622inline const Debug& Debug::OutputHistogram(const std::string& image_name_suffix, const cv::Mat& histogram, int item_width, bool is_print_image_path) const {
623 // 如果不启用图片输出,则直接返回
624 if (!is_enable_image_output)
625 return *this;
626
627 // 准备绘制直方图
628 int hist_w = histogram.rows * item_width + 40;
629 int hist_h = 200;
630 double max_val;
631 cv::Point max_val_point;
632
633 // 计算直方图中最大值
634 cv::minMaxLoc(histogram, nullptr, &max_val, nullptr, &max_val_point);
635
636 // 直方图缩放比率
637 double scale = 1.0;
638 // 控制直方图的有效高度不得超过 2000
639 if (max_val > 2000) {
640 scale = 2000.0 / max_val;
641 max_val = 2000.0;
642 }
643
644 hist_h += max_val;
645
646 cv::Mat hist_image = cv::Mat::zeros(hist_h, hist_w, CV_8UC3); // 准备 hist_image 为全黑背景色
647
648 for (int i = 0; i < histogram.rows; ++i)
649 cv::rectangle(hist_image, cv::Point(item_width * i + 20, hist_h - 100), cv::Point(item_width * (i + 1) + 20, hist_h - cvRound(histogram.at<float>(i) * scale) - 100), cv::Scalar(255, 255, 255), -1); // 绘制直方图中的每一项
650
651 // 输出直方图中最大值的灰度值
652 cv::putText(hist_image, std::to_string(max_val_point.y), cv::Point(item_width * (max_val_point.y + 1) + 10, hist_h - cvRound(histogram.at<float>(max_val_point.y) * scale) - 110), 1, 1, cv::Scalar(255, 255, 255));
653
654 bool use_counter = !counter.IsInitial(); // 图片名是否使用计数器
655
656 // 输出的图片路径
657 auto image_path = std::move(Sprintf("%s/%s%s%s%s%s.jpg", output_image_path.c_str(), image_name.c_str(), image_name_suffix.empty() ? "" : "_", image_name_suffix.c_str(), use_counter ? "_" : "", use_counter ? std::to_string(counter.Value().GetCount()).c_str() : ""));
658
660 CPrint("Output Histogram Image Path", image_path) << '\n';
661
662 // 输出图片
663 cv::imwrite(image_path, hist_image);
664
665 return *this;
666}
667
683inline const Debug& Debug::OutputHistogram(const cv::Mat& histogram, int item_width, bool is_print_image_path) const {
684 // 断言是否使用了NamedStart
685 Cm_Assert(!output_image_name_suffix.IsInitial(), "please call the \"NamedStart\" function to set the name of the output image!!!");
686
687 this->OutputHistogram(output_image_name_suffix.Value(), histogram, item_width, is_print_image_path); // 使用 默认输出图片名 输出直方图图片
688
689 return *this;
690}
691
692} // namespace cm
693
694#endif
复杂打印器类
调试类
Definition debug.hpp:37
static ComplexPrinter CPrint
复杂打印器
Definition debug.hpp:62
const Debug & OutputImage(const std::string &image_name_suffix, const cv::Mat &image, const std::vector< ConfigLines > &lines_list={}, const std::vector< ConfigRects > &rects_list={}, bool is_print_image_path=false) const
输出图片
Definition debug.hpp:554
const Debug & NamedStart(const std::string &image_name_suffix) const
设置默认的输出图片名后缀
Definition debug.hpp:449
const Debug & CounterStart(const std::string &counter_name="__INITIAL__", size_t start=0, size_t step=1) const
图片输出计数器开始计数
Definition debug.hpp:348
std::string image_name
图片名
Definition debug.hpp:59
~Debug()
调试类的析构函数
Definition debug.hpp:311
static Printer Print
简单打印器
Definition debug.hpp:61
const Debug & CounterEnd() const
图片输出计数器结束计数
Definition debug.hpp:425
std::string output_image_path
输出图片路径
Definition debug.hpp:57
const Debug & OutputHistogram(const std::string &image_name_suffix, const cv::Mat &histogram, int item_width=4, bool is_print_image_path=false) const
输出直方图
Definition debug.hpp:622
Debug & SetImageOutputStatus(bool is_enable_image_output)
设置图片输出状态
Definition debug.hpp:324
Debug(const std::string &output_image_path="", const std::string &image_name="debug", bool is_enable_image_output=true)
调试类的带参构造函数
Definition debug.hpp:302
const Debug & NamedEnd() const
撤销默认的输出图片名后缀的设置
Definition debug.hpp:530
点类
Definition point.hpp:52
T y
点的 y 坐标
Definition point.hpp:57
打印器类
Definition printer.hpp:32
#define Cm_Assert(expr, message)
断言宏
Definition macro.h:109
#define Cm_WEAK_ATTRIBUTE
弱符号定义宏
Definition macro.h:82
std::string Sprintf(const char *format,...)
格式化输出字符串
Definition string.hpp:47
带有打印配置参数的线列表
Definition debug.hpp:71
const ConfigLines & DrawLines(cv::Mat &image) const
在图片上绘制线
Definition debug.hpp:237
ConfigLines(const std::vector< Line > &lines, bool output_seq_num=true, bool is_arrowed=true, const cv::Scalar &line_color=cv::Scalar(255, 0, 0), int line_thickness=1, const cv::Scalar &text_color=cv::Scalar(0, 0, 255), int text_thickness=1)
带有打印配置参数的线列表的带参构造函数
Definition debug.hpp:224
带有打印配置参数的矩形列表
Definition debug.hpp:93
ConfigRects(const std::vector< Rect > &rects, bool output_seq_num=true, const cv::Scalar &rect_color=cv::Scalar(255, 0, 0), int rect_thickness=2, const cv::Scalar &text_color=cv::Scalar(0, 0, 255), int text_thickness=1)
带有打印配置参数的矩形列表的带参构造函数
Definition debug.hpp:266
const ConfigRects & DrawRects(cv::Mat &image) const
在图片上绘制矩形
Definition debug.hpp:279