blob: e1de75a9702f284a8c04e84c6bb66241162cc8a7 [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 <cmath>
4#include <chrono>
5#include <thread>
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08006
7#include <opencv2/imgproc.hpp>
8
9#include "aos/events/event_loop.h"
Henry Speiser1f34eea2022-01-30 14:35:21 -080010#include "aos/events/shm_event_loop.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080011#include "aos/flatbuffer_merge.h"
12#include "aos/network/team_number.h"
13#include "frc971/vision/v4l2_reader.h"
14#include "frc971/vision/vision_generated.h"
milind-u92195982022-01-22 20:29:31 -080015#include "y2022/vision/blob_detector.h"
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080016#include "y2022/vision/calibration_generated.h"
milind-u92195982022-01-22 20:29:31 -080017#include "y2022/vision/target_estimator.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080018
Henry Speiser1f34eea2022-01-30 14:35:21 -080019DEFINE_string(image_png, "", "A set of PNG images");
20
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080021namespace y2022 {
22namespace vision {
23
24using namespace frc971::vision;
25
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080026const calibration::CameraCalibration *CameraReader::FindCameraCalibration()
27 const {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080028 const std::string_view node_name = event_loop_->node()->name()->string_view();
29 const int team_number = aos::network::GetTeamNumber();
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080030 for (const calibration::CameraCalibration *candidate :
31 *calibration_data_->camera_calibrations()) {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080032 if (candidate->node_name()->string_view() != node_name) {
33 continue;
34 }
35 if (candidate->team_number() != team_number) {
36 continue;
37 }
38 return candidate;
39 }
40 LOG(FATAL) << ": Failed to find camera calibration for " << node_name
41 << " on " << team_number;
42}
43
Henry Speisere45e7a22022-02-04 23:17:01 -080044namespace {
45// Converts a vector of cv::Point to PointT for the flatbuffer
46flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Blob>>>
47CvBlobsToFbs(const std::vector<std::vector<cv::Point>> &blobs,
48 aos::Sender<TargetEstimate>::Builder &builder) {
49 std::vector<flatbuffers::Offset<Blob>> blobs_fbs;
50 for (auto &blob : blobs) {
51 std::vector<Point> points_fbs;
52 for (auto p : blob) {
53 points_fbs.push_back(Point{p.x, p.y});
54 }
55 auto points_offset = builder.fbb()->CreateVectorOfStructs(points_fbs);
56 auto blob_builder = builder.MakeBuilder<Blob>();
57 blob_builder.add_points(points_offset);
58 blobs_fbs.emplace_back(blob_builder.Finish());
59 }
60 return builder.fbb()->CreateVector(blobs_fbs.data(), blobs_fbs.size());
61}
62
63flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<BlobStatsFbs>>>
64BlobStatsToFbs(const std::vector<BlobDetector::BlobStats> blob_stats,
65 aos::Sender<TargetEstimate>::Builder &builder) {
66 std::vector<flatbuffers::Offset<BlobStatsFbs>> stats_fbs;
67 for (auto &stats : blob_stats) {
68 // Make BlobStatsFbs builder then fill each field using the BlobStats
69 // struct, then you finish it and add it to stats_fbs.
70 auto stats_builder = builder.MakeBuilder<BlobStatsFbs>();
71 Point centroid_fbs = Point{stats.centroid.x, stats.centroid.y};
72 stats_builder.add_centroid(&centroid_fbs);
73 stats_builder.add_aspect_ratio(stats.aspect_ratio);
74 stats_builder.add_area(stats.area);
75 stats_builder.add_num_points(stats.num_points);
76
77 auto current_stats = stats_builder.Finish();
78 stats_fbs.emplace_back(current_stats);
79 }
80 return builder.fbb()->CreateVector(stats_fbs.data(), stats_fbs.size());
81}
82} // namespace
83
Milind Upadhyay2b4404c2022-02-04 21:20:57 -080084void CameraReader::ProcessImage(cv::Mat image_mat) {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080085 // Remember, we're getting YUYV images, so we start by converting to RGB
86
Henry Speiser1f34eea2022-01-30 14:35:21 -080087 std::vector<std::vector<cv::Point>> filtered_blobs, unfiltered_blobs;
milind-u92195982022-01-22 20:29:31 -080088 std::vector<BlobDetector::BlobStats> blob_stats;
89 cv::Mat binarized_image =
90 cv::Mat::zeros(cv::Size(image_mat.cols, image_mat.rows), CV_8UC1);
Milind Upadhyaye7aa40c2022-01-29 22:36:21 -080091 cv::Point centroid;
Henry Speisere45e7a22022-02-04 23:17:01 -080092 BlobDetector::ExtractBlobs(image_mat, binarized_image, filtered_blobs,
93 unfiltered_blobs, blob_stats, centroid);
milind-u92195982022-01-22 20:29:31 -080094 auto builder = target_estimate_sender_.MakeBuilder();
Henry Speisere45e7a22022-02-04 23:17:01 -080095 flatbuffers::Offset<BlobResult> blob_result_offset;
96 {
97 const auto filtered_blobs_offset = CvBlobsToFbs(filtered_blobs, builder);
98 const auto unfiltered_blobs_offset =
99 CvBlobsToFbs(unfiltered_blobs, builder);
100 const auto blob_stats_offset = BlobStatsToFbs(blob_stats, builder);
101 const Point centroid_fbs = Point{centroid.x, centroid.y};
102
103 auto blob_result_builder = builder.MakeBuilder<BlobResult>();
104 blob_result_builder.add_filtered_blobs(filtered_blobs_offset);
105 blob_result_builder.add_unfiltered_blobs(unfiltered_blobs_offset);
106 blob_result_builder.add_blob_stats(blob_stats_offset);
107 blob_result_builder.add_centroid(&centroid_fbs);
108 blob_result_offset = blob_result_builder.Finish();
109 }
110
111 auto target_estimate_builder = builder.MakeBuilder<TargetEstimate>();
112 TargetEstimator::EstimateTargetLocation(centroid, CameraIntrinsics(),
113 CameraExtrinsics(),
114 &target_estimate_builder);
115 target_estimate_builder.add_blob_result(blob_result_offset);
116
117 builder.CheckOk(builder.Send(target_estimate_builder.Finish()));
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800118}
119
120void CameraReader::ReadImage() {
Henry Speiser1f34eea2022-01-30 14:35:21 -0800121 // Path is for reading from the Disk.
122 if (FLAGS_image_png != "") {
123 std::vector<cv::String> file_list;
124 cv::glob(FLAGS_image_png + "/*.png", file_list, false);
Henry Speiser1f34eea2022-01-30 14:35:21 -0800125 for (auto file : file_list) {
Henry Speiser3069ca92022-02-05 16:25:00 -0800126 // Sleep for 0.05 seconds in order to not reach the max number of messages
127 // that can be sent in a second.
128 std::this_thread::sleep_for(std::chrono::milliseconds(50));
Henry Speiser1f34eea2022-01-30 14:35:21 -0800129 LOG(INFO) << "Reading file " << file;
130 cv::Mat rgb_image = cv::imread(file.c_str());
131 ProcessImage(rgb_image);
132 }
133 event_loop_->Exit();
134 return;
135 }
136 // If we are not reading from the disk, we read the live camera stream.
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800137 if (!reader_->ReadLatestImage()) {
138 read_image_timer_->Setup(event_loop_->monotonic_now() +
139 std::chrono::milliseconds(10));
140 return;
141 }
142
Henry Speiser1f34eea2022-01-30 14:35:21 -0800143 const CameraImage &image = reader_->LatestImage();
144 cv::Mat image_mat(image.rows(), image.cols(), CV_8U);
145 CHECK(image_mat.isContinuous());
146
147 const int number_pixels = image.rows() * image.cols();
148 for (int i = 0; i < number_pixels; ++i) {
149 reinterpret_cast<uint8_t *>(image_mat.data)[i] =
150 image.data()->data()[i * 2];
151 }
152
153 ProcessImage(image_mat);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800154
155 reader_->SendLatestImage();
156 read_image_timer_->Setup(event_loop_->monotonic_now());
157}
158
159} // namespace vision
160} // namespace y2022