From 2b06100eb9163df5a87c286e09fe08fefd74f620 Mon Sep 17 00:00:00 2001 From: nvidia Date: Tue, 28 Apr 2026 15:57:57 -0700 Subject: [PATCH 1/6] add libjpeg benchmark Signed-off-by: nvidia --- src/test/integration_test/CMakeLists.txt | 3 ++ .../integration_test/libjpeg_benchmark.cc | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/test/integration_test/libjpeg_benchmark.cc diff --git a/src/test/integration_test/CMakeLists.txt b/src/test/integration_test/CMakeLists.txt index 951f9606..c41fcfc8 100644 --- a/src/test/integration_test/CMakeLists.txt +++ b/src/test/integration_test/CMakeLists.txt @@ -30,3 +30,6 @@ target_link_libraries(pva_test PRIVATE utils localization vpi) add_executable(bfs-test bfs_tester.cc) target_link_libraries(bfs-test PRIVATE pathing utils nlohmann_json::nlohmann_json wpiutil) + +add_executable(libjpeg-benchmark libjpeg_benchmark.cc) +target_link_libraries(libjpeg-benchmark PRIVATE ${OpenCV_LIBS} utils) diff --git a/src/test/integration_test/libjpeg_benchmark.cc b/src/test/integration_test/libjpeg_benchmark.cc new file mode 100644 index 00000000..7d565593 --- /dev/null +++ b/src/test/integration_test/libjpeg_benchmark.cc @@ -0,0 +1,49 @@ +#include "src/utils/pch.h" +#include "src/utils/log.h" +#include "absl/flags/flag.h" +#include "absl/flags/internal/flag.h" +#include "absl/flags/parse.h" + +ABSL_FLAG(std::string, image_path, "path/to/image.jpg", "Path to the image file to be loaded and decoded."); + +auto loadImage(std::string path) -> std::vector { + std::ifstream file(path, std::ios::binary); + if (!file) { + LOG(FATAL) << "Image could not be loaded; path invalid or image doesn't exist."; + } + std::vector data(std::istreambuf_iterator(file), {}); + return data; +} + +auto decodeImage(std::vector raw) -> cv::Mat { + cv::Mat decoded = cv::imdecode(raw, cv::IMREAD_COLOR); + return decoded; +} + +auto main(int argc, char** argv) -> int { + absl::ParseCommandLine(argc, argv); + std::string imagePath = absl::GetFlag(FLAGS_image_path); + std::vector rawImageData = loadImage(imagePath); + // print which jpeg library we are using so that we know and don't get mixed up + std::istringstream stream(cv::getBuildInformation()); + std::string line; + while (std::getline(stream, line)) { + if (line.find("jpeg:") != std::string::npos || line.find("JPEG:") != std::string::npos) { + LOG(INFO) << line; + } + } + const uint tests = 1000; + std::vector trials; + for (uint i = 0; i < tests; ++i) { + auto start = std::chrono::high_resolution_clock::now(); + cv::Mat decodedImage = decodeImage(rawImageData); + auto end = std::chrono::high_resolution_clock::now(); + double ms = std::chrono::duration(end - start).count(); + trials.push_back(ms); + } + + double total = std::accumulate(trials.begin(), trials.end(), 0.0); + double average = total / trials.size(); + LOG(INFO) << "Average decoding time over " << tests << " trials: " << average << " ms"; + return 0; +} From bc4bebed27255d001c279a8f04318aaf3310c636 Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 28 Apr 2026 23:11:54 +0000 Subject: [PATCH 2/6] comments Signed-off-by: Ari --- .../integration_test/libjpeg_benchmark.cc | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/test/integration_test/libjpeg_benchmark.cc b/src/test/integration_test/libjpeg_benchmark.cc index 7d565593..dcc9fe79 100644 --- a/src/test/integration_test/libjpeg_benchmark.cc +++ b/src/test/integration_test/libjpeg_benchmark.cc @@ -1,21 +1,26 @@ -#include "src/utils/pch.h" -#include "src/utils/log.h" +#include +#include +#include #include "absl/flags/flag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/parse.h" +#include "src/utils/log.h" +#include "src/utils/pch.h" -ABSL_FLAG(std::string, image_path, "path/to/image.jpg", "Path to the image file to be loaded and decoded."); +ABSL_FLAG(std::string, image_path, "path/to/image.jpg", // NOLINT + "Path to the image file to be loaded and decoded."); -auto loadImage(std::string path) -> std::vector { +auto loadImage(const std::string& path) -> std::vector { std::ifstream file(path, std::ios::binary); if (!file) { - LOG(FATAL) << "Image could not be loaded; path invalid or image doesn't exist."; + LOG(FATAL) << "Image could not be loaded from path '" << path + << "'; path invalid or image doesn't exist."; } std::vector data(std::istreambuf_iterator(file), {}); return data; } -auto decodeImage(std::vector raw) -> cv::Mat { +auto decodeImage(const std::vector& raw) -> cv::Mat { cv::Mat decoded = cv::imdecode(raw, cv::IMREAD_COLOR); return decoded; } @@ -28,9 +33,10 @@ auto main(int argc, char** argv) -> int { std::istringstream stream(cv::getBuildInformation()); std::string line; while (std::getline(stream, line)) { - if (line.find("jpeg:") != std::string::npos || line.find("JPEG:") != std::string::npos) { - LOG(INFO) << line; - } + if (line.find("jpeg:") != std::string::npos || + line.find("JPEG:") != std::string::npos) { + LOG(INFO) << line; + } } const uint tests = 1000; std::vector trials; @@ -44,6 +50,7 @@ auto main(int argc, char** argv) -> int { double total = std::accumulate(trials.begin(), trials.end(), 0.0); double average = total / trials.size(); - LOG(INFO) << "Average decoding time over " << tests << " trials: " << average << " ms"; + LOG(INFO) << "Average decoding time over " << tests << " trials: " << average + << " ms"; return 0; } From 66c87ccb556bb5cb28d22a1778743f7768be711c Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 28 Apr 2026 23:17:31 +0000 Subject: [PATCH 3/6] Check if image was properly decoded before adding time to average Signed-off-by: Ari --- src/test/integration_test/libjpeg_benchmark.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/integration_test/libjpeg_benchmark.cc b/src/test/integration_test/libjpeg_benchmark.cc index dcc9fe79..5cc9b078 100644 --- a/src/test/integration_test/libjpeg_benchmark.cc +++ b/src/test/integration_test/libjpeg_benchmark.cc @@ -44,6 +44,10 @@ auto main(int argc, char** argv) -> int { auto start = std::chrono::high_resolution_clock::now(); cv::Mat decodedImage = decodeImage(rawImageData); auto end = std::chrono::high_resolution_clock::now(); + if (decodedImage.empty()) { + LOG(INFO) << "image decode failed"; + continue; + } double ms = std::chrono::duration(end - start).count(); trials.push_back(ms); } From 60b48c392fa92a62b852eb9f64a9a432e233fc2d Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 28 Apr 2026 16:24:32 -0700 Subject: [PATCH 4/6] Add sstream include for clearer build and runtime Signed-off-by: Ari --- src/test/integration_test/libjpeg_benchmark.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/integration_test/libjpeg_benchmark.cc b/src/test/integration_test/libjpeg_benchmark.cc index 5cc9b078..c065a64e 100644 --- a/src/test/integration_test/libjpeg_benchmark.cc +++ b/src/test/integration_test/libjpeg_benchmark.cc @@ -6,6 +6,7 @@ #include "absl/flags/parse.h" #include "src/utils/log.h" #include "src/utils/pch.h" +#include ABSL_FLAG(std::string, image_path, "path/to/image.jpg", // NOLINT "Path to the image file to be loaded and decoded."); From 029efb3ddfb3d8ebfd68786f89f3de4cb080b4d2 Mon Sep 17 00:00:00 2001 From: Ari Date: Tue, 28 Apr 2026 16:58:07 -0700 Subject: [PATCH 5/6] absl flag for num trials Signed-off-by: Ari --- src/test/integration_test/libjpeg_benchmark.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/integration_test/libjpeg_benchmark.cc b/src/test/integration_test/libjpeg_benchmark.cc index c065a64e..e14d043e 100644 --- a/src/test/integration_test/libjpeg_benchmark.cc +++ b/src/test/integration_test/libjpeg_benchmark.cc @@ -11,6 +11,8 @@ ABSL_FLAG(std::string, image_path, "path/to/image.jpg", // NOLINT "Path to the image file to be loaded and decoded."); +ABSL_FLAG(uint, num_trials, 10000, "Number of decoding trials to perform."); // NOLINT + auto loadImage(const std::string& path) -> std::vector { std::ifstream file(path, std::ios::binary); if (!file) { @@ -39,7 +41,7 @@ auto main(int argc, char** argv) -> int { LOG(INFO) << line; } } - const uint tests = 1000; + const uint tests = absl::GetFlag(FLAGS_num_trials); std::vector trials; for (uint i = 0; i < tests; ++i) { auto start = std::chrono::high_resolution_clock::now(); From e0362c52a066b94b84972787ad2493b7c924e435 Mon Sep 17 00:00:00 2001 From: Ari Date: Fri, 1 May 2026 10:44:55 -0700 Subject: [PATCH 6/6] wip grab function --- src/camera/camera.h | 1 + src/camera/cv_camera.cc | 11 +++++++---- src/camera/cv_camera.h | 2 ++ src/camera/disk_camera.cc | 2 ++ src/camera/disk_camera.h | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/camera/camera.h b/src/camera/camera.h index 07736b7c..57fc2436 100644 --- a/src/camera/camera.h +++ b/src/camera/camera.h @@ -33,5 +33,6 @@ class ICamera { [[nodiscard]] virtual auto GetCameraConstant() const -> camera_constant_t = 0; virtual auto IsDone() -> bool { return false; } virtual ~ICamera() = default; + virtual void Grab() = 0; }; } // namespace camera diff --git a/src/camera/cv_camera.cc b/src/camera/cv_camera.cc index 96b6227f..7e3e5984 100644 --- a/src/camera/cv_camera.cc +++ b/src/camera/cv_camera.cc @@ -66,10 +66,6 @@ CVCamera::CVCamera(const CameraConstant& c, std::optional log_path) auto CVCamera::GetFrame() -> timestamped_frame_t { timestamped_frame_t timestamped_frame; cv::Mat raw_image; - if (!cap_.grab()) { - Restart(); - LOG(WARNING) << "Restarting camera"; - } timestamped_frame.timestamp = frc::Timer::GetFPGATimestamp().to(); cap_.retrieve(raw_image); @@ -96,6 +92,13 @@ auto CVCamera::Restart() -> void { std::this_thread::sleep_for(std::chrono::seconds(3)); } +auto CVCamera::Grab() -> void { + if (!cap_.grab()) { + Restart(); + LOG(WARNING) << "Restarting camera"; + cap_timestamp_ = frc::Timer::GetFPGATimestamp().to(); +} + auto CVCamera::GetCameraConstant() const -> camera_constant_t { return camera_constant_; } diff --git a/src/camera/cv_camera.h b/src/camera/cv_camera.h index 048d96b7..64d7b3d1 100644 --- a/src/camera/cv_camera.h +++ b/src/camera/cv_camera.h @@ -13,6 +13,7 @@ class CVCamera : public ICamera { std::optional log_path = std::nullopt); auto GetFrame() -> timestamped_frame_t override; auto Restart() -> void override; + auto Grab() -> void override; [[nodiscard]] auto GetCameraConstant() const -> camera_constant_t override; private: @@ -21,6 +22,7 @@ class CVCamera : public ICamera { std::string pipeline_; std::optional log_path_; cv::Mat backup_image_; + double cap_timestamp_; }; } // namespace camera diff --git a/src/camera/disk_camera.cc b/src/camera/disk_camera.cc index f3663c58..f0fea313 100644 --- a/src/camera/disk_camera.cc +++ b/src/camera/disk_camera.cc @@ -80,6 +80,8 @@ auto DiskCamera::GetFrame() -> timestamped_frame_t { auto DiskCamera::Restart() -> void {} +auto DiskCamera::Grab() -> void {} + auto DiskCamera::GetCameraConstant() const -> camera_constant_t { return *camera_constant_; } diff --git a/src/camera/disk_camera.h b/src/camera/disk_camera.h index 08d98d2d..73c3be56 100644 --- a/src/camera/disk_camera.h +++ b/src/camera/disk_camera.h @@ -31,6 +31,7 @@ class DiskCamera : public ICamera { std::optional end = std::nullopt); auto GetFrame() -> timestamped_frame_t override; auto Restart() -> void override; + auto Grab() -> void override; auto IsDone() -> bool override { return image_paths_.empty(); } [[nodiscard]] auto GetCameraConstant() const -> camera_constant_t override;