Skip to content

Commit dad7f0a

Browse files
samfreundGold856
andauthored
Add support for removing calib coefficients (#2150)
## Description Adds the ability to remove old calibrations. This might be helpful if you have a bad calibration. closes #1262 ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Gold856 <[email protected]>
1 parent 6f2603f commit dad7f0a

File tree

6 files changed

+133
-8
lines changed

6 files changed

+133
-8
lines changed

photon-client/src/components/cameras/CameraCalibrationInfoCard.vue

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { CameraCalibrationResult, VideoFormat } from "@/types/SettingTypes"
33
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
44
import { useStateStore } from "@/stores/StateStore";
55
import { computed, inject, ref } from "vue";
6-
import { getResolutionString, parseJsonFile } from "@/lib/PhotonUtils";
6+
import { axiosPost, getResolutionString, parseJsonFile } from "@/lib/PhotonUtils";
77
import { useTheme } from "vuetify";
88
99
const theme = useTheme();
@@ -12,6 +12,18 @@ const props = defineProps<{
1212
videoFormat: VideoFormat;
1313
}>();
1414
15+
const confirmRemoveDialog = ref({ show: false, vf: {} as VideoFormat });
16+
17+
const removeCalibration = (vf: VideoFormat) => {
18+
axiosPost("/calibration/remove", "delete a camera calibration", {
19+
cameraUniqueName: useCameraSettingsStore().currentCameraSettings.uniqueName,
20+
width: vf.resolution.width,
21+
height: vf.resolution.height
22+
});
23+
24+
confirmRemoveDialog.value.show = false;
25+
};
26+
1527
const exportCalibration = ref();
1628
const openExportCalibrationPrompt = () => {
1729
exportCalibration.value.click();
@@ -93,18 +105,30 @@ const calibrationImageURL = (index: number) =>
93105
</script>
94106
<template>
95107
<v-card color="surface" dark>
96-
<div class="d-flex flex-wrap pt-2 pl-2 pr-2">
108+
<div class="d-flex flex-wrap pt-2 pl-2 pr-2 align-center">
97109
<v-col cols="12" md="6">
98110
<v-card-title class="pa-0"> Calibration Details </v-card-title>
99111
</v-col>
100-
<v-col cols="6" md="3" class="d-flex align-center pt-0 pt-md-3 pl-6 pl-md-3">
112+
<v-col cols="12" md="6" class="d-flex align-center pt-0 pt-md-3">
113+
<v-btn
114+
color="error"
115+
:disabled="!currentCalibrationCoeffs"
116+
class="mr-2"
117+
style="flex: 1"
118+
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
119+
@click="() => (confirmRemoveDialog = { show: true, vf: props.videoFormat })"
120+
>
121+
<v-icon start size="large">mdi-delete</v-icon>
122+
<span>Delete</span>
123+
</v-btn>
101124
<v-btn
102125
color="buttonPassive"
103-
style="width: 100%"
126+
class="mr-2"
127+
style="flex: 1"
104128
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
105129
@click="openUploadPhotonCalibJsonPrompt"
106130
>
107-
<v-icon start size="large"> mdi-import</v-icon>
131+
<v-icon start size="large">mdi-import</v-icon>
108132
<span>Import</span>
109133
</v-btn>
110134
<input
@@ -114,12 +138,10 @@ const calibrationImageURL = (index: number) =>
114138
style="display: none"
115139
@change="importCalibration"
116140
/>
117-
</v-col>
118-
<v-col cols="6" md="3" class="d-flex align-center pt-0 pt-md-3 pr-6 pr-md-3">
119141
<v-btn
120142
color="buttonPassive"
121143
:disabled="!currentCalibrationCoeffs"
122-
style="width: 100%"
144+
style="flex: 1"
123145
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
124146
@click="openExportCalibrationPrompt"
125147
>
@@ -289,6 +311,33 @@ const calibrationImageURL = (index: number) =>
289311
</v-data-table>
290312
</v-card-text>
291313
</v-card>
314+
315+
<v-dialog v-model="confirmRemoveDialog.show" width="600">
316+
<v-card color="surface" dark>
317+
<v-card-title>Delete Calibration</v-card-title>
318+
<v-card-text class="pt-0">
319+
Are you sure you want to delete the calibration for {{ confirmRemoveDialog.vf.resolution.width }}x{{
320+
confirmRemoveDialog.vf.resolution.height
321+
}}? This cannot be undone.
322+
<v-card-actions class="pt-5 pb-0 pr-0" style="justify-content: flex-end">
323+
<v-btn
324+
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
325+
color="primary"
326+
@click="() => (confirmRemoveDialog.show = false)"
327+
>
328+
Cancel
329+
</v-btn>
330+
<v-btn
331+
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
332+
color="error"
333+
@click="removeCalibration(confirmRemoveDialog.vf)"
334+
>
335+
Delete
336+
</v-btn>
337+
</v-card-actions>
338+
</v-card-text>
339+
</v-card>
340+
</v-dialog>
292341
</template>
293342

294343
<style scoped>

photon-core/src/main/java/org/photonvision/common/configuration/CameraConfiguration.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.ArrayList;
2525
import java.util.List;
2626
import java.util.UUID;
27+
import org.opencv.core.Size;
2728
import org.photonvision.common.dataflow.websocket.UICameraConfiguration;
2829
import org.photonvision.common.logging.LogGroup;
2930
import org.photonvision.common.logging.Logger;
@@ -189,6 +190,23 @@ public void addCalibration(CameraCalibrationCoefficients calibration) {
189190
calibrations.add(calibration);
190191
}
191192

193+
/**
194+
* Remove a calibration from our list.
195+
*
196+
* @param calibration The calibration to remove
197+
*/
198+
public void removeCalibration(Size unrotatedImageSize) {
199+
logger.info("deleting calibration " + unrotatedImageSize);
200+
calibrations.stream()
201+
.filter(it -> it.unrotatedImageSize.equals(unrotatedImageSize))
202+
.findAny()
203+
.ifPresent(
204+
(it) -> {
205+
it.release();
206+
calibrations.remove(it);
207+
});
208+
}
209+
192210
/**
193211
* cscore will auto-reconnect to the camera path we give it. v4l does not guarantee that if i swap
194212
* cameras around, the same /dev/videoN ID will be assigned to that camera. So instead default to

photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,16 @@ public void addCalibrationToConfig(CameraCalibrationCoefficients newCalibration)
680680
saveAndBroadcastAll();
681681
}
682682

683+
public void removeCalibrationFromConfig(Size unrotatedImageSize) {
684+
if (unrotatedImageSize != null) {
685+
visionSource.getSettables().removeCalibration(unrotatedImageSize);
686+
} else {
687+
logger.error("Got null size?");
688+
}
689+
690+
saveAndBroadcastAll();
691+
}
692+
683693
/**
684694
* Add/remove quirks from the camera we're controlling
685695
*

photon-core/src/main/java/org/photonvision/vision/processes/VisionSourceSettables.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import edu.wpi.first.cscore.VideoMode;
2121
import java.util.HashMap;
22+
import org.opencv.core.Size;
2223
import org.photonvision.common.configuration.CameraConfiguration;
2324
import org.photonvision.common.logging.LogGroup;
2425
import org.photonvision.common.logging.Logger;
@@ -120,6 +121,11 @@ public void addCalibration(CameraCalibrationCoefficients calibrationCoefficients
120121
calculateFrameStaticProps();
121122
}
122123

124+
public void removeCalibration(Size unrotatedImageSize) {
125+
configuration.removeCalibration(unrotatedImageSize);
126+
calculateFrameStaticProps();
127+
}
128+
123129
protected void calculateFrameStaticProps() {
124130
var videoMode = getCurrentVideoMode();
125131
this.frameStaticProperties =

photon-server/src/main/java/org/photonvision/server/RequestHandler.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.opencv.core.Mat;
3636
import org.opencv.core.MatOfByte;
3737
import org.opencv.core.MatOfInt;
38+
import org.opencv.core.Size;
3839
import org.opencv.imgcodecs.Imgcodecs;
3940
import org.photonvision.common.configuration.ConfigManager;
4041
import org.photonvision.common.configuration.NetworkConfig;
@@ -997,6 +998,46 @@ public static void onMetricsPublishRequest(Context ctx) {
997998
ctx.status(204);
998999
}
9991000

1001+
private record CalibrationRemoveRequest(int width, int height, String cameraUniqueName) {}
1002+
1003+
public static void onCalibrationRemoveRequest(Context ctx) {
1004+
try {
1005+
CalibrationRemoveRequest request =
1006+
kObjectMapper.readValue(ctx.body(), CalibrationRemoveRequest.class);
1007+
1008+
logger.info(
1009+
"Attempting to remove calibration for camera: "
1010+
+ request.cameraUniqueName
1011+
+ " with a resolution of "
1012+
+ request.width
1013+
+ "x"
1014+
+ request.height);
1015+
1016+
VisionSourceManager.getInstance()
1017+
.vmm
1018+
.getModule(request.cameraUniqueName)
1019+
.removeCalibrationFromConfig(new Size(request.width, request.height));
1020+
1021+
ctx.status(200);
1022+
ctx.result(
1023+
"Successfully removed calibration for resolution: "
1024+
+ request.width
1025+
+ "x"
1026+
+ request.height);
1027+
logger.info(
1028+
"Successfully removed calibration for resolution: "
1029+
+ request.width
1030+
+ "x"
1031+
+ request.height);
1032+
} catch (JsonProcessingException e) {
1033+
ctx.status(400).result("Invalid JSON format");
1034+
logger.error("Failed to process calibration removed request", e);
1035+
} catch (Exception e) {
1036+
ctx.status(500).result("Failed to removed calibration");
1037+
logger.error("Unexpected error while attempting to remove calibration", e);
1038+
}
1039+
}
1040+
10001041
public static void onCalibrationSnapshotRequest(Context ctx) {
10011042
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
10021043
var width = Integer.parseInt(ctx.queryParam("width"));

photon-server/src/main/java/org/photonvision/server/Server.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ private static void start(int port) {
148148
// Calibration
149149
app.post("/api/calibration/end", RequestHandler::onCalibrationEndRequest);
150150
app.post("/api/calibration/importFromData", RequestHandler::onDataCalibrationImportRequest);
151+
app.post("/api/calibration/remove", RequestHandler::onCalibrationRemoveRequest);
151152

152153
// Object detection
153154
app.post("/api/objectdetection/import", RequestHandler::onImportObjectDetectionModelRequest);

0 commit comments

Comments
 (0)