Move background detect settings into SlideScan
This commit is contained in:
parent
bfef998300
commit
4da05b1869
7 changed files with 59 additions and 171 deletions
|
|
@ -44,6 +44,7 @@ from openflexure_microscope_server.ui import (
|
||||||
Accordion,
|
Accordion,
|
||||||
HTMLBlock,
|
HTMLBlock,
|
||||||
UIElementList,
|
UIElementList,
|
||||||
|
action_button_for,
|
||||||
property_control_for,
|
property_control_for,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -560,6 +561,28 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
|
||||||
|
|
||||||
return imaged, focus_height
|
return imaged, focus_height
|
||||||
|
|
||||||
|
@lt.action
|
||||||
|
def check_background(self) -> str:
|
||||||
|
"""Check if sample is background.
|
||||||
|
|
||||||
|
This action is a pre-run check for feeding back to the user.
|
||||||
|
"""
|
||||||
|
image_array = self._cam.grab_as_array(stream_name="lores")
|
||||||
|
is_sample, bg_message = self._background_detector.image_is_sample(image_array)
|
||||||
|
label = "sample" if is_sample else "background"
|
||||||
|
|
||||||
|
return f"Current image is {label} ({bg_message})"
|
||||||
|
|
||||||
|
@lt.action
|
||||||
|
def set_background(self) -> None:
|
||||||
|
"""Set the background for this background detector.
|
||||||
|
|
||||||
|
This sets the background for this workflows background detector as opposed to
|
||||||
|
the active background detector for the camera.
|
||||||
|
"""
|
||||||
|
image_array = self._cam.grab_as_array(stream_name="lores")
|
||||||
|
self._background_detector.set_background(image_array)
|
||||||
|
|
||||||
@lt.endpoint("get", "settings_ui", responses=UI_ELEMENT_RESPONSE)
|
@lt.endpoint("get", "settings_ui", responses=UI_ELEMENT_RESPONSE)
|
||||||
def settings_ui(self) -> UIElementList:
|
def settings_ui(self) -> UIElementList:
|
||||||
"""Return the UI for the workflow's settings in the scan tab."""
|
"""Return the UI for the workflow's settings in the scan tab."""
|
||||||
|
|
@ -593,13 +616,32 @@ class HistoScanWorkflow(RectGridWorkflow[HistoScanSettingsModel]):
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
background_ui = self._background_detector.settings_ui()
|
||||||
|
set_bg_button = action_button_for(
|
||||||
|
self,
|
||||||
|
"set_background",
|
||||||
|
poll_interval=0.1,
|
||||||
|
submit_label="Set Background",
|
||||||
|
can_terminate=False,
|
||||||
|
notify_on_success=True,
|
||||||
|
success_message="Background image has been updated",
|
||||||
|
)
|
||||||
|
check_bg_button = action_button_for(
|
||||||
|
self,
|
||||||
|
"check_background",
|
||||||
|
poll_interval=0.1,
|
||||||
|
submit_label="Check Current Image",
|
||||||
|
can_terminate=False,
|
||||||
|
notify_on_success=True,
|
||||||
|
response_is_success_message=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
background_ui.root += [set_bg_button, check_bg_button]
|
||||||
|
|
||||||
return UIElementList(
|
return UIElementList(
|
||||||
[
|
[
|
||||||
HTMLBlock(html=f"<h4>{self.display_name}</h4><p>{self.ui_blurb}<p>"),
|
HTMLBlock(html=f"<h4>{self.display_name}</h4><p>{self.ui_blurb}<p>"),
|
||||||
Accordion(
|
Accordion(title="Background Detect", children=background_ui),
|
||||||
title="Background Detect",
|
|
||||||
children=self._background_detector.settings_ui(),
|
|
||||||
),
|
|
||||||
Accordion(
|
Accordion(
|
||||||
title="Scan Settings",
|
title="Scan Settings",
|
||||||
children=scan_settings,
|
children=scan_settings,
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ class ActionButton(BaseModel):
|
||||||
action: str
|
action: str
|
||||||
"""The name of the action to be triggered."""
|
"""The name of the action to be triggered."""
|
||||||
|
|
||||||
poll_interval: int = 1
|
poll_interval: float = 1
|
||||||
"""The interval for polling in seconds."""
|
"""The interval for polling in seconds."""
|
||||||
|
|
||||||
submit_label: str = "Submit"
|
submit_label: str = "Submit"
|
||||||
|
|
@ -171,6 +171,12 @@ class ActionButton(BaseModel):
|
||||||
notify_on_success: bool = False
|
notify_on_success: bool = False
|
||||||
"""Specify whether to a notification on successful completion."""
|
"""Specify whether to a notification on successful completion."""
|
||||||
|
|
||||||
|
response_is_success_message: bool = False
|
||||||
|
"""Set True to use the action response as the success message.
|
||||||
|
|
||||||
|
If set ``success_message`` has is never used.
|
||||||
|
"""
|
||||||
|
|
||||||
success_message: str = "Success!"
|
success_message: str = "Success!"
|
||||||
"""The message to show on successful completion."""
|
"""The message to show on successful completion."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ import tabContent from "./genericComponents/tabContent.vue";
|
||||||
|
|
||||||
// Import new content components
|
// Import new content components
|
||||||
import aboutContent from "./tabContentComponents/aboutContent.vue";
|
import aboutContent from "./tabContentComponents/aboutContent.vue";
|
||||||
import backgroundDetectContent from "./tabContentComponents/backgroundDetectContent.vue";
|
|
||||||
import controlContent from "./tabContentComponents/controlContent.vue";
|
import controlContent from "./tabContentComponents/controlContent.vue";
|
||||||
import loggingContent from "./tabContentComponents/loggingContent.vue";
|
import loggingContent from "./tabContentComponents/loggingContent.vue";
|
||||||
import powerContent from "./tabContentComponents/powerContent.vue";
|
import powerContent from "./tabContentComponents/powerContent.vue";
|
||||||
|
|
@ -150,15 +149,6 @@ export default {
|
||||||
component: markRaw(controlContent),
|
component: markRaw(controlContent),
|
||||||
requiredThings: [],
|
requiredThings: [],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "background-detect",
|
|
||||||
title: "Background Detect",
|
|
||||||
icon: "background_replace",
|
|
||||||
component: markRaw(backgroundDetectContent),
|
|
||||||
// While stage isn't needed; automatic background detect has little function
|
|
||||||
// for a manual microscope.
|
|
||||||
requiredThings: ["stage"],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "slide-scan",
|
id: "slide-scan",
|
||||||
title: "Slide Scan",
|
title: "Slide Scan",
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,11 @@ export default {
|
||||||
*/
|
*/
|
||||||
actionResponse: function (response) {
|
actionResponse: function (response) {
|
||||||
if (this.actionData.notify_on_success) {
|
if (this.actionData.notify_on_success) {
|
||||||
this.modalNotify(this.actionData.success_message);
|
if (this.actionData.response_is_success_message) {
|
||||||
|
this.modalNotify(response.output);
|
||||||
|
} else {
|
||||||
|
this.modalNotify(this.actionData.success_message);
|
||||||
|
}
|
||||||
this.$emit("response", response);
|
this.$emit("response", response);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
/>
|
/>
|
||||||
<server-specified-action-button
|
<server-specified-action-button
|
||||||
v-else-if="element.element_type === 'action_button'"
|
v-else-if="element.element_type === 'action_button'"
|
||||||
:property-data="element"
|
:action-data="element"
|
||||||
/>
|
/>
|
||||||
<simple-accordion v-else-if="element.element_type === 'accordion'" :title="element.title">
|
<simple-accordion v-else-if="element.element_type === 'accordion'" :title="element.title">
|
||||||
<server-specified-interface :elements="element.children" />
|
<server-specified-interface :elements="element.children" />
|
||||||
|
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
<template>
|
|
||||||
<div ref="backgroundDetectContent" class="uk-padding-small">
|
|
||||||
<div>
|
|
||||||
<ul uk-accordion="multiple: true">
|
|
||||||
<li>
|
|
||||||
<a class="uk-accordion-title" href="#">Configure</a>
|
|
||||||
<div class="uk-accordion-content">
|
|
||||||
<h4 v-if="backgroundDetectorDisplayName" class="detector-name">
|
|
||||||
{{ backgroundDetectorDisplayName }}
|
|
||||||
</h4>
|
|
||||||
<server-specified-property-control
|
|
||||||
v-for="(setting, index) in backgroundDetectorSettings"
|
|
||||||
:key="'detector_setting' + index"
|
|
||||||
:property-data="setting"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="uk-margin">
|
|
||||||
<action-button
|
|
||||||
thing="camera"
|
|
||||||
action="set_background"
|
|
||||||
submit-label="Set Background"
|
|
||||||
:can-terminate="false"
|
|
||||||
:poll-interval="0.1"
|
|
||||||
@response="alertBackgroundSet"
|
|
||||||
@error="modalError"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="uk-margin">
|
|
||||||
<!--Once status is read this should be disabled if not ready..-->
|
|
||||||
<action-button
|
|
||||||
thing="camera"
|
|
||||||
action="image_is_sample"
|
|
||||||
submit-label="Check Current Image"
|
|
||||||
:is-disabled="!ready"
|
|
||||||
:can-terminate="false"
|
|
||||||
:poll-interval="0.1"
|
|
||||||
@response="alertImageLabel"
|
|
||||||
@error="modalError"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
|
||||||
import ServerSpecifiedPropertyControl from "../../labThingsComponents/serverSpecifiedPropertyControl.vue";
|
|
||||||
import { useIntersectionObserver } from "@vueuse/core";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
ActionButton,
|
|
||||||
ServerSpecifiedPropertyControl,
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
ready: false,
|
|
||||||
backgroundDetectorName: undefined,
|
|
||||||
backgroundDetectorDisplayName: undefined,
|
|
||||||
backgroundDetectorSettings: [],
|
|
||||||
animate: false,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async created() {
|
|
||||||
await this.readSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
useIntersectionObserver(
|
|
||||||
this.$refs.backgroundDetectContent,
|
|
||||||
([{ isIntersecting }]) => {
|
|
||||||
this.visibilityChanged(isIntersecting);
|
|
||||||
},
|
|
||||||
{
|
|
||||||
threshold: 0.0,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
async safeReadSettings() {
|
|
||||||
if (!this.$store.state.connected) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.readSettings();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error reading background detector settings:", error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
visibilityChanged(isVisible) {
|
|
||||||
if (isVisible) {
|
|
||||||
this.safeReadSettings();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
alertBackgroundSet() {
|
|
||||||
this.modalNotify(`Background image has been updated`);
|
|
||||||
},
|
|
||||||
alertImageLabel(r) {
|
|
||||||
let label = r.output[0] ? "sample" : "background";
|
|
||||||
this.modalNotify(`Current image is ${label} (${r.output[1]})`);
|
|
||||||
},
|
|
||||||
readSettings: async function () {
|
|
||||||
this.backgroundDetectorName = await this.readThingProperty(
|
|
||||||
"camera",
|
|
||||||
"background_detector_name",
|
|
||||||
);
|
|
||||||
if (this.backgroundDetectorName) {
|
|
||||||
this.ready = await this.readThingProperty(this.backgroundDetectorName, "ready");
|
|
||||||
this.backgroundDetectorSettings =
|
|
||||||
(await this.getThingEndpoint(this.backgroundDetectorName, "settings_ui")) || [];
|
|
||||||
this.backgroundDetectorDisplayName = await this.readThingProperty(
|
|
||||||
this.backgroundDetectorName,
|
|
||||||
"display_name",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<style scoped lang="less">
|
|
||||||
.detector-name {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<template>
|
|
||||||
<!-- Grid managing tab content -->
|
|
||||||
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove">
|
|
||||||
<div class="control-component">
|
|
||||||
<paneBackgroundDetect />
|
|
||||||
</div>
|
|
||||||
<div class="view-component uk-width-expand">
|
|
||||||
<streamDisplay />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import paneBackgroundDetect from "./backgroundDetectComponents/paneBackgroundDetect";
|
|
||||||
import streamDisplay from "./streamContent.vue";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "BackgroundDetectContent",
|
|
||||||
|
|
||||||
components: {
|
|
||||||
paneBackgroundDetect,
|
|
||||||
streamDisplay,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue