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