Store calibration board measurements in native units (#2480)

This commit is contained in:
Alan Everett
2026-06-22 23:31:44 -06:00
committed by GitHub
parent bd9f899514
commit e41be8e858
7 changed files with 50 additions and 66 deletions

View File

@@ -21,6 +21,7 @@
"type-check": "vue-tsc --noEmit"
},
"dependencies": {
"@adam-rocska/units-and-measurement": "^1.2.0",
"@fontsource/prompt": "^5.2.6",
"@mdi/font": "^7.4.47",
"@msgpack/msgpack": "^3.1.2",

View File

@@ -8,6 +8,9 @@ importers:
.:
dependencies:
'@adam-rocska/units-and-measurement':
specifier: ^1.2.0
version: 1.2.0
'@fontsource/prompt':
specifier: ^5.2.6
version: 5.2.6
@@ -96,6 +99,10 @@ importers:
packages:
'@adam-rocska/units-and-measurement@1.2.0':
resolution: {integrity: sha512-mBnZ8/STbztVec+Mz9DH932z0gny52SebtSJ/y3n+IVtuF7KqbtQ3t1u1lpFSkLFU1msaNGzFgqsW7Emj0lrXA==}
engines: {node: '>=20.0.0'}
'@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
@@ -250,42 +257,36 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -353,42 +354,36 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.17':
resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17':
resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17':
resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.17':
resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rolldown/binding-linux-x64-musl@1.0.0-rc.17':
resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@rolldown/binding-openharmony-arm64@1.0.0-rc.17':
resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==}
@@ -1084,28 +1079,24 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.32.0:
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
@@ -1550,6 +1541,8 @@ packages:
snapshots:
'@adam-rocska/units-and-measurement@1.2.0': {}
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.27.1': {}

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, ref, watchEffect } from "vue";
import { computed, ref, watch, watchEffect } from "vue";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { CalibrationBoardTypes, CalibrationTagFamilies, type VideoFormat } from "@/types/SettingTypes";
import MonoLogo from "@/assets/images/logoMono.png";
@@ -15,12 +15,12 @@ import CameraCalibrationInfoCard from "@/components/cameras/CameraCalibrationInf
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
import { useTheme } from "vuetify";
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
import { length } from "@adam-rocska/units-and-measurement/length";
const PromptRegular = import("@/assets/fonts/PromptRegular");
const jspdf = import("jspdf");
const theme = useTheme();
const MM_PER_INCH = 25.4;
const settingsValid = ref(true);
@@ -110,8 +110,8 @@ watchEffect(() => {
uniqueVideoResolutionIndex.value = currentIndex;
});
const dimensionUnit = ref<"in" | "mm">("in");
const squareSizeIn = ref(1);
const markerSizeIn = ref(0.75);
const squareSize = ref(30);
const markerSize = ref(22);
const patternWidth = ref(8);
const patternHeight = ref(8);
const boardType = ref<CalibrationBoardTypes>(CalibrationBoardTypes.Charuco);
@@ -119,24 +119,9 @@ const useOldPattern = ref(false);
const tagFamily = ref<CalibrationTagFamilies>(CalibrationTagFamilies.Dict_4X4_1000);
const requestedVideoFormatIndex = ref(0);
const convertInchesToDisplay = (valueInInches: number) =>
dimensionUnit.value === "mm" ? valueInInches * MM_PER_INCH : valueInInches;
const convertDisplayToInches = (displayValue: number) =>
dimensionUnit.value === "mm" ? displayValue / MM_PER_INCH : displayValue;
const squareSize = computed({
get: () => convertInchesToDisplay(squareSizeIn.value),
set(value) {
squareSizeIn.value = convertDisplayToInches(value);
}
});
const markerSize = computed({
get: () => convertInchesToDisplay(markerSizeIn.value),
set(value) {
markerSizeIn.value = convertDisplayToInches(value);
}
watch(dimensionUnit, (value, oldValue) => {
squareSize.value = length[oldValue](squareSize.value)[value].value;
markerSize.value = length[oldValue](markerSize.value)[value].value;
});
const dimensionStep = computed(() => (dimensionUnit.value === "mm" ? 0.1 : 0.01));
@@ -161,25 +146,31 @@ const downloadCalibBoard = async () => {
switch (boardType.value) {
case CalibrationBoardTypes.Chessboard:
const chessboardStartX = (paperWidth - patternWidth.value * squareSizeIn.value) / 2;
const squareSizeIn = length[dimensionUnit.value](squareSize.value).in.value;
const chessboardStartX = (paperWidth - patternWidth.value * squareSizeIn) / 2;
const chessboardStartY = (paperHeight - patternWidth.value * squareSizeIn.value) / 2;
const chessboardStartY = (paperHeight - patternHeight.value * squareSizeIn) / 2;
for (let squareY = 0; squareY < patternHeight.value; squareY++) {
for (let squareX = 0; squareX < patternWidth.value; squareX++) {
const xPos = chessboardStartX + squareX * squareSizeIn.value;
const yPos = chessboardStartY + squareY * squareSizeIn.value;
const xPos = chessboardStartX + squareX * squareSizeIn;
const yPos = chessboardStartY + squareY * squareSizeIn;
// Only draw the odd squares to create the chessboard pattern
if (squareY % 2 !== squareX % 2) {
doc.rect(xPos, yPos, squareSizeIn.value, squareSizeIn.value, "F");
doc.rect(xPos, yPos, squareSizeIn, squareSizeIn, "F");
}
}
}
doc.text(`${patternWidth.value} x ${patternHeight.value} | ${squareSizeIn.value}in`, paperWidth - 1, 1.0, {
maxWidth: (paperWidth - 2.0) / 2,
align: "right"
});
doc.text(
`${patternWidth.value} x ${patternHeight.value} | ${squareSize.value}${dimensionUnit.value}`,
paperWidth - 1,
1.0,
{
maxWidth: (paperWidth - 2.0) / 2,
align: "right"
}
);
break;
case CalibrationBoardTypes.Charuco:
@@ -220,8 +211,8 @@ const isCalibrating = computed(
const startCalibration = () => {
useCameraSettingsStore().startPnPCalibration({
squareSizeIn: squareSizeIn.value,
markerSizeIn: markerSizeIn.value,
squareSizeMeters: length[dimensionUnit.value](squareSize.value).m.value,
markerSizeMeters: length[dimensionUnit.value](markerSize.value).m.value,
patternHeight: patternHeight.value,
patternWidth: patternWidth.value,
boardType: boardType.value,

View File

@@ -368,8 +368,8 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*/
startPnPCalibration(
calibrationInitData: {
squareSizeIn: number;
markerSizeIn: number;
squareSizeMeters: number;
markerSizeMeters: number;
patternWidth: number;
patternHeight: number;
boardType: CalibrationBoardTypes;

View File

@@ -87,8 +87,8 @@ export interface WebsocketCalibrationData {
minCount: number;
videoModeIndex: number;
patternHeight: number;
squareSizeIn: number;
markerSizeIn: number;
squareSizeMm: number;
markerSizeMm: number;
}
export interface IncomingWebsocketData {

View File

@@ -24,11 +24,11 @@ import org.opencv.objdetect.Objdetect;
public class UICalibrationData {
public int videoModeIndex;
public int count;
public double squareSizeIn;
public double squareSizeMeters;
public int patternWidth;
public int patternHeight;
public BoardType boardType;
public double markerSizeIn;
public double markerSizeMeters;
public boolean useOldPattern;
public TagFamily tagFamily;
@@ -37,8 +37,8 @@ public class UICalibrationData {
public UICalibrationData(
int count,
int videoModeIndex,
double squareSizeIn,
double markerSizeIn,
double squareSizeMeters,
double markerSizeMeters,
int patternWidth,
int patternHeight,
BoardType boardType,
@@ -46,8 +46,8 @@ public class UICalibrationData {
TagFamily tagFamily) {
this.count = count;
this.videoModeIndex = videoModeIndex;
this.squareSizeIn = squareSizeIn;
this.markerSizeIn = markerSizeIn;
this.squareSizeMeters = squareSizeMeters;
this.markerSizeMeters = markerSizeMeters;
this.patternWidth = patternWidth;
this.patternHeight = patternHeight;
this.boardType = boardType;
@@ -98,10 +98,10 @@ public class UICalibrationData {
+ videoModeIndex
+ ", count="
+ count
+ ", squareSizeIn="
+ squareSizeIn
+ ", markerSizeIn="
+ markerSizeIn
+ ", squareSizeMeters="
+ squareSizeMeters
+ ", markerSizeMeters="
+ markerSizeMeters
+ ", patternWidth="
+ patternWidth
+ ", patternHeight="

View File

@@ -55,7 +55,6 @@ import org.photonvision.vision.pipeline.UICalibrationData;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TargetModel;
import org.photonvision.vision.target.TrackedTarget;
import org.wpilib.math.util.Units;
import org.wpilib.vision.camera.CameraServerJNI;
import org.wpilib.vision.camera.VideoException;
@@ -391,8 +390,8 @@ public class VisionModule {
+ data.videoModeIndex
+ " and settings "
+ data);
settings.gridSize = Units.inchesToMeters(data.squareSizeIn);
settings.markerSize = Units.inchesToMeters(data.markerSizeIn);
settings.gridSize = data.squareSizeMeters;
settings.markerSize = data.markerSizeMeters;
settings.boardHeight = data.patternHeight;
settings.boardWidth = data.patternWidth;
settings.boardType = data.boardType;