blob: fad0a0cbeafdbc1fed577c7283cf0941bc48a7f1 [file] [log] [blame]
Parker Schuh2a1447c2019-02-17 00:25:29 -08001#include <Eigen/Dense>
2#include <iostream>
3
4#include "y2019/vision/target_finder.h"
5
6#include "aos/vision/blob/move_scale.h"
7#include "aos/vision/blob/stream_view.h"
8#include "aos/vision/blob/transpose.h"
9#include "aos/vision/debug/debug_framework.h"
10#include "aos/vision/math/vector.h"
11
12using aos::vision::ImageRange;
13using aos::vision::ImageFormat;
14using aos::vision::RangeImage;
15using aos::vision::AnalysisAllocator;
16using aos::vision::BlobList;
17using aos::vision::Vector;
18using aos::vision::Segment;
19using aos::vision::PixelRef;
20
21namespace y2019 {
22namespace vision {
23
24std::vector<PixelRef> GetNColors(size_t num_colors) {
25 std::vector<PixelRef> colors;
26 for (size_t i = 0; i < num_colors; ++i) {
27 int quadrent = i * 6 / num_colors;
28 uint8_t alpha = (256 * 6 * i - quadrent * num_colors * 256) / num_colors;
29 uint8_t inv_alpha = 255 - alpha;
30 switch (quadrent) {
31 case 0:
32 colors.push_back(PixelRef{255, alpha, 0});
33 break;
34 case 1:
35 colors.push_back(PixelRef{inv_alpha, 255, 0});
36 break;
37 case 2:
38 colors.push_back(PixelRef{0, 255, alpha});
39 break;
40 case 3:
41 colors.push_back(PixelRef{0, inv_alpha, 255});
42 break;
43 case 4:
44 colors.push_back(PixelRef{alpha, 0, 255});
45 break;
46 case 5:
47 colors.push_back(PixelRef{255, 0, inv_alpha});
48 break;
49 }
50 }
51 return colors;
52}
53
54class FilterHarness : public aos::vision::FilterHarness {
55 public:
56 aos::vision::RangeImage Threshold(aos::vision::ImagePtr image) override {
57 return finder_.Threshold(image);
58 }
59
60 void InstallViewer(aos::vision::BlobStreamViewer *viewer) override {
61 viewer_ = viewer;
Austin Schuh9e5ca2b2019-03-06 20:43:17 -080062 viewer_->SetScale(2.0);
Parker Schuh2a1447c2019-02-17 00:25:29 -080063 overlays_.push_back(&overlay_);
64 overlays_.push_back(finder_.GetOverlay());
65 viewer_->view()->SetOverlays(&overlays_);
66 }
67
68 void DrawBlob(const RangeImage &blob, PixelRef color) {
69 if (viewer_) {
70 BlobList list;
71 list.push_back(blob);
72 viewer_->DrawBlobList(list, color);
73 }
74 }
75
76 bool HandleBlobs(BlobList imgs, ImageFormat fmt) override {
77 imgs_last_ = imgs;
78 fmt_last_ = fmt;
79 // reset for next drawing cycle
80 for (auto &overlay : overlays_) {
81 overlay->Reset();
82 }
83
84 if (draw_select_blob_ || draw_raw_poly_ || draw_components_ ||
85 draw_raw_target_ || draw_raw_IR_ || draw_results_) {
86 printf("_____ New Image _____\n");
87 }
88
89 // Remove bad blobs.
90 finder_.PreFilter(&imgs);
91
92 // Find polygons from blobs.
93 std::vector<std::vector<Segment<2>>> raw_polys;
94 for (const RangeImage &blob : imgs) {
Ben Fredricksonf7b68522019-03-02 21:19:42 -080095 // Convert blobs to contours in the corrected space.
96 ContourNode* contour = finder_.GetContour(blob);
97 if (draw_contours_) {
98 DrawContour(contour, {255, 0, 0});
99 }
Austin Schuhe5015972019-03-09 17:47:34 -0800100 const ::std::vector<::Eigen::Vector2f> unwarped_contour =
101 finder_.UnWarpContour(contour);
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800102 if (draw_contours_) {
Austin Schuhe5015972019-03-09 17:47:34 -0800103 DrawContour(unwarped_contour, {0, 0, 255});
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800104 }
105
106 // Process to polygons.
Parker Schuh2a1447c2019-02-17 00:25:29 -0800107 std::vector<Segment<2>> polygon =
Austin Schuhe5015972019-03-09 17:47:34 -0800108 finder_.FillPolygon(unwarped_contour, draw_raw_poly_);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800109 if (polygon.empty()) {
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800110 if (!draw_contours_) {
111 DrawBlob(blob, {255, 0, 0});
112 }
Parker Schuh2a1447c2019-02-17 00:25:29 -0800113 } else {
114 raw_polys.push_back(polygon);
115 if (draw_select_blob_) {
116 DrawBlob(blob, {0, 0, 255});
117 }
118 if (draw_raw_poly_) {
119 std::vector<PixelRef> colors = GetNColors(polygon.size());
120 std::vector<Vector<2>> corners;
Austin Schuhe5015972019-03-09 17:47:34 -0800121 for (size_t i = 0; i < polygon.size(); ++i) {
122 corners.push_back(
123 polygon[i].Intersect(polygon[(i + 1) % polygon.size()]));
Parker Schuh2a1447c2019-02-17 00:25:29 -0800124 }
125
Austin Schuhe5015972019-03-09 17:47:34 -0800126 for (size_t i = 0; i < polygon.size(); ++i) {
127 overlay_.AddLine(corners[i], corners[(i + 1) % polygon.size()],
128 colors[i]);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800129 }
130 }
131 }
132 }
133
134 // Calculate each component side of a possible target.
135 std::vector<TargetComponent> target_component_list =
136 finder_.FillTargetComponentList(raw_polys);
137 if (draw_components_) {
138 for (const TargetComponent &comp : target_component_list) {
139 DrawComponent(comp, {0, 255, 255}, {0, 255, 255}, {255, 0, 0},
140 {0, 0, 255});
141 }
142 }
143
144 // Put the compenents together into targets.
145 std::vector<Target> target_list = finder_.FindTargetsFromComponents(
146 target_component_list, draw_raw_target_);
147 if (draw_raw_target_) {
148 for (const Target &target : target_list) {
149 DrawTarget(target);
150 }
151 }
152
153 // Use the solver to generate an intermediate version of our results.
154 std::vector<IntermediateResult> results;
155 for (const Target &target : target_list) {
Ben Fredricksona8c3d552019-03-03 14:14:53 -0800156 results.emplace_back(finder_.ProcessTargetToResult(target, draw_raw_IR_));
Parker Schuh2a1447c2019-02-17 00:25:29 -0800157 if (draw_raw_IR_) DrawResult(results.back(), {255, 128, 0});
158 }
159
160 // Check that our current results match possible solutions.
Ben Fredricksona8c3d552019-03-03 14:14:53 -0800161 results = finder_.FilterResults(results, 0);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800162 if (draw_results_) {
163 for (const IntermediateResult &res : results) {
Parker Schuh2a1447c2019-02-17 00:25:29 -0800164 DrawTarget(res, {0, 255, 0});
165 }
166 }
167
168 // If the target list is not empty then we found a target.
169 return !results.empty();
170 }
171
172 std::function<void(uint32_t)> RegisterKeyPress() override {
173 return [this](uint32_t key) {
174 (void)key;
175 if (key == 'z') {
176 draw_results_ = !draw_results_;
177 } else if (key == 'x') {
178 draw_raw_IR_ = !draw_raw_IR_;
179 } else if (key == 'c') {
180 draw_raw_target_ = !draw_raw_target_;
181 } else if (key == 'v') {
182 draw_components_ = !draw_components_;
183 } else if (key == 'b') {
184 draw_raw_poly_ = !draw_raw_poly_;
185 } else if (key == 'n') {
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800186 draw_contours_ = !draw_contours_;
187 } else if (key == 'm') {
Parker Schuh2a1447c2019-02-17 00:25:29 -0800188 draw_select_blob_ = !draw_select_blob_;
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800189 } else if (key == 'h') {
190 printf("Key Mappings:\n");
191 printf(" z: Toggle drawing final target pose.\n");
192 printf(" x: Toggle drawing re-projected targets and print solver results.\n");
193 printf(" c: Toggle drawing proposed target groupings.\n");
194 printf(" v: Toggle drawing ordered target components.\n");
195 printf(" b: Toggle drawing proposed target components.\n");
196 printf(" n: Toggle drawing countours before and after warping.\n");
197 printf(" m: Toggle drawing raw blob data (may need to change image to toggle a redraw).\n");
198 printf(" h: Print this message.\n");
Ben Fredricksona8c3d552019-03-03 14:14:53 -0800199 printf(" a: May log camera image to /tmp/debug_viewer_jpeg_<#>.yuyv\n");
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800200 printf(" q: Exit the application.\n");
Parker Schuh2a1447c2019-02-17 00:25:29 -0800201 } else if (key == 'q') {
202 printf("User requested shutdown.\n");
203 exit(0);
204 }
205 HandleBlobs(imgs_last_, fmt_last_);
206 viewer_->Redraw();
207 };
208 }
209
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800210 void DrawContour(ContourNode *contour, PixelRef color) {
211 if (viewer_) {
212 for (ContourNode *node = contour; node->next != contour;) {
213 Vector<2> a(node->pt.x, node->pt.y);
214 Vector<2> b(node->next->pt.x, node->next->pt.y);
215 overlay_.AddLine(a, b, color);
216 node = node->next;
217 }
218 }
219 }
220
Austin Schuhe5015972019-03-09 17:47:34 -0800221 void DrawContour(const ::std::vector<::Eigen::Vector2f> &contour,
222 PixelRef color) {
223 if (viewer_) {
224 for (size_t i = 0; i < contour.size(); ++i) {
225 Vector<2> a(contour[i].x(), contour[i].y());
226 Vector<2> b(contour[(i + 1) % contour.size()].x(),
227 contour[(i + 1) % contour.size()].y());
228 overlay_.AddLine(a, b, color);
229 }
230 }
231 }
232
Parker Schuh2a1447c2019-02-17 00:25:29 -0800233 void DrawComponent(const TargetComponent &comp, PixelRef top_color,
234 PixelRef bot_color, PixelRef in_color,
235 PixelRef out_color) {
236 overlay_.AddLine(comp.top, comp.inside, top_color);
237 overlay_.AddLine(comp.bottom, comp.outside, bot_color);
238
239 overlay_.AddLine(comp.bottom, comp.inside, in_color);
240 overlay_.AddLine(comp.top, comp.outside, out_color);
241 }
242
243 void DrawTarget(const Target &target) {
244 Vector<2> leftTop = (target.left.top + target.left.inside) * 0.5;
245 Vector<2> rightTop = (target.right.top + target.right.inside) * 0.5;
246 overlay_.AddLine(leftTop, rightTop, {255, 215, 0});
247
248 Vector<2> leftBot = (target.left.bottom + target.left.outside) * 0.5;
249 Vector<2> rightBot = (target.right.bottom + target.right.outside) * 0.5;
250 overlay_.AddLine(leftBot, rightBot, {255, 215, 0});
251
252 overlay_.AddLine(leftTop, leftBot, {255, 215, 0});
253 overlay_.AddLine(rightTop, rightBot, {255, 215, 0});
254 }
255
256 void DrawResult(const IntermediateResult &result, PixelRef color) {
257 Target target =
258 Project(finder_.GetTemplateTarget(), intrinsics(), result.extrinsics);
259 DrawComponent(target.left, color, color, color, color);
260 DrawComponent(target.right, color, color, color, color);
261 }
262
263 void DrawTarget(const IntermediateResult &result, PixelRef color) {
264 Target target =
265 Project(finder_.GetTemplateTarget(), intrinsics(), result.extrinsics);
266 Segment<2> leftAx((target.left.top + target.left.inside) * 0.5,
267 (target.left.bottom + target.left.outside) * 0.5);
268 leftAx.Set(leftAx.A() * 0.9 + leftAx.B() * 0.1,
269 leftAx.B() * 0.9 + leftAx.A() * 0.1);
270 overlay_.AddLine(leftAx, color);
271
272 Segment<2> rightAx((target.right.top + target.right.inside) * 0.5,
273 (target.right.bottom + target.right.outside) * 0.5);
274 rightAx.Set(rightAx.A() * 0.9 + rightAx.B() * 0.1,
275 rightAx.B() * 0.9 + rightAx.A() * 0.1);
276 overlay_.AddLine(rightAx, color);
277
278 overlay_.AddLine(leftAx.A(), rightAx.A(), color);
279 overlay_.AddLine(leftAx.B(), rightAx.B(), color);
280 Vector<3> p1(0.0, 0.0, 100.0);
281
282 Vector<3> p2 =
283 Rotate(intrinsics().mount_angle, result.extrinsics.r1, 0.0, p1);
284 Vector<2> p3(p2.x(), p2.y());
285 overlay_.AddLine(leftAx.A(), p3 + leftAx.A(), {0, 255, 0});
286 overlay_.AddLine(leftAx.B(), p3 + leftAx.B(), {0, 255, 0});
287 overlay_.AddLine(rightAx.A(), p3 + rightAx.A(), {0, 255, 0});
288 overlay_.AddLine(rightAx.B(), p3 + rightAx.B(), {0, 255, 0});
289
290 overlay_.AddLine(p3 + leftAx.A(), p3 + leftAx.B(), {0, 255, 0});
291 overlay_.AddLine(p3 + leftAx.A(), p3 + rightAx.A(), {0, 255, 0});
292 overlay_.AddLine(p3 + rightAx.A(), p3 + rightAx.B(), {0, 255, 0});
293 overlay_.AddLine(p3 + leftAx.B(), p3 + rightAx.B(), {0, 255, 0});
294 }
295
296 const IntrinsicParams &intrinsics() const { return finder_.intrinsics(); }
297
298 private:
299 // implementation of the filter pipeline.
300 TargetFinder finder_;
301 aos::vision::BlobStreamViewer *viewer_ = nullptr;
302 aos::vision::PixelLinesOverlay overlay_;
303 std::vector<aos::vision::OverlayBase *> overlays_;
304 BlobList imgs_last_;
305 ImageFormat fmt_last_;
306 bool draw_select_blob_ = false;
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800307 bool draw_contours_ = false;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800308 bool draw_raw_poly_ = false;
309 bool draw_components_ = false;
310 bool draw_raw_target_ = false;
311 bool draw_raw_IR_ = false;
312 bool draw_results_ = true;
313};
314
315} // namespace vision
316} // namespace y2017
317
318int main(int argc, char **argv) {
319 y2019::vision::FilterHarness filter_harness;
320 aos::vision::DebugFrameworkMain(argc, argv, &filter_harness,
321 aos::vision::CameraParams());
322}