blob: e6ebc4d554780df9039ceedeaa887f57cb6c5d48 [file] [log] [blame]
James Kuszmaul77d536c2023-02-11 17:30:59 -08001#include "frc971/vision/foxglove_image_converter_lib.h"
2
Austin Schuh99f7c6a2024-06-25 22:07:44 -07003#include "absl/flags/flag.h"
James Kuszmaul0c593962023-01-28 16:04:20 -08004#include <opencv2/imgcodecs.hpp>
5#include <opencv2/imgproc.hpp>
6
Austin Schuh99f7c6a2024-06-25 22:07:44 -07007ABSL_FLAG(int32_t, jpeg_quality, 60,
8 "Compression quality of JPEGs, 0-100; lower numbers mean lower "
9 "quality and resulting image sizes.");
10ABSL_FLAG(uint32_t, max_period_ms, 100,
11 "Fastest period at which to convert images, to limit CPU usage.");
James Kuszmaul77d536c2023-02-11 17:30:59 -080012
James Kuszmaul0c593962023-01-28 16:04:20 -080013namespace frc971::vision {
James Kuszmaul0c593962023-01-28 16:04:20 -080014std::string_view ExtensionForCompression(ImageCompression compression) {
15 switch (compression) {
16 case ImageCompression::kJpeg:
17 return "jpeg";
18 case ImageCompression::kPng:
19 return "png";
20 }
21}
James Kuszmaul59a308f2023-01-28 19:14:07 -080022
James Kuszmaul0c593962023-01-28 16:04:20 -080023flatbuffers::Offset<foxglove::CompressedImage> CompressImage(
James Kuszmaul59a308f2023-01-28 19:14:07 -080024 const cv::Mat image, const aos::monotonic_clock::time_point eof,
25 flatbuffers::FlatBufferBuilder *fbb, ImageCompression compression) {
James Kuszmaul0c593962023-01-28 16:04:20 -080026 std::string_view format = ExtensionForCompression(compression);
27 // imencode doesn't let us pass in anything other than an std::vector, and
28 // performance isn't yet a big enough issue to try to avoid the copy.
29 std::vector<uint8_t> buffer;
Austin Schuh99f7c6a2024-06-25 22:07:44 -070030 CHECK(cv::imencode(
31 absl::StrCat(".", format), image, buffer,
32 {cv::IMWRITE_JPEG_QUALITY, absl::GetFlag(FLAGS_jpeg_quality)}));
James Kuszmaul0c593962023-01-28 16:04:20 -080033 const flatbuffers::Offset<flatbuffers::Vector<uint8_t>> data_offset =
34 fbb->CreateVector(buffer);
James Kuszmaul59a308f2023-01-28 19:14:07 -080035 const struct timespec timestamp_t = aos::time::to_timespec(eof);
James Kuszmaul0c593962023-01-28 16:04:20 -080036 const foxglove::Time time{static_cast<uint32_t>(timestamp_t.tv_sec),
37 static_cast<uint32_t>(timestamp_t.tv_nsec)};
38 const flatbuffers::Offset<flatbuffers::String> format_offset =
39 fbb->CreateString(format);
40 foxglove::CompressedImage::Builder builder(*fbb);
41 builder.add_timestamp(&time);
42 builder.add_data(data_offset);
43 builder.add_format(format_offset);
44 return builder.Finish();
45}
46
47FoxgloveImageConverter::FoxgloveImageConverter(aos::EventLoop *event_loop,
48 std::string_view input_channel,
49 std::string_view output_channel,
50 ImageCompression compression)
51 : event_loop_(event_loop),
James Kuszmaul59a308f2023-01-28 19:14:07 -080052 image_callback_(
53 event_loop_, input_channel,
54 [this, compression](const cv::Mat image,
55 const aos::monotonic_clock::time_point eof) {
James Kuszmaul682daef2024-03-03 14:25:10 -080056 if (event_loop_->monotonic_now() >
Austin Schuh99f7c6a2024-06-25 22:07:44 -070057 (std::chrono::milliseconds(absl::GetFlag(FLAGS_max_period_ms)) +
James Kuszmaul682daef2024-03-03 14:25:10 -080058 sender_.monotonic_sent_time())) {
59 auto builder = sender_.MakeBuilder();
60 builder.CheckOk(builder.Send(
61 CompressImage(image, eof, builder.fbb(), compression)));
62 }
James Kuszmaul59a308f2023-01-28 19:14:07 -080063 }),
James Kuszmaul0c593962023-01-28 16:04:20 -080064 sender_(
James Kuszmaul59a308f2023-01-28 19:14:07 -080065 event_loop_->MakeSender<foxglove::CompressedImage>(output_channel)) {}
James Kuszmaul0c593962023-01-28 16:04:20 -080066} // namespace frc971::vision