blob: 1a93f87ef5a6b59c0502bbcf473c82572dbc94ac [file] [log] [blame]
Parker Schuh2a1447c2019-02-17 00:25:29 -08001#include <iostream>
2
Philipp Schrader790cb542023-07-05 21:06:52 -07003#include "gflags/gflags.h"
4#include <Eigen/Dense>
Parker Schuh2a1447c2019-02-17 00:25:29 -08005
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"
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "y2019/vision/target_finder.h"
Parker Schuh2a1447c2019-02-17 00:25:29 -080012
Parker Schuh2a1447c2019-02-17 00:25:29 -080013using aos::vision::AnalysisAllocator;
14using aos::vision::BlobList;
Philipp Schrader790cb542023-07-05 21:06:52 -070015using aos::vision::ImageFormat;
16using aos::vision::ImageRange;
Parker Schuh2a1447c2019-02-17 00:25:29 -080017using aos::vision::PixelRef;
Philipp Schrader790cb542023-07-05 21:06:52 -070018using aos::vision::RangeImage;
19using aos::vision::Segment;
20using aos::vision::Vector;
Parker Schuh2a1447c2019-02-17 00:25:29 -080021
Austin Schuh75921532019-03-09 18:46:34 -080022DEFINE_int32(camera, 10, "The camera to use the intrinsics for");
23
Stephan Pleinesf63bde82024-01-13 15:59:33 -080024namespace y2019::vision {
Parker Schuh2a1447c2019-02-17 00:25:29 -080025
26std::vector<PixelRef> GetNColors(size_t num_colors) {
27 std::vector<PixelRef> colors;
28 for (size_t i = 0; i < num_colors; ++i) {
29 int quadrent = i * 6 / num_colors;
30 uint8_t alpha = (256 * 6 * i - quadrent * num_colors * 256) / num_colors;
31 uint8_t inv_alpha = 255 - alpha;
32 switch (quadrent) {
33 case 0:
34 colors.push_back(PixelRef{255, alpha, 0});
35 break;
36 case 1:
37 colors.push_back(PixelRef{inv_alpha, 255, 0});
38 break;
39 case 2:
40 colors.push_back(PixelRef{0, 255, alpha});
41 break;
42 case 3:
43 colors.push_back(PixelRef{0, inv_alpha, 255});
44 break;
45 case 4:
46 colors.push_back(PixelRef{alpha, 0, 255});
47 break;
48 case 5:
49 colors.push_back(PixelRef{255, 0, inv_alpha});
50 break;
51 }
52 }
53 return colors;
54}
55
56class FilterHarness : public aos::vision::FilterHarness {
57 public:
Philipp Schrader790cb542023-07-05 21:06:52 -070058 FilterHarness() {
59 *(target_finder_.mutable_intrinsics()) =
60 GetCamera(FLAGS_camera)->intrinsics;
61 }
Parker Schuh2a1447c2019-02-17 00:25:29 -080062 aos::vision::RangeImage Threshold(aos::vision::ImagePtr image) override {
Austin Schuh75921532019-03-09 18:46:34 -080063 return target_finder_.Threshold(image);
Parker Schuh2a1447c2019-02-17 00:25:29 -080064 }
65
66 void InstallViewer(aos::vision::BlobStreamViewer *viewer) override {
67 viewer_ = viewer;
Austin Schuh9e5ca2b2019-03-06 20:43:17 -080068 viewer_->SetScale(2.0);
Parker Schuh2a1447c2019-02-17 00:25:29 -080069 overlays_.push_back(&overlay_);
Austin Schuh75921532019-03-09 18:46:34 -080070 overlays_.push_back(target_finder_.GetOverlay());
Parker Schuh2a1447c2019-02-17 00:25:29 -080071 viewer_->view()->SetOverlays(&overlays_);
72 }
73
74 void DrawBlob(const RangeImage &blob, PixelRef color) {
75 if (viewer_) {
76 BlobList list;
77 list.push_back(blob);
78 viewer_->DrawBlobList(list, color);
79 }
80 }
81
82 bool HandleBlobs(BlobList imgs, ImageFormat fmt) override {
Austin Schuhdc477af2019-03-28 10:31:18 -070083 const CameraGeometry camera_geometry = GetCamera(FLAGS_camera)->geometry;
Parker Schuh2a1447c2019-02-17 00:25:29 -080084 imgs_last_ = imgs;
85 fmt_last_ = fmt;
86 // reset for next drawing cycle
87 for (auto &overlay : overlays_) {
88 overlay->Reset();
89 }
90
91 if (draw_select_blob_ || draw_raw_poly_ || draw_components_ ||
92 draw_raw_target_ || draw_raw_IR_ || draw_results_) {
93 printf("_____ New Image _____\n");
94 }
95
Austin Schuhf71c3e62019-05-08 20:48:41 -070096 const int num_pixels = target_finder_.PixelCount(&imgs);
97 printf("Number pixels: %d\n", num_pixels);
98
Parker Schuh2a1447c2019-02-17 00:25:29 -080099 // Remove bad blobs.
Austin Schuh75921532019-03-09 18:46:34 -0800100 target_finder_.PreFilter(&imgs);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800101
102 // Find polygons from blobs.
Austin Schuh7d2ef032019-03-10 14:59:34 -0700103 ::std::vector<Polygon> raw_polys;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800104 for (const RangeImage &blob : imgs) {
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800105 // Convert blobs to contours in the corrected space.
Austin Schuh75921532019-03-09 18:46:34 -0800106 ContourNode *contour = target_finder_.GetContour(blob);
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800107 if (draw_contours_) {
108 DrawContour(contour, {255, 0, 0});
109 }
Austin Schuh6e56faf2019-03-10 14:04:57 -0700110 ::std::vector<::Eigen::Vector2f> unwarped_contour =
Austin Schuh75921532019-03-09 18:46:34 -0800111 target_finder_.UnWarpContour(contour);
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800112 if (draw_contours_) {
Austin Schuhe5015972019-03-09 17:47:34 -0800113 DrawContour(unwarped_contour, {0, 0, 255});
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800114 }
115
116 // Process to polygons.
Austin Schuh6e56faf2019-03-10 14:04:57 -0700117 const Polygon polygon = target_finder_.FindPolygon(
118 ::std::move(unwarped_contour), draw_raw_poly_);
119 if (polygon.segments.empty()) {
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800120 if (!draw_contours_) {
121 DrawBlob(blob, {255, 0, 0});
122 }
Parker Schuh2a1447c2019-02-17 00:25:29 -0800123 } else {
124 raw_polys.push_back(polygon);
125 if (draw_select_blob_) {
126 DrawBlob(blob, {0, 0, 255});
127 }
128 if (draw_raw_poly_) {
Austin Schuh6e56faf2019-03-10 14:04:57 -0700129 std::vector<PixelRef> colors = GetNColors(polygon.segments.size());
Parker Schuh2a1447c2019-02-17 00:25:29 -0800130 std::vector<Vector<2>> corners;
Austin Schuh6e56faf2019-03-10 14:04:57 -0700131 for (size_t i = 0; i < polygon.segments.size(); ++i) {
132 corners.push_back(polygon.segments[i].Intersect(
133 polygon.segments[(i + 1) % polygon.segments.size()]));
Parker Schuh2a1447c2019-02-17 00:25:29 -0800134 }
135
Austin Schuh6e56faf2019-03-10 14:04:57 -0700136 for (size_t i = 0; i < polygon.segments.size(); ++i) {
137 overlay_.AddLine(corners[i],
138 corners[(i + 1) % polygon.segments.size()],
Austin Schuhe5015972019-03-09 17:47:34 -0800139 colors[i]);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800140 }
141 }
142 }
143 }
144
145 // Calculate each component side of a possible target.
146 std::vector<TargetComponent> target_component_list =
Austin Schuh32ffac22019-03-09 22:42:02 -0800147 target_finder_.FillTargetComponentList(raw_polys, draw_components_);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800148 if (draw_components_) {
Austin Schuh7d2ef032019-03-10 14:59:34 -0700149 for (const TargetComponent &component : target_component_list) {
150 DrawComponent(component, {0, 255, 255}, {0, 255, 255}, {255, 0, 0},
Parker Schuh2a1447c2019-02-17 00:25:29 -0800151 {0, 0, 255});
Austin Schuh7d2ef032019-03-10 14:59:34 -0700152 overlay_.DrawCross(component.bottom_point, 4, {128, 0, 255});
Parker Schuh2a1447c2019-02-17 00:25:29 -0800153 }
154 }
155
156 // Put the compenents together into targets.
Austin Schuh75921532019-03-09 18:46:34 -0800157 std::vector<Target> target_list = target_finder_.FindTargetsFromComponents(
Parker Schuh2a1447c2019-02-17 00:25:29 -0800158 target_component_list, draw_raw_target_);
159 if (draw_raw_target_) {
160 for (const Target &target : target_list) {
161 DrawTarget(target);
162 }
163 }
164
165 // Use the solver to generate an intermediate version of our results.
166 std::vector<IntermediateResult> results;
167 for (const Target &target : target_list) {
Austin Schuh75921532019-03-09 18:46:34 -0800168 results.emplace_back(
169 target_finder_.ProcessTargetToResult(target, draw_raw_IR_));
Austin Schuhe6cfbe32019-03-10 18:05:57 -0700170 if (draw_raw_IR_) {
171 IntermediateResult updatable_result = results.back();
172 target_finder_.MaybePickAndUpdateResult(&updatable_result,
173 draw_raw_IR_);
174 DrawResult(updatable_result, {255, 128, 0});
175 }
Parker Schuh2a1447c2019-02-17 00:25:29 -0800176 }
177
178 // Check that our current results match possible solutions.
Alex Perrybac3d3f2019-03-10 14:26:51 -0700179 results = target_finder_.FilterResults(results, 0, draw_results_);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800180 if (draw_results_) {
Austin Schuhdc477af2019-03-28 10:31:18 -0700181 for (const IntermediateResult &result : results) {
182 ::std::cout << "Found target x: "
183 << camera_geometry.location[0] +
184 ::std::cos(camera_geometry.heading +
185 result.extrinsics.r2) *
186 result.extrinsics.z
187 << ::std::endl;
188 ::std::cout << "Found target y: "
189 << camera_geometry.location[1] +
190 ::std::sin(camera_geometry.heading +
191 result.extrinsics.r2) *
192 result.extrinsics.z
193 << ::std::endl;
194 ::std::cout << "Found target z: "
195 << camera_geometry.location[2] + result.extrinsics.y
196 << ::std::endl;
197 DrawTarget(result, {0, 255, 0});
Parker Schuh2a1447c2019-02-17 00:25:29 -0800198 }
199 }
200
Alex Perry5b1e8e32019-04-07 13:25:31 -0700201 int desired_exposure;
Austin Schuhf71c3e62019-05-08 20:48:41 -0700202 if (target_finder_.TestExposure(results, num_pixels, &desired_exposure)) {
Alex Perry5b1e8e32019-04-07 13:25:31 -0700203 printf("Switching exposure to %d.\n", desired_exposure);
204 SetExposure(desired_exposure);
205 }
206
Parker Schuh2a1447c2019-02-17 00:25:29 -0800207 // If the target list is not empty then we found a target.
208 return !results.empty();
209 }
210
211 std::function<void(uint32_t)> RegisterKeyPress() override {
212 return [this](uint32_t key) {
213 (void)key;
214 if (key == 'z') {
215 draw_results_ = !draw_results_;
216 } else if (key == 'x') {
217 draw_raw_IR_ = !draw_raw_IR_;
218 } else if (key == 'c') {
219 draw_raw_target_ = !draw_raw_target_;
220 } else if (key == 'v') {
221 draw_components_ = !draw_components_;
222 } else if (key == 'b') {
223 draw_raw_poly_ = !draw_raw_poly_;
224 } else if (key == 'n') {
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800225 draw_contours_ = !draw_contours_;
226 } else if (key == 'm') {
Parker Schuh2a1447c2019-02-17 00:25:29 -0800227 draw_select_blob_ = !draw_select_blob_;
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800228 } else if (key == 'h') {
229 printf("Key Mappings:\n");
230 printf(" z: Toggle drawing final target pose.\n");
Philipp Schrader790cb542023-07-05 21:06:52 -0700231 printf(
232 " x: Toggle drawing re-projected targets and print solver "
233 "results.\n");
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800234 printf(" c: Toggle drawing proposed target groupings.\n");
235 printf(" v: Toggle drawing ordered target components.\n");
236 printf(" b: Toggle drawing proposed target components.\n");
237 printf(" n: Toggle drawing countours before and after warping.\n");
Philipp Schrader790cb542023-07-05 21:06:52 -0700238 printf(
239 " m: Toggle drawing raw blob data (may need to change image to "
240 "toggle a redraw).\n");
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800241 printf(" h: Print this message.\n");
Ben Fredricksona8c3d552019-03-03 14:14:53 -0800242 printf(" a: May log camera image to /tmp/debug_viewer_jpeg_<#>.yuyv\n");
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800243 printf(" q: Exit the application.\n");
Parker Schuh2a1447c2019-02-17 00:25:29 -0800244 } else if (key == 'q') {
245 printf("User requested shutdown.\n");
246 exit(0);
247 }
248 HandleBlobs(imgs_last_, fmt_last_);
249 viewer_->Redraw();
250 };
251 }
252
Ben Fredricksonf7b68522019-03-02 21:19:42 -0800253 void DrawContour(ContourNode *contour, PixelRef color) {
254 if (viewer_) {
255 for (ContourNode *node = contour; node->next != contour;) {
256 Vector<2> a(node->pt.x, node->pt.y);
257 Vector<2> b(node->next->pt.x, node->next->pt.y);
258 overlay_.AddLine(a, b, color);
259 node = node->next;
260 }
261 }
262 }
263
Austin Schuhe5015972019-03-09 17:47:34 -0800264 void DrawContour(const ::std::vector<::Eigen::Vector2f> &contour,
265 PixelRef color) {
266 if (viewer_) {
267 for (size_t i = 0; i < contour.size(); ++i) {
268 Vector<2> a(contour[i].x(), contour[i].y());
269 Vector<2> b(contour[(i + 1) % contour.size()].x(),
270 contour[(i + 1) % contour.size()].y());
271 overlay_.AddLine(a, b, color);
272 }
273 }
274 }
275
Parker Schuh2a1447c2019-02-17 00:25:29 -0800276 void DrawComponent(const TargetComponent &comp, PixelRef top_color,
277 PixelRef bot_color, PixelRef in_color,
278 PixelRef out_color) {
279 overlay_.AddLine(comp.top, comp.inside, top_color);
280 overlay_.AddLine(comp.bottom, comp.outside, bot_color);
281
282 overlay_.AddLine(comp.bottom, comp.inside, in_color);
283 overlay_.AddLine(comp.top, comp.outside, out_color);
284 }
285
286 void DrawTarget(const Target &target) {
287 Vector<2> leftTop = (target.left.top + target.left.inside) * 0.5;
288 Vector<2> rightTop = (target.right.top + target.right.inside) * 0.5;
289 overlay_.AddLine(leftTop, rightTop, {255, 215, 0});
290
291 Vector<2> leftBot = (target.left.bottom + target.left.outside) * 0.5;
292 Vector<2> rightBot = (target.right.bottom + target.right.outside) * 0.5;
293 overlay_.AddLine(leftBot, rightBot, {255, 215, 0});
294
295 overlay_.AddLine(leftTop, leftBot, {255, 215, 0});
296 overlay_.AddLine(rightTop, rightBot, {255, 215, 0});
297 }
298
299 void DrawResult(const IntermediateResult &result, PixelRef color) {
Austin Schuh75921532019-03-09 18:46:34 -0800300 Target target = Project(target_finder_.GetTemplateTarget(), intrinsics(),
301 result.extrinsics);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800302 DrawComponent(target.left, color, color, color, color);
303 DrawComponent(target.right, color, color, color, color);
304 }
305
306 void DrawTarget(const IntermediateResult &result, PixelRef color) {
Austin Schuh75921532019-03-09 18:46:34 -0800307 Target target = Project(target_finder_.GetTemplateTarget(), intrinsics(),
308 result.extrinsics);
Parker Schuh2a1447c2019-02-17 00:25:29 -0800309 Segment<2> leftAx((target.left.top + target.left.inside) * 0.5,
310 (target.left.bottom + target.left.outside) * 0.5);
311 leftAx.Set(leftAx.A() * 0.9 + leftAx.B() * 0.1,
312 leftAx.B() * 0.9 + leftAx.A() * 0.1);
313 overlay_.AddLine(leftAx, color);
314
315 Segment<2> rightAx((target.right.top + target.right.inside) * 0.5,
316 (target.right.bottom + target.right.outside) * 0.5);
317 rightAx.Set(rightAx.A() * 0.9 + rightAx.B() * 0.1,
318 rightAx.B() * 0.9 + rightAx.A() * 0.1);
319 overlay_.AddLine(rightAx, color);
320
321 overlay_.AddLine(leftAx.A(), rightAx.A(), color);
322 overlay_.AddLine(leftAx.B(), rightAx.B(), color);
323 Vector<3> p1(0.0, 0.0, 100.0);
324
325 Vector<3> p2 =
326 Rotate(intrinsics().mount_angle, result.extrinsics.r1, 0.0, p1);
327 Vector<2> p3(p2.x(), p2.y());
328 overlay_.AddLine(leftAx.A(), p3 + leftAx.A(), {0, 255, 0});
329 overlay_.AddLine(leftAx.B(), p3 + leftAx.B(), {0, 255, 0});
330 overlay_.AddLine(rightAx.A(), p3 + rightAx.A(), {0, 255, 0});
331 overlay_.AddLine(rightAx.B(), p3 + rightAx.B(), {0, 255, 0});
332
333 overlay_.AddLine(p3 + leftAx.A(), p3 + leftAx.B(), {0, 255, 0});
334 overlay_.AddLine(p3 + leftAx.A(), p3 + rightAx.A(), {0, 255, 0});
335 overlay_.AddLine(p3 + rightAx.A(), p3 + rightAx.B(), {0, 255, 0});
336 overlay_.AddLine(p3 + leftAx.B(), p3 + rightAx.B(), {0, 255, 0});
337 }
338
Austin Schuh75921532019-03-09 18:46:34 -0800339 const IntrinsicParams &intrinsics() const {
340 return target_finder_.intrinsics();
341 }
Parker Schuh2a1447c2019-02-17 00:25:29 -0800342
343 private:
344 // implementation of the filter pipeline.
Austin Schuh75921532019-03-09 18:46:34 -0800345 TargetFinder target_finder_;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800346 aos::vision::BlobStreamViewer *viewer_ = nullptr;
347 aos::vision::PixelLinesOverlay overlay_;
348 std::vector<aos::vision::OverlayBase *> overlays_;
349 BlobList imgs_last_;
350 ImageFormat fmt_last_;
351 bool draw_select_blob_ = false;
Austin Schuh45639882019-03-24 19:20:42 -0700352 bool draw_contours_ = true;
353 bool draw_raw_poly_ = true;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800354 bool draw_components_ = false;
355 bool draw_raw_target_ = false;
Austin Schuh45639882019-03-24 19:20:42 -0700356 bool draw_raw_IR_ = true;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800357 bool draw_results_ = true;
358};
359
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800360} // namespace y2019::vision
Parker Schuh2a1447c2019-02-17 00:25:29 -0800361
362int main(int argc, char **argv) {
Austin Schuh75921532019-03-09 18:46:34 -0800363 ::gflags::ParseCommandLineFlags(&argc, &argv, true);
Austin Schuha60e37c2019-03-10 19:31:09 -0700364
365 y2019::vision::FilterHarness filter_harness;
Parker Schuh2a1447c2019-02-17 00:25:29 -0800366 aos::vision::DebugFrameworkMain(argc, argv, &filter_harness,
367 aos::vision::CameraParams());
368}