blob: 2a6f0a6d016a1d4056c79404f1e0cdbfcf2833a7 [file] [log] [blame]
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -08001#include <map>
2#include <opencv2/calib3d.hpp>
3#include <opencv2/features2d.hpp>
4#include <opencv2/highgui/highgui.hpp>
5#include <opencv2/imgproc.hpp>
6#include <random>
7
8#include "aos/events/shm_event_loop.h"
9#include "aos/init.h"
10#include "aos/time/time.h"
Jim Ostrowski977850f2022-01-22 21:04:22 -080011#include "frc971/vision/vision_generated.h"
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080012#include "y2022/vision/blob_detector.h"
Henry Speisere45e7a22022-02-04 23:17:01 -080013#include "y2022/vision/target_estimate_generated.h"
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080014
15DEFINE_string(capture, "",
16 "If set, capture a single image and save it to this filename.");
17DEFINE_string(channel, "/camera", "Channel name for the image.");
18DEFINE_string(config, "config.json", "Path to the config file to use.");
Jim Ostrowski5caf81c2022-01-30 21:02:19 -080019DEFINE_string(png_dir, "", "Path to a set of images to display.");
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080020DEFINE_bool(show_features, true, "Show the blobs.");
21
22namespace y2022 {
23namespace vision {
24namespace {
25
26aos::Fetcher<frc971::vision::CameraImage> image_fetcher;
Henry Speisere45e7a22022-02-04 23:17:01 -080027aos::Fetcher<y2022::vision::TargetEstimate> target_estimate_fetcher;
28
29std::vector<std::vector<cv::Point>> FbsToCvBlobs(
30 const flatbuffers::Vector<flatbuffers::Offset<Blob>> &blobs_fbs) {
31 std::vector<std::vector<cv::Point>> blobs;
32 for (const auto blob : blobs_fbs) {
33 std::vector<cv::Point> points;
34 for (const Point *point : *blob->points()) {
35 points.emplace_back(cv::Point{point->x(), point->y()});
36 }
37 blobs.emplace_back(points);
38 }
39 return blobs;
40}
41
42std::vector<BlobDetector::BlobStats> FbsToBlobStats(
43 const flatbuffers::Vector<flatbuffers::Offset<BlobStatsFbs>>
44 &blob_stats_fbs) {
45 std::vector<BlobDetector::BlobStats> blob_stats;
46 for (const auto stats_fbs : blob_stats_fbs) {
47 cv::Point centroid{stats_fbs->centroid()->x(), stats_fbs->centroid()->y()};
48 blob_stats.emplace_back(BlobDetector::BlobStats{
49 centroid, stats_fbs->aspect_ratio(), stats_fbs->area(),
50 static_cast<size_t>(stats_fbs->num_points())});
51 }
52 return blob_stats;
53}
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080054
55bool DisplayLoop() {
56 int64_t image_timestamp = 0;
57 const frc971::vision::CameraImage *image;
58 // Read next image
Jim Ostrowski5caf81c2022-01-30 21:02:19 -080059 if (!image_fetcher.Fetch()) {
60 LOG(INFO) << "Couldn't fetch image";
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080061 return true;
62 }
63
64 image = image_fetcher.get();
65 CHECK(image != nullptr) << "Couldn't read image";
66 image_timestamp = image->monotonic_timestamp_ns();
67 VLOG(2) << "Got image at timestamp: " << image_timestamp;
68
Henry Speisere45e7a22022-02-04 23:17:01 -080069 // TODO(Milind) Store the target estimates and match them by timestamp to make
70 // sure we're getting the right one.
Jim Ostrowski46a78382022-02-06 14:05:58 -080071 const TargetEstimate *target_est = nullptr;
72 if (target_estimate_fetcher.Fetch()) {
73 target_est = target_estimate_fetcher.get();
74 }
Henry Speisere45e7a22022-02-04 23:17:01 -080075
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080076 // Create color image:
77 cv::Mat image_color_mat(cv::Size(image->cols(), image->rows()), CV_8UC2,
78 (void *)image->data()->data());
Milind Upadhyayec41e132022-02-05 17:14:05 -080079 cv::Mat bgr_image(cv::Size(image->cols(), image->rows()), CV_8UC3);
Milind Upadhyay40522942022-02-19 15:30:31 -080080 cv::cvtColor(image_color_mat, bgr_image, cv::COLOR_YUV2BGR_YUYV);
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080081
82 if (!FLAGS_capture.empty()) {
Milind Upadhyayec41e132022-02-05 17:14:05 -080083 cv::imwrite(FLAGS_capture, bgr_image);
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -080084 return false;
85 }
86
Jim Ostrowski46a78382022-02-06 14:05:58 -080087 LOG(INFO) << image->monotonic_timestamp_ns() << ": # unfiltered blobs: "
88 << target_est->blob_result()->unfiltered_blobs()->size()
89 << "; # filtered blobs: "
90 << target_est->blob_result()->filtered_blobs()->size();
Henry Speisere45e7a22022-02-04 23:17:01 -080091
Jim Ostrowski46a78382022-02-06 14:05:58 -080092 cv::Mat ret_image(cv::Size(image->cols(), image->rows()), CV_8UC3);
93 if (target_est != nullptr) {
94 BlobDetector::DrawBlobs(
95 ret_image, FbsToCvBlobs(*target_est->blob_result()->filtered_blobs()),
96 FbsToCvBlobs(*target_est->blob_result()->unfiltered_blobs()),
97 FbsToBlobStats(*target_est->blob_result()->blob_stats()),
98 cv::Point{target_est->blob_result()->centroid()->x(),
99 target_est->blob_result()->centroid()->y()});
100 cv::imshow("blobs", ret_image);
101 }
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800102
Milind Upadhyayec41e132022-02-05 17:14:05 -0800103 cv::imshow("image", bgr_image);
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800104
105 int keystroke = cv::waitKey(1);
106 if ((keystroke & 0xFF) == static_cast<int>('c')) {
107 // Convert again, to get clean image
Milind Upadhyayec41e132022-02-05 17:14:05 -0800108 cv::cvtColor(image_color_mat, bgr_image, cv::COLOR_YUV2BGR_YUYV);
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800109 std::stringstream name;
110 name << "capture-" << aos::realtime_clock::now() << ".png";
Milind Upadhyayec41e132022-02-05 17:14:05 -0800111 cv::imwrite(name.str(), bgr_image);
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800112 LOG(INFO) << "Saved image file: " << name.str();
113 } else if ((keystroke & 0xFF) == static_cast<int>('q')) {
114 return false;
115 }
116 return true;
117}
118
119void ViewerMain() {
120 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
121 aos::configuration::ReadConfig(FLAGS_config);
122
123 aos::ShmEventLoop event_loop(&config.message());
124
125 image_fetcher =
126 event_loop.MakeFetcher<frc971::vision::CameraImage>(FLAGS_channel);
127
Jim Ostrowski46a78382022-02-06 14:05:58 -0800128 target_estimate_fetcher =
129 event_loop.MakeFetcher<y2022::vision::TargetEstimate>(FLAGS_channel);
130
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800131 // Run the display loop
132 event_loop.AddPhasedLoop(
133 [&event_loop](int) {
134 if (!DisplayLoop()) {
135 LOG(INFO) << "Calling event_loop Exit";
136 event_loop.Exit();
137 };
138 },
139 ::std::chrono::milliseconds(100));
140
141 event_loop.Run();
142
143 image_fetcher = aos::Fetcher<frc971::vision::CameraImage>();
144}
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800145} // namespace
146} // namespace vision
147} // namespace y2022
148
149// Quick and lightweight viewer for images
150int main(int argc, char **argv) {
151 aos::InitGoogle(&argc, &argv);
Henry Speisere45e7a22022-02-04 23:17:01 -0800152 y2022::vision::ViewerMain();
Jim Ostrowskiff0f5e42022-01-22 01:35:31 -0800153}