Computes a 4x4 floor grounding transformation matrix from checkerboard images. This transform converts camera rig coordinates to absolute world coordinates where the floor is at Y=0.
The pipeline:
- Convert images - Converts
.8ij(12-bit) or other formats to JPEG - Detect checkerboards - Finds corner points in each image using OpenCV
- Compute transform - Uses solvePnP to estimate camera heights and fits a floor plane
- Docker (recommended), or
- Python 3.11+ with OpenCV, NumPy, Pillow, imagecodecs
# Build the container
docker build -t floorfinder:latest .
# Run with your data
docker run --rm \
-v /path/to/images:/data/input:ro \
-v /path/to/calibration:/data/calibration:ro \
-v /path/to/output:/data/output \
floorfinder:latestThe input directory should contain either:
- Images:
.8ij,.jpg,.jpeg, or.pngfiles of a checkerboard on the floor - Pre-computed grids: JSON files with detected corner points (skips steps 1 & 2)
Images can be organized in subdirectories - the tool searches recursively.
Directory containing 8i-format calibration JSONs named camera_{serial}.json:
{
"camera": {
"rotate": "{rx ry rz}",
"translate": "{x y z}",
"focal": "8.5",
"haperture": "14.18",
"vaperture": "10.38",
"win_translate": "{0.0 0.0}",
...
}
}The camera serial is extracted from image filenames. For example:
- Image:
01202026_C01C_T03_Cam2_R01_cam_94483996.jpg - Calibration:
camera_94483996.json
| Argument | Short | Default | Description |
|---|---|---|---|
--input |
-i |
/data/input |
Input directory (images or grid JSONs) |
--calibration |
-c |
/data/calibration |
Camera calibration directory |
--output |
-o |
/data/output/floor_transform.json |
Output JSON file path |
--pattern |
-p |
8x6 |
Checkerboard inner corners (columns x rows) |
--square-size |
-s |
10.0 |
Checkerboard square size in cm |
--platform-height |
50.0 |
Height of checkerboard platform above floor (cm) | |
--format |
-f |
8i |
Output format: 8i (mat string only) or full |
--keep-intermediate |
false | Keep converted images and grid JSONs |
{
"mat": "{1.0e+00 0.0e+00 0.0e+00 0.0e+00 0.0e+00 0.0e+00 -1.0e+00 0.0e+00 0.0e+00 1.0e+00 0.0e+00 0.0e+00 0.0e+00 4.226e+01 0.0e+00 1.0e+00}"
}{
"summary": {
"total_processed": 23,
"height_stats": { "min": 48.0, "max": 213.3, "mean": 145.0 },
"checkerboard_level": { "z_mean_cm": 7.7, "z_std_cm": 14.4 },
"floor_estimate": { "floor_z_rig_cm": -42.3 }
},
"floor_transform": {
"matrix_4x4": [[1,0,0,0], [0,0,-1,0], [0,1,0,0], [0,42.26,0,1]],
"mat_8i_format": "{...}",
"y_translation_cm": 42.26
},
"results": [ ... per-camera details ... ]
}docker run --rm \
-v ./images:/data/input:ro \
-v ./calibration:/data/calibration:ro \
-v ./output:/data/output \
floorfinder:latestdocker run --rm \
-v ./images:/data/input:ro \
-v ./calibration:/data/calibration:ro \
-v ./output:/data/output \
floorfinder:latest \
--pattern 7x5 \
--square-size 5.0docker run --rm \
-v ./images:/data/input:ro \
-v ./calibration:/data/calibration:ro \
-v ./output:/data/output \
floorfinder:latest \
--format full \
--platform-height 75.0./run.sh ./images ./calibration ./output/transform.json --pattern 8x6pip install -r requirements.txt
python entrypoint.py \
--input ./images \
--calibration ./calibration \
--output ./transform.json- Rig coordinates: Z-up (camera positions from calibration
translatefield) - World coordinates: Y-up (after transform, floor at Y=0)
The 4x4 matrix transforms rig → world:
- Rotation: Swaps Z↔Y axes
- Translation: Shifts so floor is at Y=0
If providing pre-computed grids, each JSON should contain:
{
"corners": [[x1,y1], [x2,y2], ...],
"pattern_size": [8, 6],
"image_size": [4112, 3008],
"source_image": "path/to/image.jpg"
}- Verify the pattern size matches your checkerboard (count inner corners, not squares)
- Ensure adequate lighting and image quality
- Try
--patternwith different values
- Check that calibration files are named
camera_{serial}.json - Verify the serial in the image filename matches
- Ensure the checkerboard is flat on a level surface
- Check that all cameras have correct calibration data
- Verify the
--square-sizematches the actual checkerboard
Internal use.