Add calibdb upload button (#735)

* Add calibdb upload

* Fix distortion coefficients size
This commit is contained in:
Matt
2023-01-18 16:29:58 -05:00
committed by GitHub
parent a985c6cf3a
commit 9d6997180d
6 changed files with 185 additions and 1 deletions

View File

@@ -299,6 +299,19 @@
Download Target
</v-btn>
</v-col>
<v-col>
<v-btn
color="secondary"
small
style="width: 100%;"
@click="$refs.importCalibrationFromCalibdb.click()"
>
<v-icon left>
mdi-upload
</v-icon>
Import From CalibDB
</v-btn>
</v-col>
</v-row>
</div>
</v-card>
@@ -375,6 +388,20 @@
</template>
</v-col>
</v-row>
<!-- Special hidden upload input that gets 'clicked' when the user imports settings -->
<input
ref="importCalibrationFromCalibdb"
type="file"
accept=".json"
style="display: none;"
@change="readImportedCalibration"
/>
<v-snackbar v-model="uploadSnack" top :color="uploadSnackData.color" timeout="-1">
<span>{{ uploadSnackData.text }}</span>
</v-snackbar>
</div>
</template>
@@ -406,6 +433,11 @@ export default {
filteredVideomodeIndex: 0,
settingsValid: true,
unfilteredStreamDivisors: [1, 2, 4],
uploadSnackData: {
color: "success",
text: "",
},
uploadSnack: false,
}
},
computed: {
@@ -571,6 +603,57 @@ export default {
},
},
methods: {
readImportedCalibration(event) {
// let formData = new FormData();
// formData.append("zipData", event.target.files[0]);
const filename = event.target.files[0].name;
event.target.files[0].text().then(fileText => {
const data = {
"cameraIndex": this.$store.getters.currentCameraIndex,
"payload": fileText,
"filename": filename,
};
this.axios
.post("http://" + this.$address + "/api/calibration/import", data, {
headers: { "Content-Type": "text/plain" },
})
.then(() => {
this.uploadSnackData = {
color: "success",
text:
"Calibration imported successfully! PhotonVision will restart in the background...",
};
this.uploadSnack = true;
})
.catch((err) => {
if (err.response) {
this.uploadSnackData = {
color: "error",
text:
"Error while uploading calibration file! Could not process provided file.",
};
} else if (err.request) {
this.uploadSnackData = {
color: "error",
text:
"Error while uploading calibration file! No respond to upload attempt.",
};
} else {
this.uploadSnackData = {
color: "error",
text: "Error while uploading calibration file!",
};
}
this.uploadSnack = true;
});
})
},
closeDialog() {
this.snack = false;
this.calibrationInProgress = false;

View File

@@ -21,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.Size;
@@ -82,4 +83,43 @@ public class CameraCalibrationCoefficients implements Releasable {
cameraIntrinsics.release();
distCoeffs.release();
}
public static CameraCalibrationCoefficients parseFromCalibdbJson(JsonNode json) {
// camera_matrix is a row major, array of arrays
var cam_matrix = json.get("camera_matrix");
double[] cam_arr =
new double[] {
cam_matrix.get(0).get(0).doubleValue(),
cam_matrix.get(0).get(1).doubleValue(),
cam_matrix.get(0).get(2).doubleValue(),
cam_matrix.get(1).get(0).doubleValue(),
cam_matrix.get(1).get(1).doubleValue(),
cam_matrix.get(1).get(2).doubleValue(),
cam_matrix.get(2).get(0).doubleValue(),
cam_matrix.get(2).get(1).doubleValue(),
cam_matrix.get(2).get(2).doubleValue()
};
var dist_coefs = json.get("distortion_coefficients");
double[] dist_array =
new double[] {
dist_coefs.get(0).doubleValue(),
dist_coefs.get(1).doubleValue(),
dist_coefs.get(2).doubleValue(),
dist_coefs.get(3).doubleValue(),
dist_coefs.get(4).doubleValue(),
};
var cam_jsonmat = new JsonMat(3, 3, cam_arr);
var distortion_jsonmat = new JsonMat(1, 5, dist_array);
var error = json.get("avg_reprojection_error").asDouble();
var width = json.get("img_size").get(0).doubleValue();
var height = json.get("img_size").get(1).doubleValue();
return new CameraCalibrationCoefficients(
new Size(width, height), cam_jsonmat, distortion_jsonmat, new double[] {error}, 0);
}
}

View File

@@ -586,4 +586,15 @@ public class VisionModule {
logger.error("Cannot set target model of non-reflective pipe! Ignoring...");
}
}
public void addCalibrationToConfig(CameraCalibrationCoefficients newCalibration) {
if (newCalibration != null) {
logger.info("Got new calibration for " + newCalibration.resolution);
visionSource.getSettables().getConfiguration().addCalibration(newCalibration);
} else {
logger.error("Got null calibration?");
}
saveAndBroadcastAll();
}
}

View File

@@ -28,6 +28,7 @@ import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.numbers.DoubleCouple;
import org.photonvision.common.util.numbers.IntegerCouple;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.pipeline.AdvancedPipelineSettings;
import org.photonvision.vision.pipeline.PipelineType;
import org.photonvision.vision.pipeline.UICalibrationData;
@@ -114,6 +115,10 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
parentModule.setPipeline(idx);
parentModule.saveAndBroadcastAll();
return;
case "calibrationUploaded":
if (newPropValue instanceof CameraCalibrationCoefficients)
parentModule.addCalibrationToConfig((CameraCalibrationCoefficients) newPropValue);
return;
case "robotOffsetPoint":
if (currentSettings instanceof AdvancedPipelineSettings) {
var curAdvSettings = (AdvancedPipelineSettings) currentSettings;

View File

@@ -18,6 +18,7 @@
package org.photonvision.server;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.javalin.http.Context;
import java.io.File;
@@ -33,6 +34,9 @@ import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.configuration.NetworkConfig;
import org.photonvision.common.dataflow.DataChangeDestination;
import org.photonvision.common.dataflow.DataChangeService;
import org.photonvision.common.dataflow.events.IncomingWebSocketEvent;
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.hardware.HardwareManager;
import org.photonvision.common.hardware.Platform;
@@ -42,6 +46,7 @@ import org.photonvision.common.networking.NetworkManager;
import org.photonvision.common.util.ShellExec;
import org.photonvision.common.util.TimedTaskManager;
import org.photonvision.common.util.file.ProgramDirectoryUtilities;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.processes.VisionModuleManager;
import org.photonvision.vision.target.TargetModel;
@@ -274,6 +279,44 @@ public class RequestHandler {
}
}
public static void importCalibrationFromCalibdb(Context ctx) {
var file = ctx.body();
if (file != null) {
// check if it's a JSON file
// Load using Jackson
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readTree(file);
int cameraIndex = actualObj.get("cameraIndex").asInt();
String filename = actualObj.get("filename").asText();
var payload = mapper.readTree(actualObj.get("payload").asText());
var coeffs = CameraCalibrationCoefficients.parseFromCalibdbJson(payload);
var uploadCalibrationEvent =
new IncomingWebSocketEvent<CameraCalibrationCoefficients>(
DataChangeDestination.DCD_ACTIVEMODULE,
"calibrationUploaded",
coeffs,
(Integer) cameraIndex,
null);
DataChangeService.getInstance().publishEvent(uploadCalibrationEvent);
ctx.status(200);
logger.info("Calibration added!");
} catch (Exception e) {
logger.warn("Could not parse cal metaJSON!");
e.printStackTrace();
return;
}
} else {
ctx.status(500);
return;
}
}
public static void setCameraNickname(Context ctx) {
try {
var data = kObjectMapper.readValue(ctx.body(), HashMap.class);
@@ -304,7 +347,8 @@ public class RequestHandler {
public static void sendMetrics(Context ctx) {
HardwareManager.getInstance().publishMetrics();
// TimedTaskManager.getInstance().addOneShotTask(() -> RoborioFinder.getInstance().findRios(),
// TimedTaskManager.getInstance().addOneShotTask(() ->
// RoborioFinder.getInstance().findRios(),
// 0);
ctx.status(200);
}

View File

@@ -93,6 +93,7 @@ public class Server {
app.post("api/vision/pnpModel", RequestHandler::uploadPnpModel);
app.post("api/sendMetrics", RequestHandler::sendMetrics);
app.post("api/setCameraNickname", RequestHandler::setCameraNickname);
app.post("api/calibration/import", RequestHandler::importCalibrationFromCalibdb);
app.start(port);
}