Detect chessboard

import multicam_calibration as mcc
board_shape = (5,7)
square_size = 12.5

camera_names = ['top', 'side1', 'side2', 'side3', 'side4', 'bottom']
prefix = '../../tests/example_data/example_calibration'
video_paths = [f'{prefix}.{camera}.mp4' for camera in camera_names]

# detect calibration object in each video
all_calib_uvs, all_img_sizes = mcc.run_calibration_detection(
    video_paths, mcc.detect_chessboard, n_workers=6,
    detection_options=dict(board_shape=board_shape, scale_factor=0.5))

# display a table with the detections shared between camera pairs
mcc.summarize_detections(all_calib_uvs)

# plot corner-match scores for each frame
fig = mcc.plot_chessboard_qc_data(video_paths)

# optionally generate overlay videos
# for p in video_paths:
#     mcc.overlay_detections(p)
_images/78ad7412672a77880965f3ddbff481de1e49a9aeb399e7039c8c73ae8ecc62a4.png

Calibrate

Initialization

calib_objpoints = mcc.generate_chessboard_objpoints(board_shape, square_size)

all_extrinsics, all_intrinsics, calib_poses, spanning_tree = mcc.calibrate(
    all_calib_uvs, all_img_sizes, calib_objpoints, root=0, n_samples_for_intrinsics=100)
Estimating camera intrinsics
100%|█████████████████████████████████████| 6/6 [01:00<00:00, 10.12s/it]
Initializing calibration object poses
100%|█████████████████████████████████████| 6/6 [00:02<00:00,  2.21it/s]
Estimating camera extrinsics
Merging calibration object poses

fig, shared_detections = plot_shared_detections(all_calib_uvs, spanning_tree)
_images/ae5a67a6fecb3a608b259112c6cbc5cc82b5a3b92adfe67e800f09fc0ee2781f.png
fig, median_error, reprojections, transformed_reprojections = mcc.plot_residuals(
    all_calib_uvs, all_extrinsics, all_intrinsics, calib_objpoints, calib_poses, inches_per_axis=3)
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:01<00:00,  4.58it/s]
_images/b09a59a25b81136b4674b384b5aee867b5f963e07ee6ec44f7712acce0f5ed64.png

Bundle adjustment

adj_extrinsics, adj_intrinsics, adj_calib_poses, use_frames, result = \
    mcc.bundle_adjust(all_calib_uvs, all_extrinsics, all_intrinsics, calib_objpoints, calib_poses, n_frames=5000, ftol=1e-4)
Excluding 199 out of 2130 frames based on an outlier threshold of 3.428785613103967
   Iteration     Total nfev        Cost      Cost reduction    Step norm     Optimality   
       0              1         9.7568e+04                                    7.50e+06    
       1              3         7.8176e+04      1.94e+04       1.02e+02       1.01e+07    
       2              6         4.3648e+04      3.45e+04       1.62e+01       3.31e+06    
       3              7         4.1601e+04      2.05e+03       3.18e+01       4.44e+05    
       4              8         3.7025e+04      4.58e+03       9.18e+00       2.13e+05    
       5              9         3.6771e+04      2.54e+02       1.93e+01       2.27e+05    
       6             10         3.5528e+04      1.24e+03       5.45e+00       1.82e+05    
       7             12         3.5078e+04      4.50e+02       2.40e+00       1.75e+05    
       8             14         3.4917e+04      1.61e+02       8.61e-01       1.77e+05    
       9             15         3.4797e+04      1.19e+02       7.64e-01       1.74e+05    
      10             16         3.4665e+04      1.32e+02       9.95e-01       1.48e+05    
      11             17         3.4490e+04      1.75e+02       1.01e+00       1.29e+05    
      12             18         3.4263e+04      2.26e+02       1.66e+00       1.20e+05    
      13             19         3.4076e+04      1.88e+02       2.17e+00       1.15e+05    
      14             20         3.3939e+04      1.37e+02       3.31e+00       9.48e+04    
      15             21         3.3794e+04      1.44e+02       8.53e+00       8.92e+04    
      16             22         3.3596e+04      1.98e+02       1.86e+01       7.80e+04    
      17             23         3.3379e+04      2.16e+02       3.89e+01       2.42e+05    
      18             24         3.3304e+04      7.53e+01       2.63e+01       1.03e+05    
      19             25         3.3287e+04      1.73e+01       1.82e+01       2.67e+04    
      20             26         3.3282e+04      4.65e+00       4.63e+00       4.55e+03    
      21             27         3.3280e+04      2.30e+00       4.29e+00       4.04e+03    
`ftol` termination condition is satisfied.
Function evaluations 27, initial cost 9.7568e+04, final cost 3.3280e+04, first-order optimality 4.04e+03.
fig, median_error, reprojections, transformed_reprojections = mcc.plot_residuals(
    all_calib_uvs[:,use_frames], adj_extrinsics, adj_intrinsics, calib_objpoints, adj_calib_poses, inches_per_axis=3)
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:01<00:00,  5.19it/s]
_images/dae3eed05172769c7f9609cfeaee19f244d0dadda009b054c68593d81d9cac3f.png

Save results

# save for JARVIS
save_path = f'{video_dir}/CalibrationParameters/'
mcc.save_calibration(all_extrinsics, all_intrinsics, camera_names, save_path, save_format='jarvis')

# save for GIMBAL
save_path = f'{video_dir}/camera_params.h5'
mcc.save_calibration(all_extrinsics, all_intrinsics, camera_names, save_path, save_format='gimbal')