diff --git a/include/cloud_point/scared_dataset_loader.hpp b/include/cloud_point/scared_dataset_loader.hpp index bbf1d15..bb1e157 100644 --- a/include/cloud_point/scared_dataset_loader.hpp +++ b/include/cloud_point/scared_dataset_loader.hpp @@ -18,7 +18,8 @@ namespace score { class ScaredDatasetLoader { public: /// @brief Load calibration and images from @p keyframe_dir. - /// @throws std::runtime_error if any file cannot be opened or parsed. + /// @throws std::runtime_error if any file cannot be opened or parsed, + /// or if the left and right images have different dimensions. explicit ScaredDatasetLoader(const std::string &keyframe_dir); /// @brief Return the stereo calibration DTO (translation in metres). diff --git a/include/cloud_point/stereo_matcher_factory.hpp b/include/cloud_point/stereo_matcher_factory.hpp index a52ca9b..434dce6 100644 --- a/include/cloud_point/stereo_matcher_factory.hpp +++ b/include/cloud_point/stereo_matcher_factory.hpp @@ -13,6 +13,9 @@ class StereoMatcherFactory { /// @brief Create a stereo matcher of the requested type. /// If GPU is requested but unavailable, falls back to CPU. /// @param num_disparities Number of disparity levels for SGBM (default 128). + /// Must be a positive multiple of 16. + /// @throws std::invalid_argument if @p num_disparities is not a positive + /// multiple of 16. [[nodiscard]] static std::unique_ptr create(StereoAlgorithmType type, int num_disparities = 128); }; diff --git a/src/cloud_point/scared_dataset_loader.cpp b/src/cloud_point/scared_dataset_loader.cpp index f5358a6..8e6dd20 100644 --- a/src/cloud_point/scared_dataset_loader.cpp +++ b/src/cloud_point/scared_dataset_loader.cpp @@ -75,6 +75,16 @@ ScaredDatasetLoader::ScaredDatasetLoader(const std::string &keyframe_dir) { left_image_ = load_bgr_image(left_path); right_image_ = load_bgr_image(right_path); + if (left_image_.width != right_image_.width || + left_image_.height != right_image_.height) { + throw std::runtime_error( + "ScaredDatasetLoader: stereo pair dimension mismatch: left " + + std::to_string(left_image_.width) + "x" + + std::to_string(left_image_.height) + " vs right " + + std::to_string(right_image_.width) + "x" + + std::to_string(right_image_.height)); + } + calib_.width = left_image_.width; calib_.height = left_image_.height; diff --git a/src/cloud_point/scared_dataset_server.cpp b/src/cloud_point/scared_dataset_server.cpp index 109fecf..ad330d8 100644 --- a/src/cloud_point/scared_dataset_server.cpp +++ b/src/cloud_point/scared_dataset_server.cpp @@ -11,6 +11,7 @@ #include "cloud_point_rpc/rpc_dto.hpp" #include "cloud_point_rpc/rpc_server.hpp" #include "cloud_point_rpc/tcp_server.hpp" +#include #include #include #include @@ -28,16 +29,17 @@ int main(int argc, char *argv[]) { } const std::string keyframe_dir = argv[1]; - const int port = (argc >= 3) ? std::stoi(argv[2]) : 8080; LOG(INFO) << "SCARED dataset server starting"; LOG(INFO) << " keyframe_dir = " << keyframe_dir; - LOG(INFO) << " port = " << port; try { + const int port = (argc >= 3) ? std::stoi(argv[2]) : 8080; + LOG(INFO) << " port = " << port; + score::ScaredDatasetLoader loader(keyframe_dir); - uint64_t frame_counter = 0; + std::atomic frame_counter{0}; score::RpcServer rpc_server; rpc_server.register_method( diff --git a/src/cloud_point/stereo_matcher_factory.cpp b/src/cloud_point/stereo_matcher_factory.cpp index 2326540..92c356e 100644 --- a/src/cloud_point/stereo_matcher_factory.cpp +++ b/src/cloud_point/stereo_matcher_factory.cpp @@ -2,11 +2,19 @@ #include "cloud_point/cpu_stereo_matcher.hpp" #include "cloud_point/gpu_stereo_matcher.hpp" #include +#include +#include namespace score { std::unique_ptr StereoMatcherFactory::create(StereoAlgorithmType type, int num_disparities) { + if (num_disparities <= 0 || num_disparities % 16 != 0) { + throw std::invalid_argument( + "StereoMatcherFactory: num_disparities must be a positive " + "multiple of 16, got " + + std::to_string(num_disparities)); + } switch (type) { case StereoAlgorithmType::CPU: return std::make_unique(0, num_disparities); diff --git a/tests/test_scared_dataset.cpp b/tests/test_scared_dataset.cpp index bab9c93..6b407f0 100644 --- a/tests/test_scared_dataset.cpp +++ b/tests/test_scared_dataset.cpp @@ -6,6 +6,7 @@ /// SCARED_KEYFRAME_DIR=/path/to/test_dataset_8/keyframe_0 \ /// ./build/tests/unit_tests --gtest_filter=ScaredDataset* #include +#include #include #include #include @@ -83,7 +84,7 @@ TEST_F(ScaredDatasetTest, ComputeCloudFromRealData) { ScaredDatasetLoader loader(keyframe_dir_); - uint64_t frame_counter = 0; + std::atomic frame_counter{0}; auto rpc = std::make_unique(); rpc->register_method( diff --git a/tests/test_stereo_matcher.cpp b/tests/test_stereo_matcher.cpp index 06dba3f..cd2cec2 100644 --- a/tests/test_stereo_matcher.cpp +++ b/tests/test_stereo_matcher.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "cloud_point/cpu_stereo_matcher.hpp" #include "cloud_point/gpu_stereo_matcher.hpp" @@ -46,13 +47,30 @@ TEST(StereoMatcherTest, FactoryCpuCreatesNonNull) { EXPECT_FALSE(disparity.empty()); } +TEST(StereoMatcherTest, FactoryRejectsInvalidNumDisparities) { + EXPECT_THROW(std::ignore = StereoMatcherFactory::create( + StereoAlgorithmType::CPU, 0), + std::invalid_argument); + EXPECT_THROW(std::ignore = StereoMatcherFactory::create( + StereoAlgorithmType::CPU, -16), + std::invalid_argument); + EXPECT_THROW(std::ignore = StereoMatcherFactory::create( + StereoAlgorithmType::CPU, 150), + std::invalid_argument); +} + +TEST(StereoMatcherTest, FactoryAcceptsValidNumDisparities) { + auto matcher = StereoMatcherFactory::create(StereoAlgorithmType::CPU, 160); + ASSERT_NE(matcher, nullptr); +} + TEST(StereoMatcherTest, FactoryGpuFallsBackToCpuWhenUnavailable) { // On this machine CUDA is absent; factory should fall back to CPU. auto matcher = StereoMatcherFactory::create(StereoAlgorithmType::GPU); ASSERT_NE(matcher, nullptr); auto [left, right] = make_synthetic_stereo(); - EXPECT_NO_THROW(matcher->compute(left, right)); + EXPECT_NO_THROW(std::ignore = matcher->compute(left, right)); } TEST(StereoMatcherTest, GpuMatcherThrowsOnThisMachine) {