blob: 5b808a2422131effa84a0d86beb228b4ef5b9f59 [file] [log] [blame]
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08001#include "y2022/vision/camera_reader.h"
2
Henry Speiser3069ca92022-02-05 16:25:00 -08003#include <chrono>
Milind Upadhyay25610d22022-02-07 15:35:26 -08004#include <cmath>
Henry Speiser3069ca92022-02-05 16:25:00 -08005#include <thread>
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08006
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08007#include "aos/events/event_loop.h"
Henry Speiser1f34eea2022-01-30 14:35:21 -08008#include "aos/events/shm_event_loop.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08009#include "aos/flatbuffer_merge.h"
10#include "aos/network/team_number.h"
11#include "frc971/vision/v4l2_reader.h"
12#include "frc971/vision/vision_generated.h"
Milind Upadhyay25610d22022-02-07 15:35:26 -080013#include "opencv2/imgproc.hpp"
milind-u92195982022-01-22 20:29:31 -080014#include "y2022/vision/blob_detector.h"
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080015#include "y2022/vision/calibration_generated.h"
milind-u92195982022-01-22 20:29:31 -080016#include "y2022/vision/target_estimator.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080017
Henry Speiser1f34eea2022-01-30 14:35:21 -080018DEFINE_string(image_png, "", "A set of PNG images");
19
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080020namespace y2022 {
21namespace vision {
22
23using namespace frc971::vision;
24
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080025const calibration::CameraCalibration *CameraReader::FindCameraCalibration()
26 const {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080027 const std::string_view node_name = event_loop_->node()->name()->string_view();
28 const int team_number = aos::network::GetTeamNumber();
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080029 for (const calibration::CameraCalibration *candidate :
30 *calibration_data_->camera_calibrations()) {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080031 if (candidate->node_name()->string_view() != node_name) {
32 continue;
33 }
34 if (candidate->team_number() != team_number) {
35 continue;
36 }
37 return candidate;
38 }
39 LOG(FATAL) << ": Failed to find camera calibration for " << node_name
40 << " on " << team_number;
41}
42
Henry Speisere45e7a22022-02-04 23:17:01 -080043namespace {
44// Converts a vector of cv::Point to PointT for the flatbuffer
45flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Blob>>>
46CvBlobsToFbs(const std::vector<std::vector<cv::Point>> &blobs,
47 aos::Sender<TargetEstimate>::Builder &builder) {
48 std::vector<flatbuffers::Offset<Blob>> blobs_fbs;
49 for (auto &blob : blobs) {
50 std::vector<Point> points_fbs;
51 for (auto p : blob) {
52 points_fbs.push_back(Point{p.x, p.y});
53 }
54 auto points_offset = builder.fbb()->CreateVectorOfStructs(points_fbs);
55 auto blob_builder = builder.MakeBuilder<Blob>();
56 blob_builder.add_points(points_offset);
57 blobs_fbs.emplace_back(blob_builder.Finish());
58 }
59 return builder.fbb()->CreateVector(blobs_fbs.data(), blobs_fbs.size());
60}
61
62flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BlobStatsFbs>>>
63BlobStatsToFbs(const std::vector<BlobDetector::BlobStats> blob_stats,
64 aos::Sender<TargetEstimate>::Builder &builder) {
65 std::vector<flatbuffers::Offset<BlobStatsFbs>> stats_fbs;
66 for (auto &stats : blob_stats) {
67 // Make BlobStatsFbs builder then fill each field using the BlobStats
68 // struct, then you finish it and add it to stats_fbs.
69 auto stats_builder = builder.MakeBuilder<BlobStatsFbs>();
70 Point centroid_fbs = Point{stats.centroid.x, stats.centroid.y};
71 stats_builder.add_centroid(&centroid_fbs);
72 stats_builder.add_aspect_ratio(stats.aspect_ratio);
73 stats_builder.add_area(stats.area);
74 stats_builder.add_num_points(stats.num_points);
75
76 auto current_stats = stats_builder.Finish();
77 stats_fbs.emplace_back(current_stats);
78 }
79 return builder.fbb()->CreateVector(stats_fbs.data(), stats_fbs.size());
80}
81} // namespace
82
Jim Ostrowski210765a2022-02-27 12:52:14 -080083void CameraReader::ProcessImage(cv::Mat image_mat,
84 int64_t image_monotonic_timestamp_ns) {
Milind Upadhyay25610d22022-02-07 15:35:26 -080085 BlobDetector::BlobResult blob_result;
Milind Upadhyay25610d22022-02-07 15:35:26 -080086 BlobDetector::ExtractBlobs(image_mat, &blob_result);
milind-u92195982022-01-22 20:29:31 -080087 auto builder = target_estimate_sender_.MakeBuilder();
Milind Upadhyay25610d22022-02-07 15:35:26 -080088 flatbuffers::Offset<BlobResultFbs> blob_result_offset;
Henry Speisere45e7a22022-02-04 23:17:01 -080089 {
Milind Upadhyay25610d22022-02-07 15:35:26 -080090 const auto filtered_blobs_offset =
91 CvBlobsToFbs(blob_result.filtered_blobs, builder);
Henry Speisere45e7a22022-02-04 23:17:01 -080092 const auto unfiltered_blobs_offset =
Milind Upadhyay25610d22022-02-07 15:35:26 -080093 CvBlobsToFbs(blob_result.unfiltered_blobs, builder);
94 const auto blob_stats_offset =
95 BlobStatsToFbs(blob_result.blob_stats, builder);
96 const Point centroid_fbs =
97 Point{blob_result.centroid.x, blob_result.centroid.y};
Henry Speisere45e7a22022-02-04 23:17:01 -080098
Milind Upadhyay25610d22022-02-07 15:35:26 -080099 auto blob_result_builder = builder.MakeBuilder<BlobResultFbs>();
Henry Speisere45e7a22022-02-04 23:17:01 -0800100 blob_result_builder.add_filtered_blobs(filtered_blobs_offset);
101 blob_result_builder.add_unfiltered_blobs(unfiltered_blobs_offset);
102 blob_result_builder.add_blob_stats(blob_stats_offset);
103 blob_result_builder.add_centroid(&centroid_fbs);
104 blob_result_offset = blob_result_builder.Finish();
105 }
106
Milind Upadhyaye2f40d72022-02-24 13:55:53 -0800107 const auto camera_calibration_offset =
108 aos::RecursiveCopyFlatBuffer(camera_calibration_, builder.fbb());
109
Henry Speisere45e7a22022-02-04 23:17:01 -0800110 auto target_estimate_builder = builder.MakeBuilder<TargetEstimate>();
Milind Upadhyay25610d22022-02-07 15:35:26 -0800111 TargetEstimator::EstimateTargetLocation(
112 blob_result.centroid, CameraIntrinsics(), CameraExtrinsics(),
113 &target_estimate_builder);
Henry Speisere45e7a22022-02-04 23:17:01 -0800114 target_estimate_builder.add_blob_result(blob_result_offset);
Milind Upadhyaye2f40d72022-02-24 13:55:53 -0800115 target_estimate_builder.add_camera_calibration(camera_calibration_offset);
Jim Ostrowski210765a2022-02-27 12:52:14 -0800116 target_estimate_builder.add_image_monotonic_timestamp_ns(
117 image_monotonic_timestamp_ns);
Henry Speisere45e7a22022-02-04 23:17:01 -0800118 builder.CheckOk(builder.Send(target_estimate_builder.Finish()));
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800119}
120
121void CameraReader::ReadImage() {
Henry Speiser1f34eea2022-01-30 14:35:21 -0800122 // Path is for reading from the Disk.
123 if (FLAGS_image_png != "") {
124 std::vector<cv::String> file_list;
125 cv::glob(FLAGS_image_png + "/*.png", file_list, false);
Henry Speiser1f34eea2022-01-30 14:35:21 -0800126 for (auto file : file_list) {
Henry Speiser3069ca92022-02-05 16:25:00 -0800127 // Sleep for 0.05 seconds in order to not reach the max number of messages
128 // that can be sent in a second.
129 std::this_thread::sleep_for(std::chrono::milliseconds(50));
Henry Speiser1f34eea2022-01-30 14:35:21 -0800130 LOG(INFO) << "Reading file " << file;
Milind Upadhyayec41e132022-02-05 17:14:05 -0800131 cv::Mat bgr_image = cv::imread(file.c_str());
Jim Ostrowski210765a2022-02-27 12:52:14 -0800132 // TODO (Henry) convert to YUYV
133 int64_t timestamp =
134 aos::monotonic_clock::now().time_since_epoch().count();
135 ProcessImage(bgr_image, timestamp);
Henry Speiser1f34eea2022-01-30 14:35:21 -0800136 }
137 event_loop_->Exit();
138 return;
139 }
140 // If we are not reading from the disk, we read the live camera stream.
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800141 if (!reader_->ReadLatestImage()) {
142 read_image_timer_->Setup(event_loop_->monotonic_now() +
143 std::chrono::milliseconds(10));
144 return;
145 }
146
Henry Speiser1f34eea2022-01-30 14:35:21 -0800147 const CameraImage &image = reader_->LatestImage();
Henry Speiser1f34eea2022-01-30 14:35:21 -0800148
Jim Ostrowski210765a2022-02-27 12:52:14 -0800149 cv::Mat image_color_mat(cv::Size(image.cols(), image.rows()), CV_8UC2,
150 (void *)image.data()->data());
151 cv::Mat image_mat(cv::Size(image.cols(), image.rows()), CV_8UC3);
152 cv::cvtColor(image_color_mat, image_mat, cv::COLOR_YUV2BGR_YUYV);
Henry Speiser1f34eea2022-01-30 14:35:21 -0800153
Jim Ostrowski210765a2022-02-27 12:52:14 -0800154 ProcessImage(image_mat, image.monotonic_timestamp_ns());
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800155
156 reader_->SendLatestImage();
157 read_image_timer_->Setup(event_loop_->monotonic_now());
158}
159
160} // namespace vision
161} // namespace y2022