Add camera calibration steps into refactored calibration wizard.

This commit is contained in:
Julian Stirling 2025-10-22 22:45:19 +01:00
parent 8f1253ec02
commit 0ebc507eff
10 changed files with 186 additions and 32 deletions

View file

@ -86,6 +86,11 @@ class SimulatedCamera(BaseCamera):
self.generate_blobs() self.generate_blobs()
self.generate_canvas() self.generate_canvas()
@lt.thing_property
def calibration_required(self) -> bool:
"""Whether the camera needs calibrating."""
return not self.background_detector_status.ready
def validate_inputs(self) -> None: def validate_inputs(self) -> None:
"""Validate the inputs passed to the simulation, and raises an error if invalid. """Validate the inputs passed to the simulation, and raises an error if invalid.
@ -367,6 +372,22 @@ class SimulatedCamera(BaseCamera):
LOGGER.warning(f"Simulation camera camera doesn't respect {stream_name=}") LOGGER.warning(f"Simulation camera camera doesn't respect {stream_name=}")
return Image.fromarray(self.generate_frame()) return Image.fromarray(self.generate_frame())
@lt.thing_action
def full_auto_calibrate(self, portal: lt.deps.BlockingPortal) -> None:
"""Perform a full auto-calibration.
For the simulation microscope the process is:
* ``remove_sample``
* ``set_background``
* ``load_sample``
"""
self.remove_sample()
time.sleep(0.2)
self.set_background(portal)
time.sleep(0.2)
self.load_sample()
@lt.thing_action @lt.thing_action
def remove_sample(self) -> None: def remove_sample(self) -> None:
"""Show the simulated background with no sample.""" """Show the simulated background with no sample."""
@ -381,6 +402,15 @@ class SimulatedCamera(BaseCamera):
raise RuntimeError("Sample is already in place.") raise RuntimeError("Sample is already in place.")
self._show_sample = True self._show_sample = True
@lt.thing_property
def primary_calibration_actions(self) -> list[ActionButton]:
"""The calibration actions for both calibration wizard and settings panel."""
return [
action_button_for(
self.full_auto_calibrate, submit_label="Full Auto Calibrate"
),
]
@lt.thing_property @lt.thing_property
def secondary_calibration_actions(self) -> list[ActionButton]: def secondary_calibration_actions(self) -> list[ActionButton]:
"""The calibration actions that appear only in settings panel.""" """The calibration actions that appear only in settings panel."""

View file

@ -22,6 +22,8 @@
<script> <script>
import singleStepTask from "./calibrationWizardComponents/singleStepTask.vue"; import singleStepTask from "./calibrationWizardComponents/singleStepTask.vue";
import welcomeStep from "./calibrationWizardComponents/welcomeStep.vue"; import welcomeStep from "./calibrationWizardComponents/welcomeStep.vue";
import cameraCalibrationTask from "./calibrationWizardComponents/cameraCalibrationTask.vue";
import finalStep from "./calibrationWizardComponents/finalStep.vue";
export default { export default {
name: "calibrationWizard", name: "calibrationWizard",
@ -60,6 +62,8 @@ export default {
this.calibrateableThings = thingsToCheck.filter(name => this.thingAvailable(name)); this.calibrateableThings = thingsToCheck.filter(name => this.thingAvailable(name));
this.tasks = [ this.tasks = [
{component: singleStepTask, props: {stepComponent: welcomeStep}}, {component: singleStepTask, props: {stepComponent: welcomeStep}},
{component: cameraCalibrationTask},
{component: singleStepTask, props: {stepComponent: finalStep}},
] ]
}, },
@ -98,7 +102,7 @@ export default {
}, },
show_if_needed: async function() { show_if_needed: async function() {
// Check if the camera and stage are calibrated, if they can be // Check if the calibration modal is needed, and only show it if it is.
let needed = await this.check_if_needed() let needed = await this.check_if_needed()
// Check if this calibration wizard can actually do anything useful // Check if this calibration wizard can actually do anything useful
@ -117,7 +121,6 @@ export default {
this.show(); this.show();
}, },
show: function() { show: function() {
// Show the modal element // Show the modal element
var el = this.$refs["calibrationModalEl"]; var el = this.$refs["calibrationModalEl"];

View file

@ -3,18 +3,7 @@
structure structure
--> -->
<div v-show="stepValue == 0"> <div v-show="stepValue == 0">
<p>
<b
>Some important microscope calibration data is currently missing.</b
>
</p>
<p>
Your microscope will still function, however some functionality will
be limited, and image quality will likely suffer.
</p>
<p>
<b>Click Next to begin microscope calibration.</b>
</p>
</div> </div>
<div v-show="stepValue == 1"> <div v-show="stepValue == 1">
@ -28,16 +17,7 @@
</p> </p>
</div> </div>
<div v-else> <div v-else>
<p>
<b
>Follow the important steps below before starting lens-shading
calibration!</b
>
</p>
<ul class="uk-list uk-list-bullet">
<li>Remove any samples from your microscope</li>
<li>Ensure your illumination is on and properly fixed in place</li>
</ul>
<miniStreamDisplay <miniStreamDisplay
v-if="stepValue == 1" v-if="stepValue == 1"

View file

@ -11,6 +11,7 @@ Tasks can be divided into multiple steps.
--> -->
<template> <template>
<div> <div>
<h3 v-if="title">{{ title }}</h3>
<component <component
v-if="currentStep" v-if="currentStep"
:is="currentStep.component" :is="currentStep.component"
@ -43,6 +44,10 @@ export default {
name: "calibrationWizardTask", name: "calibrationWizardTask",
props: { props: {
title: {
type: String,
default: null
},
first: Boolean, first: Boolean,
final: Boolean, final: Boolean,
startOnLast: { startOnLast: {
@ -61,10 +66,6 @@ export default {
}; };
}, },
mounted() {
console.log("Steps received:", this.steps);
},
computed: { computed: {
currentStep() { currentStep() {
return this.steps[this.stepIndex] || null; return this.steps[this.stepIndex] || null;

View file

@ -0,0 +1,20 @@
<template>
<div>
<p>
<b>
Before starting camera calibration:
</b>
</p>
<ul class="uk-list uk-list-bullet">
<li>Remove any samples from your microscope</li>
<li>Ensure your illumination is on, well focussed, and centred.</li>
</ul>
</div>
</template>
<script>
export default {
name: "camCalibrationExplanation"
}
</script>

View file

@ -0,0 +1,34 @@
<template>
<stepTemplateWithStream>
<p>
<b>
<p>Once you're ready, click auto-calibrate.</p>
<cameraCalibrationSettings
:show-extra-settings="false"
:camera-uri="cameraUri"
></cameraCalibrationSettings>
</b>
</p>
</stepTemplateWithStream>
</template>
<script>
import stepTemplateWithStream from "../stepTemplateWithStream.vue"
import cameraCalibrationSettings from "../../../tabContentComponents/settingsComponents/cameraSettingsComponents/cameraCalibrationSettings.vue";
export default {
name: "cameraMainCalibrationStep",
components: {
stepTemplateWithStream,
cameraCalibrationSettings
},
computed: {
cameraUri: function() {
return `${this.$store.getters.baseUri}/camera/`;
}
}
}
</script>

View file

@ -0,0 +1,41 @@
<template>
<calibrationWizardTask
title="Camera Calibration"
:first="first"
:final="final"
:startOnLast="startOnLast"
:steps="steps"
@next="$emit('next')"
@back="$emit('back')"
/>
</template>
<script>
import calibrationWizardTask from "./calibrationWizardTask.vue";
import camCalibrationExplanation from "./cameraCalibrationSteps/camCalibrationExplanation.vue";
import cameraMainCalibrationStep from "./cameraCalibrationSteps/cameraMainCalibrationStep.vue";
export default {
name: "cameraCalibrationTask",
components: {calibrationWizardTask},
props: {
// Standard calibrationWizardTask props below:
first: Boolean,
final: Boolean,
startOnLast: {
type: Boolean,
default: false
}
},
data: function() {
return {
steps: [
{component: camCalibrationExplanation},
{component: cameraMainCalibrationStep},
]
};
}
}
</script>

View file

@ -0,0 +1,17 @@
<template>
<div>
<p>
<b>Calibration complete</b>
</p>
<p>
Click Finish to return to your microscope.
</p>
</div>
</template>
<script>
export default {
name: "finalStep"
}
</script>

View file

@ -1,5 +1,6 @@
<template> <template>
<calibrationWizardTask <calibrationWizardTask
:title="title"
:first="first" :first="first"
:final="final" :final="final"
:startOnLast="startOnLast" :startOnLast="startOnLast"
@ -24,6 +25,10 @@ export default {
default: () => ({}) default: () => ({})
}, },
// Standard calibrationWizardTask props below: // Standard calibrationWizardTask props below:
title: {
type: String,
default: null
},
first: Boolean, first: Boolean,
final: Boolean, final: Boolean,
startOnLast: { startOnLast: {
@ -39,9 +44,5 @@ export default {
] ]
}; };
}, },
mounted(){
console.log(this.stepComponent);
}
} }
</script> </script>

View file

@ -0,0 +1,27 @@
<template>
<div>
<slot></slot>
<miniStreamDisplay class="mini-preview" />
</div>
</template>
<script>
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
export default {
name: "stepTemplateWithStream",
components: {
miniStreamDisplay
}
}
</script>
<style scoped>
.mini-preview {
width: 75%;
margin-left: auto;
margin-right: auto;
}
</style>