Skip to content

Commit a097be1

Browse files
Add camera solver test for soccer cones dataset.
1 parent aba5f6e commit a097be1

1 file changed

Lines changed: 199 additions & 0 deletions

File tree

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
//
2+
// Copyright (C) 2025, 2026 David Cattermole.
3+
//
4+
// This file is part of mmSolver.
5+
//
6+
// mmSolver is free software: you can redistribute it and/or modify it
7+
// under the terms of the GNU Lesser General Public License as
8+
// published by the Free Software Foundation, either version 3 of the
9+
// License, or (at your option) any later version.
10+
//
11+
// mmSolver is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU Lesser General Public License for more details.
15+
//
16+
// You should have received a copy of the GNU Lesser General Public License
17+
// along with mmSolver. If not, see <https://www.gnu.org/licenses/>.
18+
// ====================================================================
19+
//
20+
21+
//! Integration test for complete camera solve using Soccer Cones datasets.
22+
23+
#![allow(unused)]
24+
#![allow(unused_imports)]
25+
#![allow(dead_code)]
26+
#![allow(non_snake_case)]
27+
28+
mod common;
29+
30+
use anyhow::Result;
31+
use mmsfm_rust::datatype::{
32+
CameraFilmBack, ImageSize, MillimeterUnit, UnitValue,
33+
};
34+
use mmsfm_rust::sfm_camera::{
35+
BundleAdjustmentSolverType, CameraSolveConfig, GlobalAdjustmentConfig,
36+
};
37+
38+
use crate::common::bundle_adjustment_solver_type_to_naming;
39+
use crate::common::data_utils::load_marker_data;
40+
use crate::common::marker_noise::add_noise_to_markers;
41+
use crate::common::visualization::scene::ViewConfigurationBuilder;
42+
use crate::common::NamingSolverType;
43+
use crate::common::{
44+
test_output_file_naming, DataCondition, OutputFileNaming, TestType,
45+
VisualizationType,
46+
};
47+
48+
/// Camera parameters shared by both v1 and v2 soccer cones datasets.
49+
///
50+
/// The UV files embed camera metadata (24mm focal, 35x19.6875mm film back)
51+
/// but the solver is run with approximate 35mm / 36x20.25mm values for
52+
/// investigation purposes.
53+
fn soccer_cones_camera_params(
54+
) -> (MillimeterUnit<f64>, CameraFilmBack<f64>, ImageSize<f64>) {
55+
let focal_length = MillimeterUnit::new(35.0);
56+
let film_back = CameraFilmBack::new(
57+
MillimeterUnit::new(36.0),
58+
MillimeterUnit::new(20.25), // 16:9 aspect ratio.
59+
);
60+
let image_size = ImageSize::from_pixels(3840.0, 2160.0);
61+
(focal_length, film_back, image_size)
62+
}
63+
64+
fn run_camera_solve_soccer_cones(
65+
uv_filename: &str,
66+
dataset_label: &str,
67+
test_prefix: &str,
68+
is_noisy: bool,
69+
) -> Result<()> {
70+
let (mut markers, frame_range) = load_marker_data(uv_filename)?;
71+
72+
let solver_type = BundleAdjustmentSolverType::SparseLevenbergMarquardt;
73+
let naming_solver_type =
74+
bundle_adjustment_solver_type_to_naming(&solver_type);
75+
let solver_suffix = naming_solver_type.as_str();
76+
77+
let (dataset_name, condition) = if is_noisy {
78+
add_noise_to_markers(&mut markers, 0.005);
79+
(
80+
format!("{} (noisy, {})", dataset_label, solver_suffix),
81+
DataCondition::Noisy,
82+
)
83+
} else {
84+
(
85+
format!("{} (clean, {})", dataset_label, solver_suffix),
86+
DataCondition::Clean,
87+
)
88+
};
89+
90+
// Create output naming for visualizations.
91+
let naming = test_output_file_naming(
92+
TestType::CameraSolve,
93+
test_prefix,
94+
VisualizationType::Scene3d,
95+
)
96+
.with_condition(condition)
97+
.with_solver(naming_solver_type);
98+
99+
let (focal_length, film_back, image_size) = soccer_cones_camera_params();
100+
101+
// Random seed for reproducibility.
102+
let seed = 42;
103+
104+
// Configure global focal length optimization using DE.
105+
// The embedded focal length is 24mm; we search around 35mm ± 5mm.
106+
let generation_count = 10;
107+
let global_config = GlobalAdjustmentConfig::small_refinement(
108+
(30.0, 40.0),
109+
generation_count,
110+
seed,
111+
);
112+
113+
// Configure solver.
114+
let config = CameraSolveConfig {
115+
origin_frame: 1,
116+
bundle_solver_type: solver_type,
117+
..Default::default()
118+
};
119+
120+
// Define visualization views.
121+
let views = vec![
122+
ViewConfigurationBuilder::new()
123+
.view_name("top")
124+
.rotation_ortho_top()
125+
.resolution_hd()
126+
.build(),
127+
ViewConfigurationBuilder::new()
128+
.view_name("right")
129+
.rotation_ortho_right()
130+
.resolution_hd()
131+
.build(),
132+
];
133+
134+
let step_by = 1;
135+
common::run_camera_solve_dataset_test(
136+
&markers,
137+
frame_range,
138+
&dataset_name,
139+
&naming,
140+
views,
141+
focal_length,
142+
film_back,
143+
image_size,
144+
config,
145+
None,
146+
// Some(&global_config), // Uncomment to optimize focal length.
147+
step_by,
148+
)
149+
}
150+
151+
// ---------------------------------------------------------------------------
152+
// Soccer Cones v1 (71 markers, 231 frames)
153+
// ---------------------------------------------------------------------------
154+
155+
#[test]
156+
fn test_camera_solve_clean_soccer_cones_v1_sparse_lm() -> Result<()> {
157+
run_camera_solve_soccer_cones(
158+
"tracking_soccer_cones_v1.uv",
159+
"Soccer Cones v1",
160+
"soccer_cones_v1",
161+
false,
162+
)
163+
}
164+
165+
#[test]
166+
#[ignore]
167+
fn test_camera_solve_noisy_soccer_cones_v1_sparse_lm() -> Result<()> {
168+
run_camera_solve_soccer_cones(
169+
"tracking_soccer_cones_v1.uv",
170+
"Soccer Cones v1",
171+
"soccer_cones_v1",
172+
true,
173+
)
174+
}
175+
176+
// ---------------------------------------------------------------------------
177+
// Soccer Cones v2 (62 markers, 231 frames)
178+
// ---------------------------------------------------------------------------
179+
180+
#[test]
181+
fn test_camera_solve_clean_soccer_cones_v2_sparse_lm() -> Result<()> {
182+
run_camera_solve_soccer_cones(
183+
"tracking_soccer_cones_v2.uv",
184+
"Soccer Cones v2",
185+
"soccer_cones_v2",
186+
false,
187+
)
188+
}
189+
190+
#[test]
191+
#[ignore]
192+
fn test_camera_solve_noisy_soccer_cones_v2_sparse_lm() -> Result<()> {
193+
run_camera_solve_soccer_cones(
194+
"tracking_soccer_cones_v2.uv",
195+
"Soccer Cones v2",
196+
"soccer_cones_v2",
197+
true,
198+
)
199+
}

0 commit comments

Comments
 (0)