Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,47 @@ import { useStateStore } from "@/stores/StateStore";
import { computed, inject, ref } from "vue";
import { getResolutionString, parseJsonFile } from "@/lib/PhotonUtils";
import { useTheme } from "vuetify";
import axios from "axios";

const theme = useTheme();

const props = defineProps<{
videoFormat: VideoFormat;
}>();

const removeCalibration = () => {
axios
.post("/calibration/remove", {
cameraUniqueName: useCameraSettingsStore().currentCameraSettings.uniqueName,
width: props.videoFormat.resolution.width,
height: props.videoFormat.resolution.height
})
.then((response) => {
useStateStore().showSnackbarMessage({
message: response.data.text || response.data,
color: "success"
});
})
.catch((error) => {
if (error.response) {
useStateStore().showSnackbarMessage({
color: "error",
message: error.response.data.text || error.response.data
});
} else if (error.request) {
useStateStore().showSnackbarMessage({
color: "error",
message: "Error while trying to process the request! The backend didn't respond."
});
} else {
useStateStore().showSnackbarMessage({
color: "error",
message: "An error occurred while trying to process the request."
});
}
});
};

const exportCalibration = ref();
const openExportCalibrationPrompt = () => {
exportCalibration.value.click();
Expand Down Expand Up @@ -93,18 +127,30 @@ const calibrationImageURL = (index: number) =>
</script>
<template>
<v-card color="surface" dark>
<div class="d-flex flex-wrap pt-2 pl-2 pr-2">
<div class="d-flex flex-wrap pt-2 pl-2 pr-2 align-center">
<v-col cols="12" md="6">
<v-card-title class="pa-0"> Calibration Details </v-card-title>
</v-col>
<v-col cols="6" md="3" class="d-flex align-center pt-0 pt-md-3 pl-6 pl-md-3">
<v-col cols="12" md="6" class="d-flex align-center pt-0 pt-md-3">
<v-btn
color="error"
:disabled="!currentCalibrationCoeffs"
class="mr-2"
style="flex: 1"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="removeCalibration"
>
<v-icon start size="large">mdi-delete</v-icon>
<span>Delete</span>
</v-btn>
<v-btn
color="buttonPassive"
style="width: 100%"
class="mr-2"
style="flex: 1"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="openUploadPhotonCalibJsonPrompt"
>
<v-icon start size="large"> mdi-import</v-icon>
<v-icon start size="large">mdi-import</v-icon>
<span>Import</span>
</v-btn>
<input
Expand All @@ -114,12 +160,10 @@ const calibrationImageURL = (index: number) =>
style="display: none"
@change="importCalibration"
/>
</v-col>
<v-col cols="6" md="3" class="d-flex align-center pt-0 pt-md-3 pr-6 pr-md-3">
<v-btn
color="buttonPassive"
:disabled="!currentCalibrationCoeffs"
style="width: 100%"
style="flex: 1"
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
@click="openExportCalibrationPrompt"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.opencv.core.Size;
import org.photonvision.common.dataflow.websocket.UICameraConfiguration;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
Expand Down Expand Up @@ -189,6 +190,23 @@ public void addCalibration(CameraCalibrationCoefficients calibration) {
calibrations.add(calibration);
}

/**
* Remove a calibration from our list.
*
* @param calibration The calibration to remove
*/
public void removeCalibration(Size unrotatedImageSize) {
logger.info("deleting calibration " + unrotatedImageSize);
calibrations.stream()
.filter(it -> it.unrotatedImageSize.equals(unrotatedImageSize))
.findAny()
.ifPresent(
(it) -> {
it.release();
calibrations.remove(it);
});
}

/**
* cscore will auto-reconnect to the camera path we give it. v4l does not guarantee that if i swap
* cameras around, the same /dev/videoN ID will be assigned to that camera. So instead default to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,16 @@ public void addCalibrationToConfig(CameraCalibrationCoefficients newCalibration)
saveAndBroadcastAll();
}

public void removeCalibrationFromConfig(Size unrotatedImageSize) {
if (unrotatedImageSize != null) {
visionSource.getSettables().removeCalibration(unrotatedImageSize);
} else {
logger.error("Got null size?");
}

saveAndBroadcastAll();
}

/**
* Add/remove quirks from the camera we're controlling
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import edu.wpi.first.cscore.VideoMode;
import java.util.HashMap;
import org.opencv.core.Size;
import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
Expand Down Expand Up @@ -120,6 +121,11 @@ public void addCalibration(CameraCalibrationCoefficients calibrationCoefficients
calculateFrameStaticProps();
}

public void removeCalibration(Size unrotatedImageSize) {
configuration.removeCalibration(unrotatedImageSize);
calculateFrameStaticProps();
}

protected void calculateFrameStaticProps() {
var videoMode = getCurrentVideoMode();
this.frameStaticProperties =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfInt;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.configuration.NetworkConfig;
Expand Down Expand Up @@ -1001,6 +1002,46 @@ public static void onMetricsPublishRequest(Context ctx) {
ctx.status(204);
}

private record CalibrationRemoveRequest(int width, int height, String cameraUniqueName) {}

public static void onCalibrationRemoveRequest(Context ctx) {
try {
CalibrationRemoveRequest request =
kObjectMapper.readValue(ctx.body(), CalibrationRemoveRequest.class);

logger.info(
"Attempting to remove calibration for camera: "
+ request.cameraUniqueName
+ " with a resolution of "
+ request.width
+ "x"
+ request.height);

VisionSourceManager.getInstance()
.vmm
.getModule(request.cameraUniqueName)
.removeCalibrationFromConfig(new Size(request.width, request.height));

ctx.status(200);
ctx.result(
"Successfully removed calibration for resolution: "
+ request.width
+ "x"
+ request.height);
logger.info(
"Successfully removed calibration for resolution: "
+ request.width
+ "x"
+ request.height);
} catch (JsonProcessingException e) {
ctx.status(400).result("Invalid JSON format");
logger.error("Failed to process calibration removed request", e);
} catch (Exception e) {
ctx.status(500).result("Failed to removed calibration");
logger.error("Unexpected error while attempting to remove calibration", e);
}
}

public static void onCalibrationSnapshotRequest(Context ctx) {
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
var width = Integer.parseInt(ctx.queryParam("width"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ private static void start(int port) {
// Calibration
app.post("/api/calibration/end", RequestHandler::onCalibrationEndRequest);
app.post("/api/calibration/importFromData", RequestHandler::onDataCalibrationImportRequest);
app.post("/api/calibration/remove", RequestHandler::onCalibrationRemoveRequest);

// Object detection
app.post("/api/objectdetection/import", RequestHandler::onImportObjectDetectionModelRequest);
Expand Down
Loading