calibrate_fisheye¶
calibrate_fisheye
¶
Fisheye Camera Calibration¶
Calibrates the equidistant fisheye model (r = f * theta) used by mqtt_bridge.py. Standard OpenCV fisheye calibration uses Kannala-Brandt with polynomial distortion coefficients, which does not fit this 200-degree spherical lens on a 16:9 sensor.
This script uses a custom bundle adjustment that directly fits the equidistant projection model to checkerboard observations.
Parameters calibrated
cx, cy : optical center in the preprocessed frame (pixels) focal_length : equidistant projection focal length (pixels) k1, k2 : optional radial correction terms (r = f(theta + k1theta^3 + k2*theta^5))
Usage
From a set of images showing a checkerboard:¶
python calibrate_fisheye.py --images calibration_frames/*.jpg
From a video (extracts frames at an interval):¶
python calibrate_fisheye.py --video calibration.avi --interval 30
With a known board size and square dimensions:¶
python calibrate_fisheye.py --images *.jpg --board-width 9 --board-height 6 --square-size 0.025
Enable radial correction terms for higher accuracy:¶
python calibrate_fisheye.py --images *.jpg --fit-distortion
Interactive mode: step through a video and press 's' to select frames:¶
python calibrate_fisheye.py --video calibration.avi --interactive
preprocess_frame
¶
Pad to square and center-crop, matching the mqtt_bridge pipeline.
Source code in calibration\calibrate_fisheye.py
equidistant_project
¶
Project 3D points through the equidistant fisheye model.
Model
theta = angle between ray and optical axis r = f * (theta + k1theta^3 + k2theta^5) u = cx + r * cos(phi) v = cy + r * sin(phi)
Camera convention: x-right, y-down, z-forward (optical axis).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pts_3d
|
(N, 3) object-frame coordinates. |
required | |
rvec
|
(3,) Rodrigues rotation vector. |
required | |
tvec
|
(3,) translation vector. |
required | |
cx, cy
|
optical center (pixels). |
required | |
f
|
equidistant focal length (pixels). |
required | |
k1, k2
|
radial correction coefficients. |
required |
Returns:
| Type | Description |
|---|---|
|
(N, 2) pixel coordinates [u, v]. |
Source code in calibration\calibrate_fisheye.py
build_perspective_remap
¶
Build remap tables that convert a fisheye image to a perspective view.
findChessboardCorners requires straight lines between corners, which does not hold under fisheye distortion. Remapping to a perspective (rectilinear) view straightens those lines so detection works.
The remap is built from the approximate equidistant model — it does not need to be perfectly accurate, only good enough that the perspective image has approximately straight lines.
Returns:
| Type | Description |
|---|---|
|
dict with map_x, map_y (for cv2.remap), f_persp, persp_size. |
Source code in calibration\calibrate_fisheye.py
detect_checkerboard
¶
Detect checkerboard corners in a fisheye image.
Pipeline
- Remap fisheye → perspective (straightens curved lines)
- Detect checkerboard in the perspective image
- Map corners back to fisheye pixel coordinates
- Refine with cornerSubPix on the original fisheye image
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
image
|
Full-resolution fisheye image (BGR or grayscale). |
required | |
board_size
|
(cols, rows) inner corner count. |
required | |
remap
|
Dict from build_perspective_remap(). |
required |
Returns:
| Type | Description |
|---|---|
|
(found, corners) where corners is (N, 1, 2) in fisheye pixels. |
Source code in calibration\calibrate_fisheye.py
calibrate
¶
calibrate(obj_pts_list, img_pts_list, image_size, initial_cx=None, initial_cy=None, initial_f=None, fit_distortion=False)
Run full calibration via two-stage bundle adjustment.
Stage 1 — Levenberg-Marquardt with linear loss (fast convergence). Stage 2 — Trust-region with soft_l1 loss (outlier robustness).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj_pts_list
|
list of (N, 3) checkerboard 3D points per frame. |
required | |
img_pts_list
|
list of (N, 2) detected pixel coordinates per frame. |
required | |
image_size
|
(width, height) of preprocessed frame. |
required | |
initial_cx/cy
|
initial optical-center guess (default: frame center). |
required | |
initial_f
|
initial focal-length guess (default: from 200 deg FOV). |
None
|
|
fit_distortion
|
if True, also fit k1, k2 correction coefficients. |
False
|
Returns:
| Type | Description |
|---|---|
|
dict with calibrated parameters, per-frame errors, and diagnostics. |
Source code in calibration\calibrate_fisheye.py
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 | |
draw_reprojection
¶
Overlay detected (green) and reprojected (red) corners on an image.
Source code in calibration\calibrate_fisheye.py
draw_detection
¶
Draw detected checkerboard corners on an image.
load_frames_from_images
¶
Load frames from image file paths / glob patterns.
Source code in calibration\calibrate_fisheye.py
load_frames_from_video
¶
Extract frames from a video at a regular interval.
Source code in calibration\calibrate_fisheye.py
interactive_select_frames
¶
Step through a video and let the user press 's' to select frames.
Controls
s - save current frame for calibration d / -> - skip forward 10 frames a / <- - skip backward 10 frames space - advance 1 frame q / Esc - done selecting