Skip to content

Commit

Permalink
added in calibrations folder with necessary scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
PGgit08 committed Dec 24, 2024
1 parent 67cbc2d commit 5adf992
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 2 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ A base project for future robots that has CTRE generated swerve drive code and P
- After that, since this project is a template on github, the actual 2025 robot code repo can be generated from this template:
![github templates](https://docs.github.com/assets/cb-76823/mw-1440/images/help/repository/use-this-template-button.webp)

# Calibration Process
- Run `calibration/calibrator.zsh` in zshell in WSL (make sure all packages are installed).
- Analyze calibration as according to the mrcal tour.
- Convert the `.cameramodel` calibration data format into `.json` using `calibration/mrcal_to_photon.py` in WSL.

## 2025 Latest Beta Known Issues
- To run sim, do `./gradlew simulateJava` instead of using the WPILib extension (for Epilogue to work).
46 changes: 46 additions & 0 deletions calibration/calibrator.zsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# NOT DONE HERE YET

# names
echo -n "Enter camera name: "
read -r name

# echo -n "Enter input video file name: "
# read -r input

# echo -n "Enter desired ffmpeg fps: "
# read -r fps

# # frame dir
# mkdir frames1

# fill up frame directory with png frames
# ffmpeg

# generate corners.vnl
# mrgingham

# ---- CALIBRATE ----
evens='frames/*[02468].png'
odds='frames/*[13579].png'
all='frames/*.png'

mrcal_calibrate=(mrcal-calibrate-cameras \
--corners-cache corners.vnl \
--lensmodel LENSMODEL_SPLINED_STEREOGRAPHIC_order=3_Nx=16_Ny=9_fov_x_deg=70 \
--focal 1015 \
--object-spacing 0.012 \
--object-width-n 14 \
)

# cross diffs
$mrcal_calibrate $evens
mv camera-0.cameramodel $name-evens.cameramodel

$mrcal_calibrate $odds
mv camera-0.cameramodel $name-odds.cameramodel

# main calibration
$mrcal_calibrate $all
mv camera-0.cameramodel $name.cameramodel

# ---- DONE! ----
111 changes: 111 additions & 0 deletions calibration/mrcal_to_photon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import argparse
import base64
import json
import os
import cv2
import numpy as np
import mrcal # type: ignore (this exists when running in wsl)
from dataclasses import dataclass, asdict

# Assuming similar dataclass structures for simplicity and compatibility
@dataclass
class Size:
width: int
height: int

@dataclass
class JsonMatOfDoubles:
rows: int
cols: int
type: int # Assuming type follows OpenCV conventions, 6 for CV_64F
data: list[float]

@dataclass
class JsonMat:
rows: int
cols: int
type: int # Assuming type follows OpenCV conventions
data: str # Base64-encoded image data

@dataclass
class CameraCalibration:
resolution: Size
cameraIntrinsics: JsonMatOfDoubles
distCoeffs: JsonMatOfDoubles
observations: list # This would need to be fleshed out based on actual use
calobjectWarp: list[float]
calobjectSize: Size
calobjectSpacing: float

def __convert_mrcal_to_photon_cameramodel(cameramodel_path: str) -> CameraCalibration:
model = mrcal.cameramodel(cameramodel_path)

# Extracting necessary data from mrcal model
intrinsics = model.intrinsics()
lensmodel, intrinsics_data = intrinsics
dist_coeffs = intrinsics_data[4:] # Assuming the first four are the core intrinsics
resolution = model.imagersize()

# Placeholder for generating/synthesizing observation data
observations = []

# Constructing the CameraCalibration object
camera_calibration = CameraCalibration(
resolution=Size(width=resolution[0], height=resolution[1]),
cameraIntrinsics=JsonMatOfDoubles(rows=1, cols=4, type=6, data=intrinsics_data[:4]),
distCoeffs=JsonMatOfDoubles(rows=1, cols=len(dist_coeffs), type=6, data=dist_coeffs),
observations=observations,
calobjectWarp=[], # Placeholder, as warp is not directly available from mrcal
calobjectSize=Size(width=0, height=0), # Placeholder
calobjectSpacing=0 # Placeholder
)

return camera_calibration

def __convert_mrcal_to_photon_cameramodel(cameramodel_path: str) -> CameraCalibration:
model = mrcal.cameramodel(cameramodel_path)

# Extracting necessary data from mrcal model
intrinsics = model.intrinsics()
lensmodel, intrinsics_data = intrinsics
dist_coeffs = intrinsics_data[4:].tolist() # Convert to list for JSON serialization
resolution = model.imagersize()

# Placeholder for generating/synthesizing observation data
observations = []

intrinsics_list = intrinsics_data[:4].tolist()
camera_intrinsics = [intrinsics_list[0], 0, intrinsics_list[2], 0, intrinsics_list[1], intrinsics_list[3], 0, 0, 1]

# Constructing the CameraCalibration object, ensuring all data is in a serializable form
camera_calibration = CameraCalibration(
resolution=Size(width=int(resolution[0]), height=int(resolution[1])), # Convert to int
cameraIntrinsics=JsonMatOfDoubles(rows=3, cols=3, type=6, data=camera_intrinsics),
distCoeffs=JsonMatOfDoubles(rows=1, cols=len(dist_coeffs), type=6, data=dist_coeffs),
observations=observations,
calobjectWarp=[], # Placeholder, as warp is not directly available from mrcal
calobjectSize=Size(width=0, height=0), # Placeholder
calobjectSpacing=0 # Placeholder
)

return camera_calibration


def convert_mrcal_to_photon(mrcal_model_path: str, output_json_path: str):
camera_cal_data = __convert_mrcal_to_photon_cameramodel(mrcal_model_path)

# Writing the calibration data to a JSON file
with open(output_json_path, "w") as outfile:
json.dump(asdict(camera_cal_data), outfile, indent=4)

def main():
parser = argparse.ArgumentParser(description="Convert mrcal cameramodel to PhotonVision calibration JSON")
parser.add_argument("input", type=str, help="Path to mrcal cameramodel file")
parser.add_argument("output", type=str, help="Output path for the PhotonVision calibration JSON")

args = parser.parse_args()

convert_mrcal_to_photon(args.input, args.output)

if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions src/main/java/frc/robot/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public Robot(NetworkTableInstance ntInst) {
_ntInst = ntInst;

// set up loggers
DogLog.getOptions().withCaptureDs(true);
DogLog.setOptions(DogLog.getOptions().withCaptureDs(true));

setFileOnly(false); // file-only once connected to fms

Expand All @@ -94,7 +94,7 @@ public Robot(NetworkTableInstance ntInst) {

// set logging to be file only or not
private void setFileOnly(boolean fileOnly) {
DogLog.getOptions().withNtPublish(!fileOnly);
DogLog.setOptions(DogLog.getOptions().withNtPublish(!fileOnly));

if (fileOnly) {
Epilogue.getConfig().backend = new FileBackend(DataLogManager.getLog());
Expand Down

0 comments on commit 5adf992

Please sign in to comment.