blob: 2f274bb700f15d32214a9652b346f51b4cf5617e [file] [log] [blame]
Austin Schuh25837f22021-06-27 15:49:14 -07001#ifndef Y2020_VISION_CHARUCO_LIB_H_
2#define Y2020_VISION_CHARUCO_LIB_H_
3
4#include <functional>
Milind Upadhyayc6e42ee2022-12-27 00:02:11 -08005#include <string_view>
6
Austin Schuh25837f22021-06-27 15:49:14 -07007#include "Eigen/Dense"
8#include "Eigen/Geometry"
Austin Schuh25837f22021-06-27 15:49:14 -07009#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070010#include "external/com_github_foxglove_schemas/ImageAnnotations_generated.h"
11#include <opencv2/aruco/charuco.hpp>
12#include <opencv2/calib3d.hpp>
13
Austin Schuh25837f22021-06-27 15:49:14 -070014#include "aos/events/event_loop.h"
Austin Schuhea7b0142021-10-08 22:04:53 -070015#include "aos/network/message_bridge_server_generated.h"
Jim Ostrowski814d2812022-12-11 23:17:14 -080016#include "frc971/vision/calibration_generated.h"
Austin Schuh25837f22021-06-27 15:49:14 -070017
Jim Ostrowskib3cab972022-12-03 15:47:00 -080018DECLARE_bool(visualize);
Jim Ostrowskib3cab972022-12-03 15:47:00 -080019
Austin Schuh25837f22021-06-27 15:49:14 -070020namespace frc971 {
21namespace vision {
22
23// Class to find extrinsics for a specified pi's camera using the provided
24// training data.
25class CameraCalibration {
26 public:
James Kuszmaul7e958812023-02-11 15:34:31 -080027 CameraCalibration(const calibration::CameraCalibration *calibration);
Austin Schuh25837f22021-06-27 15:49:14 -070028
29 // Intrinsics for the located camera.
James Kuszmaul7e958812023-02-11 15:34:31 -080030 cv::Mat CameraIntrinsics() const { return intrinsics_; }
31 Eigen::Matrix3d CameraIntrinsicsEigen() const { return intrinsics_eigen_; }
Austin Schuh25837f22021-06-27 15:49:14 -070032
33 // Distortion coefficients for the located camera.
James Kuszmaul7e958812023-02-11 15:34:31 -080034 cv::Mat CameraDistCoeffs() const { return dist_coeffs_; }
Austin Schuh25837f22021-06-27 15:49:14 -070035
36 private:
James Kuszmaul7e958812023-02-11 15:34:31 -080037 const cv::Mat intrinsics_;
38 const Eigen::Matrix3d intrinsics_eigen_;
39 const cv::Mat dist_coeffs_;
Austin Schuh25837f22021-06-27 15:49:14 -070040};
41
Jim Ostrowskib3cab972022-12-03 15:47:00 -080042// Helper class to call a function with a cv::Mat and age when an image shows up
43// on the provided channel. This hides all the conversions and wrangling needed
44// to view the image.
45// Can connect this with HandleImage function from CharucoExtrator for
46// full-service callback functionality
Austin Schuh25837f22021-06-27 15:49:14 -070047class ImageCallback {
48 public:
Austin Schuhac402e92023-01-08 13:56:20 -080049 enum class Format {
50 YUYV2 = 0,
51 BGR = 1,
52 GRAYSCALE = 2,
53 };
milind-u0cb53112023-02-03 20:32:55 -080054
55 // `max_age` is the age to start dropping frames at
56 ImageCallback(
57 aos::EventLoop *event_loop, std::string_view channel,
58 std::function<void(cv::Mat, aos::monotonic_clock::time_point)>
59 &&handle_image_fn,
60 aos::monotonic_clock::duration max_age = std::chrono::milliseconds(100));
Austin Schuh25837f22021-06-27 15:49:14 -070061
milind-u09fb1252023-01-28 19:21:41 -080062 void set_format(Format format) { format_ = format; }
Austin Schuhac402e92023-01-08 13:56:20 -080063
Austin Schuh25837f22021-06-27 15:49:14 -070064 private:
Austin Schuhc3419862023-01-08 13:54:36 -080065 void DisableTracing();
66
Austin Schuh25837f22021-06-27 15:49:14 -070067 aos::EventLoop *event_loop_;
Austin Schuhea7b0142021-10-08 22:04:53 -070068 aos::Fetcher<aos::message_bridge::ServerStatistics> server_fetcher_;
69 const aos::Node *source_node_;
70 std::function<void(cv::Mat, aos::monotonic_clock::time_point)> handle_image_;
Austin Schuhc3419862023-01-08 13:54:36 -080071 aos::TimerHandler *timer_fn_;
72
73 bool disabling_ = false;
74
75 aos::Ftrace ftrace_;
Austin Schuhac402e92023-01-08 13:56:20 -080076
77 Format format_ = Format::BGR;
milind-u0cb53112023-02-03 20:32:55 -080078
79 aos::monotonic_clock::duration max_age_;
Austin Schuh25837f22021-06-27 15:49:14 -070080};
81
Milind Upadhyayc6e42ee2022-12-27 00:02:11 -080082// Types of targets that a CharucoExtractor can detect in images
83enum class TargetType : uint8_t {
milind-u09fb1252023-01-28 19:21:41 -080084 kAruco = 0,
85 kCharuco = 1,
86 kCharucoDiamond = 2
Milind Upadhyayc6e42ee2022-12-27 00:02:11 -080087};
88
James Kuszmauld6199be2023-02-11 19:56:28 -080089TargetType TargetTypeFromString(std::string_view str);
90std::ostream &operator<<(std::ostream &os, TargetType target_type);
91
Austin Schuh25837f22021-06-27 15:49:14 -070092// Class which calls a callback each time an image arrives with the information
93// extracted from it.
94class CharucoExtractor {
95 public:
Jim Ostrowski2f2685f2023-03-25 11:57:54 -070096 // Setting up a constructor that doesn't require an event_loop, so we can call
97 // and get results back from ProcessImage directly
98 CharucoExtractor(const calibration::CameraCalibration *calibration,
99 const TargetType target_type);
100
Austin Schuh25837f22021-06-27 15:49:14 -0700101 // The callback takes the following arguments:
102 // cv::Mat -> image with overlays drawn on it.
Austin Schuhea7b0142021-10-08 22:04:53 -0700103 // monotonic_clock::time_point -> Time on this node when this image was
104 // captured.
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800105 // std::vector<Vec4i> -> target ids (aruco/april in first slot of Vec4i)
106 // NOTE: We use Vec4i since that stores the ids for the charuco diamond target
107 // std::vector<std::vector<cv::Point2f>> -> charuco_corners
Austin Schuh25837f22021-06-27 15:49:14 -0700108 // bool -> true if rvec/tvec is valid.
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800109 // std::vector<Eigen::Vector3d> -> rvec
110 // std::vector<Eigen::Vector3d> -> tvec
111 // NOTE: we return as a vector since all but charuco boards could have
112 // multiple targets in an image; for charuco boards, there should be just one
113 // element
Austin Schuhea7b0142021-10-08 22:04:53 -0700114 CharucoExtractor(
James Kuszmaul7e958812023-02-11 15:34:31 -0800115 aos::EventLoop *event_loop,
116 const calibration::CameraCalibration *calibration, TargetType target_type,
Milind Upadhyayc6e42ee2022-12-27 00:02:11 -0800117 std::string_view image_channel,
Austin Schuhea7b0142021-10-08 22:04:53 -0700118 std::function<void(cv::Mat, aos::monotonic_clock::time_point,
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800119 std::vector<cv::Vec4i>,
120 std::vector<std::vector<cv::Point2f>>, bool,
121 std::vector<Eigen::Vector3d>,
122 std::vector<Eigen::Vector3d>)> &&handle_charuco_fn);
123
124 // Handles the image by detecting the charuco board in it.
Jim Ostrowski2f2685f2023-03-25 11:57:54 -0700125 void HandleImage(cv::Mat rgb_image,
126 const aos::monotonic_clock::time_point eof);
127
128 void ProcessImage(cv::Mat rgb_image,
129 const aos::monotonic_clock::time_point eof,
130 const aos::monotonic_clock::time_point current_time,
131 std::vector<cv::Vec4i> &result_ids,
132 std::vector<std::vector<cv::Point2f>> &result_corners,
133 bool &valid, std::vector<Eigen::Vector3d> &rvecs_eigen,
134 std::vector<Eigen::Vector3d> &tvecs_eigen);
Austin Schuh25837f22021-06-27 15:49:14 -0700135
136 // Returns the aruco dictionary in use.
137 cv::Ptr<cv::aruco::Dictionary> dictionary() const { return dictionary_; }
138 // Returns the aruco board in use.
139 cv::Ptr<cv::aruco::CharucoBoard> board() const { return board_; }
140
141 // Returns the camera matrix for this camera.
James Kuszmaul7e958812023-02-11 15:34:31 -0800142 const cv::Mat camera_matrix() const {
143 return calibration_.CameraIntrinsics();
144 }
Austin Schuh25837f22021-06-27 15:49:14 -0700145 // Returns the distortion coefficients for this camera.
James Kuszmaul7e958812023-02-11 15:34:31 -0800146 const cv::Mat dist_coeffs() const { return calibration_.CameraDistCoeffs(); }
Austin Schuh25837f22021-06-27 15:49:14 -0700147
148 private:
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800149 // Creates the dictionary, board, and other parameters for the appropriate
150 // (ch)aruco target
151 void SetupTargetData();
152
153 // Draw the axes from the pose(s) on the image
154 void DrawTargetPoses(cv::Mat rgb_image, std::vector<cv::Vec3d> rvecs,
155 std::vector<cv::Vec3d> tvecs);
156
Jim Ostrowski2f2685f2023-03-25 11:57:54 -0700157 // Helper function to convert rotation (rvecs) and translation (tvecs)
158 // vectors into Eigen vectors and store in corresponding vectors
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800159 void PackPoseResults(std::vector<cv::Vec3d> &rvecs,
160 std::vector<cv::Vec3d> &tvecs,
161 std::vector<Eigen::Vector3d> *rvecs_eigen,
162 std::vector<Eigen::Vector3d> *tvecs_eigen);
Austin Schuh25837f22021-06-27 15:49:14 -0700163
Austin Schuhea7b0142021-10-08 22:04:53 -0700164 aos::EventLoop *event_loop_;
Austin Schuh25837f22021-06-27 15:49:14 -0700165
166 cv::Ptr<cv::aruco::Dictionary> dictionary_;
167 cv::Ptr<cv::aruco::CharucoBoard> board_;
168
Milind Upadhyayc6e42ee2022-12-27 00:02:11 -0800169 // Type of targets to detect
170 TargetType target_type_;
171 // Channel to listen on for images
172 std::string_view image_channel_;
173
174 // Length of a side of the target marker
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800175 double marker_length_;
176 // Length of a side of the checkerboard squares (around the marker)
177 double square_length_;
178
James Kuszmaul7e958812023-02-11 15:34:31 -0800179 CameraCalibration calibration_;
Austin Schuh25837f22021-06-27 15:49:14 -0700180
Austin Schuh25837f22021-06-27 15:49:14 -0700181 // Function to call.
Jim Ostrowskib3cab972022-12-03 15:47:00 -0800182 std::function<void(
183 cv::Mat, aos::monotonic_clock::time_point, std::vector<cv::Vec4i>,
184 std::vector<std::vector<cv::Point2f>>, bool, std::vector<Eigen::Vector3d>,
185 std::vector<Eigen::Vector3d>)>
Austin Schuh25837f22021-06-27 15:49:14 -0700186 handle_charuco_;
187};
188
James Kuszmaul969e4ab2023-01-28 16:09:19 -0800189// Puts the provided charuco corners into a foxglove ImageAnnotation type for
190// visualization purposes.
191flatbuffers::Offset<foxglove::ImageAnnotations> BuildAnnotations(
Jim Ostrowski5e2c5e62023-02-26 12:52:56 -0800192 flatbuffers::FlatBufferBuilder *fbb,
James Kuszmaul969e4ab2023-01-28 16:09:19 -0800193 const aos::monotonic_clock::time_point monotonic_now,
Jim Ostrowski5e2c5e62023-02-26 12:52:56 -0800194 const std::vector<std::vector<cv::Point2f>> &corners,
195 const std::vector<double> rgba_color = std::vector<double>{0.0, 1.0, 0.0,
196 1.0},
197 const double thickness = 5,
198 const foxglove::PointsAnnotationType line_type =
199 foxglove::PointsAnnotationType::POINTS);
200
Jim Ostrowski2f2685f2023-03-25 11:57:54 -0700201// Creates a PointsAnnotation to build up ImageAnnotations with different
202// types
Jim Ostrowski5e2c5e62023-02-26 12:52:56 -0800203flatbuffers::Offset<foxglove::PointsAnnotation> BuildPointsAnnotation(
204 flatbuffers::FlatBufferBuilder *fbb,
205 const aos::monotonic_clock::time_point monotonic_now,
206 const std::vector<cv::Point2f> &corners,
207 const std::vector<double> rgba_color = std::vector<double>{0.0, 1.0, 0.0,
208 1.0},
209 const double thickness = 5,
210 const foxglove::PointsAnnotationType line_type =
211 foxglove::PointsAnnotationType::POINTS);
James Kuszmaul969e4ab2023-01-28 16:09:19 -0800212
Austin Schuh25837f22021-06-27 15:49:14 -0700213} // namespace vision
214} // namespace frc971
215
216#endif // Y2020_VISION_CHARUCO_LIB_H_