blob: 8317c0915e623c248235d3ae963d10fdf4d90fa2 [file] [log] [blame]
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08001#ifndef Y2022_VISION_CAMERA_READER_H_
2#define Y2022_VISION_CAMERA_READER_H_
3
4#include <math.h>
5
6#include <opencv2/calib3d.hpp>
7#include <opencv2/features2d.hpp>
Henry Speiser1f34eea2022-01-30 14:35:21 -08008#include <opencv2/imgcodecs.hpp>
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08009#include <opencv2/imgproc.hpp>
10
Henry Speiser1f34eea2022-01-30 14:35:21 -080011#include "aos/events/shm_event_loop.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080012#include "aos/flatbuffer_merge.h"
13#include "aos/network/team_number.h"
14#include "frc971/vision/v4l2_reader.h"
15#include "frc971/vision/vision_generated.h"
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -070016#include "y2022/localizer/localizer_output_generated.h"
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080017#include "y2022/vision/calibration_data.h"
18#include "y2022/vision/calibration_generated.h"
Jim Ostrowski2a483b32022-02-15 18:19:14 -080019#include "y2022/vision/gpio.h"
milind-u92195982022-01-22 20:29:31 -080020#include "y2022/vision/target_estimate_generated.h"
Milind Upadhyayf61e1482022-02-11 20:42:55 -080021#include "y2022/vision/target_estimator.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080022
23namespace y2022 {
24namespace vision {
25
26using namespace frc971::vision;
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -070027using frc971::controls::LedOutput;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080028
Jim Ostrowski2a483b32022-02-15 18:19:14 -080029// TODO<jim>: Probably need to break out LED control to separate process
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080030class CameraReader {
31 public:
Milind Upadhyaya31f0272022-04-03 13:55:22 -070032 static const calibration::CameraCalibration *FindCameraCalibration(
33 const calibration::CalibrationData *calibration_data,
34 std::string_view node_name, int team_number);
35
36 static cv::Mat CameraIntrinsics(
37 const calibration::CameraCalibration *camera_calibration) {
38 cv::Mat result(3, 3, CV_32F,
39 const_cast<void *>(static_cast<const void *>(
40 camera_calibration->intrinsics()->data())));
41 result.convertTo(result, CV_64F);
42 CHECK_EQ(result.total(), camera_calibration->intrinsics()->size());
43 return result;
44 }
45
46 static cv::Mat CameraExtrinsics(
47 const calibration::CameraCalibration *camera_calibration) {
48 // TODO(james): What's the principled way to handle non-z-axis turrets?
49 const frc971::vision::calibration::TransformationMatrix *transform =
50 camera_calibration->has_turret_extrinsics()
51 ? camera_calibration->turret_extrinsics()
52 : camera_calibration->fixed_extrinsics();
53
54 cv::Mat result(4, 4, CV_32F,
55 const_cast<void *>(
56 static_cast<const void *>(transform->data()->data())));
57 result.convertTo(result, CV_64F);
58 CHECK_EQ(result.total(), transform->data()->size());
59 return result;
60 }
61
62 static cv::Mat CameraDistCoeffs(
63 const calibration::CameraCalibration *camera_calibration) {
64 const cv::Mat result(5, 1, CV_32F,
65 const_cast<void *>(static_cast<const void *>(
66 camera_calibration->dist_coeffs()->data())));
67 CHECK_EQ(result.total(), camera_calibration->dist_coeffs()->size());
68 return result;
69 }
70
71 static std::pair<cv::Mat, cv::Mat> ComputeUndistortMaps(
72 const cv::Mat intrinsics, const cv::Mat dist_coeffs) {
73 std::pair<cv::Mat, cv::Mat> undistort_maps;
74 static const cv::Size kImageSize = {640, 480};
75 cv::initUndistortRectifyMap(intrinsics, dist_coeffs, cv::Mat(), intrinsics,
76 kImageSize, CV_16SC2, undistort_maps.first,
77 undistort_maps.second);
78 return undistort_maps;
79 }
80
81 static cv::Mat UndistortImage(cv::Mat image_distorted,
82 std::pair<cv::Mat, cv::Mat> undistort_maps) {
83 cv::Mat image;
84 cv::remap(image_distorted, image, undistort_maps.first,
85 undistort_maps.second, cv::INTER_LINEAR);
86 return image;
87 }
88
Henry Speiser1f34eea2022-01-30 14:35:21 -080089 CameraReader(aos::ShmEventLoop *event_loop,
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080090 const calibration::CalibrationData *calibration_data,
91 V4L2Reader *reader)
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080092 : event_loop_(event_loop),
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080093 calibration_data_(calibration_data),
Milind Upadhyaya31f0272022-04-03 13:55:22 -070094 camera_calibration_(FindCameraCalibration(
95 calibration_data_, event_loop_->node()->name()->string_view(),
96 aos::network::GetTeamNumber())),
97 undistort_maps_(
98 ComputeUndistortMaps(CameraIntrinsics(), CameraDistCoeffs())),
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080099 reader_(reader),
100 image_sender_(event_loop->MakeSender<CameraImage>("/camera")),
Milind Upadhyayf61e1482022-02-11 20:42:55 -0800101 target_estimator_(CameraIntrinsics(), CameraExtrinsics()),
milind-u92195982022-01-22 20:29:31 -0800102 target_estimate_sender_(
103 event_loop->MakeSender<TargetEstimate>("/camera")),
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -0700104 localizer_output_fetcher_(
105 event_loop->MakeFetcher<frc971::controls::LocalizerOutput>(
106 "/localizer")),
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800107 read_image_timer_(event_loop->AddTimer([this]() { ReadImage(); })),
Jim Ostrowskia49d20e2022-02-26 18:34:05 -0800108 gpio_imu_pin_(GPIOControl(GPIO_PIN_SCLK_IMU, kGPIOIn)),
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800109 gpio_pwm_control_(GPIOPWMControl(GPIO_PIN_SCK_PWM, duty_cycle_)),
110 gpio_disable_control_(
111 GPIOControl(GPIO_PIN_MOSI_DISABLE, kGPIOOut, kGPIOLow)) {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800112 event_loop->OnRun(
113 [this]() { read_image_timer_->Setup(event_loop_->monotonic_now()); });
114 }
115
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800116 void SetDutyCycle(double duty_cycle) {
117 duty_cycle_ = duty_cycle;
118 gpio_pwm_control_.setPWMDutyCycle(duty_cycle_);
119 }
120
121 double GetDutyCycle() { return duty_cycle_; }
122
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800123 private:
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800124 // Processes an image (including sending the results).
Milind Upadhyay3c1a5c02022-03-27 16:27:19 -0700125 void ProcessImage(cv::Mat image_mat_distorted,
126 int64_t image_monotonic_timestamp_ns);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800127
128 // Reads an image, and then performs all of our processing on it.
129 void ReadImage();
130
131 cv::Mat CameraIntrinsics() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700132 return CameraIntrinsics(camera_calibration_);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800133 }
134
milind-u92195982022-01-22 20:29:31 -0800135 cv::Mat CameraExtrinsics() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700136 return CameraExtrinsics(camera_calibration_);
milind-u92195982022-01-22 20:29:31 -0800137 }
138
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800139 cv::Mat CameraDistCoeffs() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700140 return CameraDistCoeffs(camera_calibration_);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800141 }
142
Henry Speiser1f34eea2022-01-30 14:35:21 -0800143 aos::ShmEventLoop *const event_loop_;
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800144 const calibration::CalibrationData *const calibration_data_;
145 const calibration::CameraCalibration *const camera_calibration_;
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700146 std::pair<cv::Mat, cv::Mat> undistort_maps_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800147 V4L2Reader *const reader_;
148 aos::Sender<CameraImage> image_sender_;
Milind Upadhyayf61e1482022-02-11 20:42:55 -0800149 TargetEstimator target_estimator_;
milind-u92195982022-01-22 20:29:31 -0800150 aos::Sender<TargetEstimate> target_estimate_sender_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800151
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -0700152 LedOutput prev_led_output_ = LedOutput::ON;
153 aos::Fetcher<frc971::controls::LocalizerOutput> localizer_output_fetcher_;
154
milind-u92195982022-01-22 20:29:31 -0800155 // We schedule this immediately to read an image. Having it on a timer
156 // means other things can run on the event loop in between.
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800157 aos::TimerHandler *const read_image_timer_;
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800158
159 double duty_cycle_ = 0.0;
Jim Ostrowskia49d20e2022-02-26 18:34:05 -0800160 GPIOControl gpio_imu_pin_;
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800161 GPIOPWMControl gpio_pwm_control_;
162 GPIOControl gpio_disable_control_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800163};
164
165} // namespace vision
166} // namespace y2022
167#endif // Y2022_VISION_CAMERA_READER_H_