blob: c44490e0ff4a99f6d43726f4863b4df0817f38e9 [file] [log] [blame]
Jim Ostrowskic560cbe2020-03-07 00:29:30 -08001#include <map>
Philipp Schrader790cb542023-07-05 21:06:52 -07002#include <random>
3
Austin Schuh99f7c6a2024-06-25 22:07:44 -07004#include "absl/flags/flag.h"
Jim Ostrowski23eb6582020-03-04 23:15:32 -08005#include <opencv2/calib3d.hpp>
6#include <opencv2/features2d.hpp>
7#include <opencv2/highgui/highgui.hpp>
8#include <opencv2/imgproc.hpp>
9
10#include "aos/events/shm_event_loop.h"
11#include "aos/init.h"
Jim Ostrowskibaa43692020-03-08 16:25:10 -070012#include "aos/time/time.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080013#include "frc971/vision/v4l2_reader.h"
14#include "frc971/vision/vision_generated.h"
Jim Ostrowskic560cbe2020-03-07 00:29:30 -080015#include "y2020/vision/sift/sift_generated.h"
Jim Ostrowski23eb6582020-03-04 23:15:32 -080016
Austin Schuh99f7c6a2024-06-25 22:07:44 -070017ABSL_FLAG(std::string, config, "aos_config.json",
18 "Path to the config file to use.");
19ABSL_FLAG(bool, show_features, true, "Show the SIFT features that matched.");
20ABSL_FLAG(std::string, channel, "/camera", "Channel name for the image.");
Jim Ostrowski23eb6582020-03-04 23:15:32 -080021
Austin Schuh99f7c6a2024-06-25 22:07:44 -070022ABSL_FLAG(std::string, capture, "",
23 "If set, capture a single image and save it to this filename.");
Austin Schuh57763122021-11-06 20:49:18 -070024
Stephan Pleinesf63bde82024-01-13 15:59:33 -080025namespace frc971::vision {
Jim Ostrowski23eb6582020-03-04 23:15:32 -080026namespace {
27
Jim Ostrowski834dddf2021-04-10 14:40:19 -070028aos::Fetcher<CameraImage> image_fetcher;
29aos::Fetcher<sift::ImageMatchResult> match_fetcher;
Jim Ostrowski56c09322021-10-23 16:17:21 -070030cv::Mat palette_;
Jim Ostrowski834dddf2021-04-10 14:40:19 -070031
32bool DisplayLoop() {
Jim Ostrowski56c09322021-10-23 16:17:21 -070033 // Try to get target match data
34 int64_t match_timestamp = 0;
35 const sift::ImageMatchResult *match;
Jim Ostrowski834dddf2021-04-10 14:40:19 -070036 if (match_fetcher.Fetch()) {
Jim Ostrowski56c09322021-10-23 16:17:21 -070037 match = match_fetcher.get();
Jim Ostrowski834dddf2021-04-10 14:40:19 -070038 CHECK(match != nullptr) << "Got null when trying to fetch match result";
39
Jim Ostrowski56c09322021-10-23 16:17:21 -070040 match_timestamp = match->image_monotonic_timestamp_ns();
41 if (match->camera_poses() != nullptr && match->camera_poses()->size() > 0) {
42 VLOG(2) << "Got matches for timestamp " << match_timestamp << "\n";
43 }
44 } else {
45 VLOG(2) << "Didn't get match this cycle";
46 }
47
48 int64_t image_timestamp = 0;
49 bool matching_image_found = false;
50 const CameraImage *image;
51 while (!matching_image_found) {
52 // Read next image
53 if (!image_fetcher.FetchNext()) {
54 VLOG(2) << "Couldn't fetch next image";
55 return true;
56 }
57
58 image = image_fetcher.get();
59 CHECK(image != nullptr) << "Couldn't read image";
60 image_timestamp = image->monotonic_timestamp_ns();
61 VLOG(2) << "Got image at timestamp: " << image_timestamp;
62
63 if (match_timestamp != 0 && image_timestamp == match_timestamp) {
64 matching_image_found = true;
65 } else if (image_timestamp > match_timestamp) {
66 LOG(INFO) << "Image timestamp went past match_timestamp";
67 return true;
Jim Ostrowski834dddf2021-04-10 14:40:19 -070068 }
69 }
70
Jim Ostrowski834dddf2021-04-10 14:40:19 -070071 // Create color image:
72 cv::Mat image_color_mat(cv::Size(image->cols(), image->rows()), CV_8UC2,
73 (void *)image->data()->data());
74 cv::Mat rgb_image(cv::Size(image->cols(), image->rows()), CV_8UC3);
Brian Silverman4c7235a2021-11-17 19:04:37 -080075 cv::cvtColor(image_color_mat, rgb_image, cv::COLOR_YUV2BGR_YUYV);
Jim Ostrowski834dddf2021-04-10 14:40:19 -070076
Austin Schuh99f7c6a2024-06-25 22:07:44 -070077 if (!absl::GetFlag(FLAGS_capture).empty()) {
78 cv::imwrite(absl::GetFlag(FLAGS_capture), rgb_image);
Austin Schuh57763122021-11-06 20:49:18 -070079 return false;
80 }
81
Jim Ostrowski56c09322021-10-23 16:17:21 -070082 if (matching_image_found) {
83 // Draw whatever matches we have
84 if (match->camera_poses() != nullptr && match->camera_poses()->size() > 0) {
85 // Draw target point in image
86 float x = match->camera_poses()->Get(0)->query_target_point_x();
87 float y = match->camera_poses()->Get(0)->query_target_point_y();
88 float radius = match->camera_poses()->Get(0)->query_target_point_radius();
89 cv::circle(rgb_image, cv::Point2f(x, y), radius, cv::Scalar(0, 255, 0),
90 5);
91 }
92
Austin Schuh99f7c6a2024-06-25 22:07:44 -070093 if (absl::GetFlag(FLAGS_show_features) &&
94 match->image_matches() != nullptr &&
Jim Ostrowski56c09322021-10-23 16:17:21 -070095 match->image_matches()->size() > 0) {
96 // Iterate through matches and draw matched keypoints
97 for (uint model_match_ind = 0;
98 model_match_ind < match->image_matches()->size();
99 model_match_ind++) {
100 auto match_list =
101 match->image_matches()->Get(model_match_ind)->matches();
102 if (match_list != nullptr && match_list->size() > 0) {
103 int train_image_ind =
104 match->image_matches()->Get(model_match_ind)->train_image();
105 VLOG(2) << "Got " << match_list->size() << " matches to model "
106 << train_image_ind;
107
108 // Picking color from palette and drawing
109 auto color = palette_.at<cv::Vec3b>(train_image_ind % palette_.cols);
110 LOG(INFO) << "Using color " << color;
111 for (uint i = 0; i < match_list->size(); i++) {
112 uint query_feature_ind = match_list->Get(i)->query_feature();
113 float kp_x = match->features()->Get(query_feature_ind)->x();
114 float kp_y = match->features()->Get(query_feature_ind)->y();
115 cv::circle(rgb_image, cv::Point2f(kp_x, kp_y), 5, color, 2);
116 }
117 }
118 }
119 }
Jim Ostrowski834dddf2021-04-10 14:40:19 -0700120 }
121
122 cv::imshow("Display", rgb_image);
123 int keystroke = cv::waitKey(1);
124 if ((keystroke & 0xFF) == static_cast<int>('c')) {
125 // Convert again, to get clean image
Brian Silverman4c7235a2021-11-17 19:04:37 -0800126 cv::cvtColor(image_color_mat, rgb_image, cv::COLOR_YUV2BGR_YUYV);
Jim Ostrowski834dddf2021-04-10 14:40:19 -0700127 std::stringstream name;
128 name << "capture-" << aos::realtime_clock::now() << ".png";
129 cv::imwrite(name.str(), rgb_image);
130 LOG(INFO) << "Saved image file: " << name.str();
131 } else if ((keystroke & 0xFF) == static_cast<int>('q')) {
132 return false;
133 }
134 return true;
135}
136
137void ViewerMain() {
Jim Ostrowski56c09322021-10-23 16:17:21 -0700138 // Create random color palette for distinguishing multiple models
139 uchar colors[5][3] = {
140 {0, 0, 255}, {0, 165, 255}, {0, 255, 255}, {255, 0, 0}, {128, 0, 128}};
141 palette_ = cv::Mat(3, 5, CV_8U, &colors);
Jim Ostrowskic560cbe2020-03-07 00:29:30 -0800142
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800143 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700144 aos::configuration::ReadConfig(absl::GetFlag(FLAGS_config));
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800145
146 aos::ShmEventLoop event_loop(&config.message());
147
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700148 image_fetcher =
149 event_loop.MakeFetcher<CameraImage>(absl::GetFlag(FLAGS_channel));
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800150
Jim Ostrowski56c09322021-10-23 16:17:21 -0700151 // If we want to show the features, we have to use the detailed channel
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700152 std::string result_channel = absl::GetFlag(FLAGS_channel);
153 if (absl::GetFlag(FLAGS_show_features)) {
Jim Ostrowski56c09322021-10-23 16:17:21 -0700154 result_channel += "/detailed";
155 }
156 match_fetcher =
157 event_loop.MakeFetcher<sift::ImageMatchResult>(result_channel);
Jim Ostrowskibaa43692020-03-08 16:25:10 -0700158
Jim Ostrowski834dddf2021-04-10 14:40:19 -0700159 // Run the display loop
160 event_loop.AddPhasedLoop(
161 [&event_loop](int) {
162 if (!DisplayLoop()) {
163 LOG(INFO) << "Calling event_loop Exit";
164 event_loop.Exit();
165 };
166 },
167 ::std::chrono::milliseconds(100));
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800168
169 event_loop.Run();
Austin Schuh57763122021-11-06 20:49:18 -0700170
171 image_fetcher = aos::Fetcher<CameraImage>();
172 match_fetcher = aos::Fetcher<sift::ImageMatchResult>();
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800173}
174
175} // namespace
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800176} // namespace frc971::vision
Jim Ostrowski23eb6582020-03-04 23:15:32 -0800177
178// Quick and lightweight grayscale viewer for images
179int main(int argc, char **argv) {
180 aos::InitGoogle(&argc, &argv);
181 frc971::vision::ViewerMain();
182}