Hi Dima, thank you for writing and sharing this software with the open source community.
I have a question regarding using the python tools to calibrate a pair of thermal infrared cameras using an anchored (non-checkerboard) grid pattern with a moving rig holding two thermal cameras at a fixed separation of about 1 meter.
The calibration target is an array of stick-on resistive electric hotpads against a wooden board; e.g. visual camera appearance like this:

and thermal pair images like this:


I have a "dot detector" that can output vnl-format text files of the dot pattern centers, starting from top right dot, and
providing the x,y coordinates for the centers in order of top-to-bottom, right-to-left. An example file (not specifically from the above images) gives the center points as:
## generated with make_vnlfiles.py
# filename x y level
stereo_cam2_00007.png 704.3236 467.94455 0
stereo_cam2_00007.png 695.18475 533.9793 0
stereo_cam2_00007.png 686.5277 600.4337 0
stereo_cam2_00007.png 678.0138 667.6202 0
stereo_cam2_00007.png 667.8977 496.71448 0
stereo_cam2_00007.png 657.7925 563.66754 0
stereo_cam2_00007.png 649.7433 630.1107 0
stereo_cam2_00007.png 641.88007 696.6739 0
stereo_cam2_00007.png 637.7005 458.31003 0
stereo_cam2_00007.png 627.91504 524.61676 0
stereo_cam2_00007.png 619.01154 591.028 0
stereo_cam2_00007.png 610.5706 658.3819 0
stereo_cam2_00007.png 601.77106 486.57288 0
stereo_cam2_00007.png 591.06506 553.82135 0
stereo_cam2_00007.png 583.2952 620.97815 0
stereo_cam2_00007.png 574.2796 688.2082 0
stereo_cam2_00007.png 569.1609 448.06207 0
stereo_cam2_00007.png 559.0736 514.76953 0
stereo_cam2_00007.png 551.06335 582.1288 0
stereo_cam2_00007.png 542.4579 649.3663 0
stereo_cam2_00007.png 533.81104 476.6088 0
stereo_cam2_00007.png 524.1529 544.13086 0
stereo_cam2_00007.png 514.11597 611.4478 0
stereo_cam2_00007.png 505.4032 678.06744 0
stereo_cam2_00007.png 500.84088 438.70718 0
stereo_cam2_00007.png 491.37918 505.05344 0
stereo_cam2_00007.png 482.02417 572.33105 0
stereo_cam2_00007.png 473.0924 639.07385 0
stereo_cam2_00007.png 465.06732 466.6333 0
stereo_cam2_00007.png 455.16403 534.18567 0
stereo_cam2_00007.png 445.67804 601.48804 0
stereo_cam2_00007.png 437.5754 668.36255 0
stereo_cam2_00007.png 432.20752 427.99762 0
stereo_cam2_00007.png 422.10034 495.39325 0
stereo_cam2_00007.png 411.8926 562.6122 0
stereo_cam2_00007.png 403.84375 630.01996 0
There are some imprecisions in how the dot array is physically laid out, but I have a reasonable model of the real-world dot positions as a combination of an algorithmic generation plus a table of offsets:
from target_corrections import corrections_california as corrections
boardSize = (4,9) # 4 (staggered) rows of 9 columns per staggered row#35
# example of one staggered row of 9 columns
# * * * * *
# * * * *
frameSize = (1280, 1024) # sensor is 1280 wide x1024 tall
# assuming sensor pixel is 11 micrometers square (0.001 cm per pixel)
# and estimated focal length is 25mm (2.50 cm), then focal length in pixels
# will be 2.5/0.001 pixels
est_focal_length = 2.5 / 0.001
est_cx = frameSize[0] / 2
est_cy = frameSize[1] / 2
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0).
objp = np.zeros((boardSize[0] * boardSize[1], 3), np.float32)
# assuming:
# units in centimeters
# target is ~10 meters away
#
# |----9.5" ----|
# * * * * * --
# |
# * * * * 9.5"
# |
# * * * * * --
#
# * * * *
# with board upright, targets are spaced 9.5" apart vertically and horizontally, so
# vertical/horizontal center-to-center distance is 24.13 cm apart
# and diagonal center-to-center distance is 17.062 cm apart
# indexing the pattern starts at top right, and goes top to bottom, then shifts
# 1 column left and repeats top-to-bottom, until all 9 columns are completed.
#initialize objp starting from top left, and going top-to-bottom, left-to-right
step_size = 24.13 # center-to-center distance in cm
half_step_size = step_size / 2.0
# the openCV findCircleGrid returns sequence ordered as top->bottom, right-to-left !!!
# and openCV's calibrateCamera expects that.
# *** objp units are in cm ***
target_world_X = 0
target_world_Y = 0
target_world_Z = 0
index = 0
if apply_known_offsets:
for x in range(boardSize[1], 0, -1):
for y in range(boardSize[0]):
target_world_X = (x * half_step_size) + half_step_size + (corrections[index][0])
target_world_Y = ((y * step_size) + (((x + 1) % 2) * half_step_size)) + (corrections[index][1])
objp[index] = (target_world_X, target_world_Y, target_world_Z)
index += 1
else:
for x in range(boardSize[1], 0, -1):
for y in range(boardSize[0]):
target_world_X = (x * half_step_size) + half_step_size
target_world_Y = ((y * step_size) + (((x+1)%2) * half_step_size))
objp[index] = (target_world_X, target_world_Y, target_world_Z)
index += 1
The final result is a list of X,Y,Z coordinates for the centers (where Z=0, and X,Y are horizontal and vertical distances in centimeters from top left corner of the board holding the thermal pads.
Where I'm having difficulty is how to pass this list of object-space centers to the test-surveyed-calibration.py example. Is there a simple way to give it the objp structure as a list of points (possibly as a vml file), or do I need to separate the points into two distinct 5 wide x 4 tall and 4 wide x 4 tall overlapped rectangular grid pairs and just process one of those grids?
Thank you,
-Tom
Hi Dima, thank you for writing and sharing this software with the open source community.
I have a question regarding using the python tools to calibrate a pair of thermal infrared cameras using an anchored (non-checkerboard) grid pattern with a moving rig holding two thermal cameras at a fixed separation of about 1 meter.
The calibration target is an array of stick-on resistive electric hotpads against a wooden board; e.g. visual camera appearance like this:
and thermal pair images like this:
I have a "dot detector" that can output vnl-format text files of the dot pattern centers, starting from top right dot, and
providing the x,y coordinates for the centers in order of top-to-bottom, right-to-left. An example file (not specifically from the above images) gives the center points as:
There are some imprecisions in how the dot array is physically laid out, but I have a reasonable model of the real-world dot positions as a combination of an algorithmic generation plus a table of offsets:
The final result is a list of X,Y,Z coordinates for the centers (where Z=0, and X,Y are horizontal and vertical distances in centimeters from top left corner of the board holding the thermal pads.
Where I'm having difficulty is how to pass this list of object-space centers to the test-surveyed-calibration.py example. Is there a simple way to give it the objp structure as a list of points (possibly as a vml file), or do I need to separate the points into two distinct 5 wide x 4 tall and 4 wide x 4 tall overlapped rectangular grid pairs and just process one of those grids?
Thank you,
-Tom