blob: 3beb9e1511f5461d461547974e1615e99ee8de8f [file] [log] [blame]
Parker Schuh2cd173d2017-01-28 00:12:01 -08001#ifndef _AOS_VISION_IMAGE_DEBUG_OVERLAY_H_
2#define _AOS_VISION_IMAGE_DEBUG_OVERLAY_H_
3
4#include <string>
5#include <vector>
6
7#include "aos/vision/image/image_types.h"
8#include "aos/vision/math/segment.h"
9#include "aos/vision/math/vector.h"
10
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080011namespace aos::vision {
Parker Schuh2cd173d2017-01-28 00:12:01 -080012
13// Abstract away rendering to avoid compiling gtk for arm.
14// This should match a reduced cairo rendering api.
15class RenderInterface {
16 public:
17 RenderInterface() {}
18 RenderInterface(RenderInterface &&other) = delete;
19 RenderInterface(const RenderInterface &other) = delete;
20 ~RenderInterface() {}
21
22 virtual void Translate(double x, double y) = 0;
23 virtual void SetSourceRGB(double r, double g, double b) = 0;
24 virtual void MoveTo(double x, double y) = 0;
25 virtual void LineTo(double x, double y) = 0;
26 virtual void Circle(double x, double y, double r) = 0;
27 // negative in x, y, text_x, text_y measures from max in those value
28 virtual void Text(int x, int y, int text_x, int text_y,
29 const std::string &text) = 0;
30 virtual void Stroke() = 0;
31};
32
33// Interface for a list of overlays to be drawn onto a debug image.
34// These will be passed into the running vision algorithms to output debug info,
35// so they must not have costly side-effects.
36class OverlayBase {
37 public:
38 OverlayBase() {}
39 virtual ~OverlayBase() {}
40
41 // Draws this overlay to the given canvas.
42 virtual void Draw(RenderInterface *render, double /* width */,
43 double /* height */) = 0;
44
45 // Clears the entire overlay.
46 virtual void Reset() = 0;
47
48 PixelRef color = {255, 0, 0};
49 double scale = 1.0;
50};
51
52// A lambda that renders directly to the render interface.
53class LambdaOverlay : public OverlayBase {
54 public:
55 std::function<void(RenderInterface *, double, double)> draw_fn;
56 void Draw(RenderInterface *render, double width, double height) override {
57 if (draw_fn) draw_fn(render, width, height);
58 }
59 void Reset() override {}
60};
61
62// Lines rendered in a coordinate system where the origin is the center
63// of the screen
64class LinesOverlay : public OverlayBase {
65 public:
66 LinesOverlay() : OverlayBase() {}
67 ~LinesOverlay() {}
68
69 // build a segment for this line
70 void add_line(Vector<2> st, Vector<2> ed) { add_line(st, ed, color); }
71
72 // build a segment for this line
73 void add_line(Vector<2> st, Vector<2> ed, PixelRef newColor) {
74 lines_.emplace_back(
75 std::pair<Segment<2>, PixelRef>(Segment<2>(st, ed), newColor));
76 }
77
78 void add_point(Vector<2> pt) { add_point(pt, color); }
79
80 // add a new point connected to the last point in the line
81 void add_point(Vector<2> pt, PixelRef newColor) {
82 if (lines_.empty()) {
83 lines_.emplace_back(
84 std::pair<Segment<2>, PixelRef>(Segment<2>(pt, pt), newColor));
85 } else {
86 Vector<2> st = lines_.back().first.B();
87 lines_.emplace_back(
88 std::pair<Segment<2>, PixelRef>(Segment<2>(st, pt), newColor));
89 }
90 }
91
92 void Draw(RenderInterface *render, double w, double h) override {
93 render->Translate(w / 2.0, h / 2.0);
94 for (const auto &ln : lines_) {
95 PixelRef localColor = ln.second;
96 render->SetSourceRGB(localColor.r / 255.0, localColor.g / 255.0,
97 localColor.b / 255.0);
98 render->MoveTo(scale * ln.first.A().x(), -scale * ln.first.A().y());
99 render->LineTo(scale * ln.first.B().x(), -scale * ln.first.B().y());
100 render->Stroke();
101 }
102 }
103
104 // Empting the list will blank the whole overlay
105 void Reset() override { lines_.clear(); }
106
107 private:
108 // lines in this over lay
109 std::vector<std::pair<Segment<2>, PixelRef>> lines_;
110};
111
112// Lines rendered in pixel coordinates (Should match up with the screen.)
113class PixelLinesOverlay : public OverlayBase {
114 public:
115 PixelLinesOverlay() : OverlayBase() {}
116 ~PixelLinesOverlay() {}
117
118 // build a segment for this line
Parker Schuhef47dbf2017-03-04 16:59:30 -0800119 void AddLine(Vector<2> st, Vector<2> ed) { AddLine(st, ed, color); }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800120
121 // build a segment for this line
Parker Schuhef47dbf2017-03-04 16:59:30 -0800122 void AddLine(Vector<2> st, Vector<2> ed, PixelRef newColor) {
Parker Schuh02f13f62019-02-16 16:42:41 -0800123 AddLine(Segment<2>(st, ed), newColor);
124 }
125
126 // draw a segment.
127 void AddLine(Segment<2> seg, PixelRef newColor) {
128 lines_.emplace_back(std::pair<Segment<2>, PixelRef>(seg, newColor));
Parker Schuh2cd173d2017-01-28 00:12:01 -0800129 }
130
Austin Schuh7d2ef032019-03-10 14:59:34 -0700131 void DrawCross(::Eigen::Vector2f center, int width,
132 aos::vision::PixelRef color) {
133 DrawCross(aos::vision::Vector<2>(center.x(), center.y()), width, color);
134 }
135
Parker Schuhef47dbf2017-03-04 16:59:30 -0800136 void DrawCross(aos::vision::Vector<2> center, int width,
137 aos::vision::PixelRef color) {
138 using namespace aos::vision;
Parker Schuhcd258b82017-04-09 16:28:29 -0700139 AddLine(Vector<2>(center.x() - width / 2, center.y()),
140 Vector<2>(center.x() + width / 2, center.y()), color);
141 AddLine(Vector<2>(center.x(), center.y() - width / 2),
142 Vector<2>(center.x(), center.y() + width / 2), color);
Parker Schuhef47dbf2017-03-04 16:59:30 -0800143 }
144
145 void DrawBBox(const ImageBBox &box, aos::vision::PixelRef color) {
146 using namespace aos::vision;
147 AddLine(Vector<2>(box.minx, box.miny), Vector<2>(box.maxx, box.miny),
148 color);
149 AddLine(Vector<2>(box.maxx, box.miny), Vector<2>(box.maxx, box.maxy),
150 color);
151 AddLine(Vector<2>(box.maxx, box.maxy), Vector<2>(box.minx, box.maxy),
152 color);
153 AddLine(Vector<2>(box.minx, box.maxy), Vector<2>(box.minx, box.miny),
154 color);
155 }
156
Parker Schuhcd258b82017-04-09 16:28:29 -0700157 // Build a circle as a point and radius.
158 void DrawCircle(Vector<2> center, double radius, PixelRef newColor) {
159 circles_.emplace_back(std::pair<Vector<2>, std::pair<double, PixelRef>>(
160 center, std::pair<double, PixelRef>(radius, newColor)));
161 }
162
Parker Schuhef47dbf2017-03-04 16:59:30 -0800163 void StartNewProfile() { start_profile = true; }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800164
165 // add a new point connected to the last point in the line
Parker Schuhef47dbf2017-03-04 16:59:30 -0800166 void AddPoint(Vector<2> pt, PixelRef newColor) {
Parker Schuh2cd173d2017-01-28 00:12:01 -0800167 if (lines_.empty() || start_profile) {
168 lines_.emplace_back(
169 std::pair<Segment<2>, PixelRef>(Segment<2>(pt, pt), newColor));
170 start_profile = false;
171 } else {
172 Vector<2> st = lines_.back().first.B();
173 lines_.emplace_back(
174 std::pair<Segment<2>, PixelRef>(Segment<2>(st, pt), newColor));
175 }
176 }
177
178 void Draw(RenderInterface *render, double /*width*/,
179 double /*hieght*/) override {
180 for (const auto &ln : lines_) {
181 PixelRef localColor = ln.second;
182 render->SetSourceRGB(localColor.r / 255.0, localColor.g / 255.0,
183 localColor.b / 255.0);
184 render->MoveTo(ln.first.A().x(), ln.first.A().y());
185 render->LineTo(ln.first.B().x(), ln.first.B().y());
186 render->Stroke();
187 }
Parker Schuhcd258b82017-04-09 16:28:29 -0700188 for (const auto &circle : circles_) {
189 PixelRef localColor = circle.second.second;
190 render->SetSourceRGB(localColor.r / 255.0, localColor.g / 255.0,
191 localColor.b / 255.0);
192 render->Circle(circle.first.x(), circle.first.y(), circle.second.first);
193 render->Stroke();
194 }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800195 }
196
197 // Empting the list will blank the whole overlay.
Parker Schuhcd258b82017-04-09 16:28:29 -0700198 void Reset() override {
199 lines_.clear();
200 circles_.clear();
201 }
Parker Schuh2cd173d2017-01-28 00:12:01 -0800202
203 private:
204 // Lines in this overlay.
205 std::vector<std::pair<Segment<2>, PixelRef>> lines_;
Parker Schuhcd258b82017-04-09 16:28:29 -0700206 std::vector<std::pair<Vector<2>, std::pair<double, PixelRef>>> circles_;
Parker Schuh2cd173d2017-01-28 00:12:01 -0800207 bool start_profile = false;
208};
209
210// Circles rendered in a coordinate system where the origin is the center
211// of the screen.
212class CircleOverlay : public OverlayBase {
213 public:
214 CircleOverlay() : OverlayBase() {}
215 ~CircleOverlay() {}
216
217 // build a circle as a point and radius
218 std::pair<Vector<2>, double> *add_circle(Vector<2> center, double radius) {
219 circles_.emplace_back(std::pair<Vector<2>, double>(center, radius));
220 return &(circles_.back());
221 }
222
223 void Draw(RenderInterface *render, double w, double h) {
224 render->Translate(w / 2.0, h / 2.0);
225 render->SetSourceRGB(color.r / 255.0, color.g / 255.0, color.b / 255.0);
226 for (const auto &circle : circles_) {
227 render->Circle(scale * circle.first.x(), -scale * circle.first.y(),
228 scale * circle.second);
229 render->Stroke();
230 }
231 }
232
233 // empting the list will blank the whole overlay
234 void Reset() { circles_.clear(); }
235
236 private:
237 // circles in this overlay
238 std::vector<std::pair<Vector<2>, double>> circles_;
239};
240
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800241} // namespace aos::vision
Parker Schuh2cd173d2017-01-28 00:12:01 -0800242
243#endif // _AOS_VISION_IMAGE_DEBUG_OVERLAY_H_