Camera settings for labthings-picamera2
I've updated URLs and tidied things a bit, so that we can now adjust the key camera settings with the new camera drivers.
This commit is contained in:
parent
13229d9b99
commit
79752a2a4c
5 changed files with 460 additions and 277 deletions
|
|
@ -0,0 +1,121 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<label class="uk-form-label">{{ label }}</label>
|
||||||
|
<div class="input-and-buttons-container">
|
||||||
|
<input
|
||||||
|
v-for="(_v, key) in value"
|
||||||
|
class="uk-form-small numeric-setting-line-input"
|
||||||
|
type="number"
|
||||||
|
v-model="value[key]"
|
||||||
|
:key="key"
|
||||||
|
@focusin="focusIn"
|
||||||
|
@focusout="focusOut"
|
||||||
|
@keydown="keyDown"
|
||||||
|
/>
|
||||||
|
<a class="button-next-to-input" @click="readProperty">
|
||||||
|
<i class="material-icons">refresh</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MultiNumericSettingLine",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
propertyUrl: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
readBackDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: undefined,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
value: {},
|
||||||
|
valueOnEnter: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
readBack: function() {
|
||||||
|
return this.readBackDelay !== undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.readProperty();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
readProperty: async function() {
|
||||||
|
let response = await axios.get(this.propertyUrl)
|
||||||
|
this.value = response.data
|
||||||
|
console.log("Read property", this.propertyUrl, response.data)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
writeProperty: async function() {
|
||||||
|
try {
|
||||||
|
let requestedValue = Number(this.value)
|
||||||
|
await axios.post(this.propertyUrl, requestedValue)
|
||||||
|
if(this.readBack) {
|
||||||
|
await new Promise(r => setTimeout(r, this.readBackDelay))
|
||||||
|
let newVal = await this.readProperty()
|
||||||
|
if(newVal == requestedValue) {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal}.`)
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal} (requested ${requestedValue}).`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${this.value}.`);
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
this.modalError(error); // Let mixin handle error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focusIn: function(event) {
|
||||||
|
this.valueOnEnter = event.target.value;
|
||||||
|
},
|
||||||
|
focusOut: function(event) {
|
||||||
|
if (this.valueOnEnter != event.target.value) {
|
||||||
|
this.writeProperty(event.target.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyDown: function(event) {
|
||||||
|
// Pressing enter should set the property, whether or not we think it's changed.
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
this.writeProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input-and-buttons-container {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.numeric-setting-line-input {
|
||||||
|
display: table-cell;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
.button-next-to-input {
|
||||||
|
display: table-cell;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<label class="uk-form-label">{{ label }}</label>
|
||||||
|
<div class="input-and-buttons-container">
|
||||||
|
<input
|
||||||
|
v-for="i in value.length"
|
||||||
|
class="uk-form-small numeric-setting-line-input"
|
||||||
|
type="number"
|
||||||
|
v-model="value[i - 1]"
|
||||||
|
:key="i"
|
||||||
|
@focusin="focusIn"
|
||||||
|
@focusout="focusOut"
|
||||||
|
@keydown="keyDown"
|
||||||
|
/>
|
||||||
|
<a class="button-next-to-input" @click="readProperty">
|
||||||
|
<i class="material-icons">refresh</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "NumericArraySettingLine",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
propertyUrl: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
readBackDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: undefined,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
value: {},
|
||||||
|
valueOnEnter: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
readBack: function() {
|
||||||
|
return this.readBackDelay !== undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.readProperty();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
readProperty: async function() {
|
||||||
|
let response = await axios.get(this.propertyUrl)
|
||||||
|
this.value = response.data
|
||||||
|
console.log("Read property", this.propertyUrl, response.data)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
writeProperty: async function() {
|
||||||
|
try {
|
||||||
|
let requestedValue = this.value
|
||||||
|
await axios.post(this.propertyUrl, requestedValue)
|
||||||
|
if(this.readBack) {
|
||||||
|
await new Promise(r => setTimeout(r, this.readBackDelay))
|
||||||
|
let newVal = await this.readProperty()
|
||||||
|
if(newVal == requestedValue) {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal}.`)
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal} (requested ${requestedValue}).`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${this.value}.`);
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
this.modalError(error); // Let mixin handle error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focusIn: function(event) {
|
||||||
|
this.valueOnEnter = event.target.value;
|
||||||
|
},
|
||||||
|
focusOut: function(event) {
|
||||||
|
if (this.valueOnEnter != event.target.value) {
|
||||||
|
this.writeProperty(event.target.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyDown: function(event) {
|
||||||
|
// Pressing enter should set the property, whether or not we think it's changed.
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
this.writeProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input-and-buttons-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-content: stretch;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.numeric-setting-line-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
.button-next-to-input {
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
125
webapp/src/components/genericComponents/numericSettingLine.vue
Normal file
125
webapp/src/components/genericComponents/numericSettingLine.vue
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<label class="uk-form-label">{{ label }}</label>
|
||||||
|
<div class="input-and-buttons-container">
|
||||||
|
<input
|
||||||
|
class="uk-form-small numeric-setting-line-input"
|
||||||
|
type="number"
|
||||||
|
v-model="value"
|
||||||
|
@focusin="focusIn"
|
||||||
|
@focusout="focusOut"
|
||||||
|
@keydown="keyDown"
|
||||||
|
/>
|
||||||
|
<a class="button-next-to-input" @click="readProperty">
|
||||||
|
<i class="material-icons">refresh</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "NumericSettingLine",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
propertyUrl: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
readBackDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: undefined,
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
value: undefined,
|
||||||
|
valueOnEnter: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
readBack: function() {
|
||||||
|
return this.readBackDelay !== undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.readProperty();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
readProperty: async function() {
|
||||||
|
let response = await axios.get(this.propertyUrl)
|
||||||
|
this.value = response.data
|
||||||
|
console.log("Read property", this.propertyUrl, response.data)
|
||||||
|
return response.data
|
||||||
|
},
|
||||||
|
writeProperty: async function() {
|
||||||
|
try {
|
||||||
|
let requestedValue = Number(this.value)
|
||||||
|
await axios.post(this.propertyUrl, requestedValue)
|
||||||
|
if(this.readBack) {
|
||||||
|
await new Promise(r => setTimeout(r, this.readBackDelay))
|
||||||
|
let newVal = await this.readProperty()
|
||||||
|
if(newVal == requestedValue) {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal}.`)
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${newVal} (requested ${requestedValue}).`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await this.modalNotify(`Set ${this.label} to ${this.value}.`);
|
||||||
|
}
|
||||||
|
} catch(error) {
|
||||||
|
this.modalError(error); // Let mixin handle error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focusIn: function(event) {
|
||||||
|
this.valueOnEnter = event.target.value;
|
||||||
|
},
|
||||||
|
focusOut: function(event) {
|
||||||
|
if (this.valueOnEnter != event.target.value) {
|
||||||
|
this.writeProperty(event.target.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyDown: function(event) {
|
||||||
|
// Pressing enter should set the property, whether or not we think it's changed.
|
||||||
|
if (event.keyCode == 13) {
|
||||||
|
this.writeProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.input-and-buttons-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-content: stretch;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.numeric-setting-line-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
.button-next-to-input {
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
<div id="cameraSettings">
|
<div id="cameraSettings">
|
||||||
<div class="uk-grid uk-grid-divider uk-child-width-expand" uk-grid>
|
<div class="uk-grid uk-grid-divider uk-child-width-expand" uk-grid>
|
||||||
<div class="uk-width-large">
|
<div class="uk-width-large">
|
||||||
|
<h3>Automatic calibration</h3>
|
||||||
|
<cameraCalibrationSettings :camera-uri="cameraUri"/>
|
||||||
|
|
||||||
<h3>Manual camera settings</h3>
|
<h3>Manual camera settings</h3>
|
||||||
<form @submit.prevent="applySettingsRequest">
|
<form @submit.prevent="applySettingsRequest">
|
||||||
<div class="uk-margin-small-bottom">
|
<div class="uk-margin-small-bottom">
|
||||||
|
|
@ -9,139 +12,42 @@
|
||||||
<li class="uk-open">
|
<li class="uk-open">
|
||||||
<a class="uk-accordion-title" href="#">Pi Camera Settings</a>
|
<a class="uk-accordion-title" href="#">Pi Camera Settings</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
<div v-if="picamera.shutter_speed !== undefined">
|
<NumericSettingLine
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
label="Exposure time"
|
||||||
>Exposure time</label
|
:property-url="cameraUri + 'exposure_time'"
|
||||||
>
|
:read-back-delay="1000"
|
||||||
<div class="uk-form-controls">
|
/>
|
||||||
<input
|
<NumericSettingLine
|
||||||
v-model="picamera.shutter_speed"
|
label="Analogue gain"
|
||||||
class="uk-input uk-form-small"
|
:property-url="cameraUri + 'analogue_gain'"
|
||||||
type="number"
|
:read-back-delay="1000"
|
||||||
/>
|
/>
|
||||||
</div>
|
<NumericArraySettingLine
|
||||||
</div>
|
label="Colour gains"
|
||||||
|
:property-url="cameraUri + 'colour_gains'"
|
||||||
<div v-if="picamera.analog_gain !== undefined">
|
:read-back-delay="1000"
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
/>
|
||||||
>Analogue gain</label
|
|
||||||
>
|
|
||||||
<div class="uk-form-controls">
|
|
||||||
<input
|
|
||||||
v-model="picamera.analog_gain"
|
|
||||||
class="uk-input uk-form-small"
|
|
||||||
type="number"
|
|
||||||
step="0.0000000000000001"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="picamera.digital_gain !== undefined">
|
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
|
||||||
>Digital gain</label
|
|
||||||
>
|
|
||||||
<div class="uk-form-controls">
|
|
||||||
<input
|
|
||||||
v-model="picamera.digital_gain"
|
|
||||||
class="uk-input uk-form-small"
|
|
||||||
type="number"
|
|
||||||
step="0.0000000000000001"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="picamera.awb_gains !== undefined">
|
|
||||||
<label class="uk-form-label" for="form-stacked-text">
|
|
||||||
White Balance gains
|
|
||||||
</label>
|
|
||||||
<div class="uk-form-controls">
|
|
||||||
<label class="uk-form-label">R:</label>
|
|
||||||
<input
|
|
||||||
v-model="picamera.awb_gains[0]"
|
|
||||||
class="uk-input uk-form-small"
|
|
||||||
type="number"
|
|
||||||
step="0.0000000000000001"
|
|
||||||
/>
|
|
||||||
<label class="uk-form-label">B:</label>
|
|
||||||
<input
|
|
||||||
v-model="picamera.awb_gains[1]"
|
|
||||||
class="uk-input uk-form-small"
|
|
||||||
type="number"
|
|
||||||
step="0.0000000000000001"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="uk-open">
|
<li class="uk-open">
|
||||||
<a class="uk-accordion-title" href="#">Image Quality</a>
|
<a class="uk-accordion-title" href="#">Image Quality</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
<div class="uk-child-width-1-2" uk-grid>
|
<NumericSettingLine
|
||||||
<div v-if="jpeg_quality !== undefined">
|
label="MJPEG stream bit rate"
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
:property-url="cameraUri + 'mjpeg_bitrate'"
|
||||||
>JPEG capture quality (%)</label
|
:read-back-delay="100"
|
||||||
>
|
/>
|
||||||
<div class="uk-form-controls">
|
<NumericArraySettingLine
|
||||||
<input
|
label="MJPEG stream resolution"
|
||||||
v-model="jpeg_quality"
|
:property-url="cameraUri +'stream_resolution'"
|
||||||
class="uk-input uk-form-small"
|
:read-back-delay="100"
|
||||||
type="number"
|
/>
|
||||||
step="1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="stream_resolution !== undefined">
|
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
|
||||||
>Stream resolution</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
v-model="stream_resolution"
|
|
||||||
class="uk-select uk-form-small"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="option in resolutionOptions"
|
|
||||||
:key="option.value[0]"
|
|
||||||
:value="option.value"
|
|
||||||
>
|
|
||||||
{{ option.text }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<!--
|
||||||
<li>
|
<li>
|
||||||
<a class="uk-accordion-title" href="#">Advanced</a>
|
<a class="uk-accordion-title" href="#">Advanced</a>
|
||||||
<div class="uk-accordion-content">
|
<div class="uk-accordion-content">
|
||||||
<div v-if="mjpeg_bitrate !== undefined">
|
|
||||||
<label class="uk-form-label" for="form-stacked-text"
|
|
||||||
>Camera bitrate</label
|
|
||||||
>
|
|
||||||
<select
|
|
||||||
v-model="mjpeg_bitrate"
|
|
||||||
class="uk-select uk-form-small"
|
|
||||||
>
|
|
||||||
<option
|
|
||||||
v-for="option in bitrateOptions"
|
|
||||||
:key="option.value"
|
|
||||||
:value="option.value"
|
|
||||||
>
|
|
||||||
{{ option.text }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<p class="uk-margin-remove">
|
|
||||||
This option sets the target bitrate for camera
|
|
||||||
recordings.<br />
|
|
||||||
<b
|
|
||||||
>Limiting bitrate may impact fast-autofocus
|
|
||||||
reliability.</b
|
|
||||||
>
|
|
||||||
However is guaranteed to fix the live stream disappearing
|
|
||||||
for some highly detailed samples.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="picamera.framerate !== undefined"
|
v-if="picamera.framerate !== undefined"
|
||||||
|
|
@ -166,27 +72,14 @@
|
||||||
This option sets the framerate of the Pi Camera video
|
This option sets the framerate of the Pi Camera video
|
||||||
encoder. The actual stream framerate is determined by
|
encoder. The actual stream framerate is determined by
|
||||||
network speed, and is limited by the encoder framerate.<br />
|
network speed, and is limited by the encoder framerate.<br />
|
||||||
<b
|
<b>Lowering framerate may impact fast-autofocus accuracy.</b>
|
||||||
>Lowering framerate may impact fast-autofocus
|
|
||||||
accuracy.</b
|
|
||||||
>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>-->
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="uk-button uk-button-primary uk-margin-small uk-width-1-1"
|
|
||||||
>
|
|
||||||
Apply Settings
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h3>Automatic calibration</h3>
|
|
||||||
<cameraCalibrationSettings></cameraCalibrationSettings>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="mini-stream">
|
<div id="mini-stream">
|
||||||
|
|
@ -197,9 +90,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from "axios";
|
|
||||||
import cameraCalibrationSettings from "./cameraSettingsComponents/cameraCalibrationSettings.vue";
|
import cameraCalibrationSettings from "./cameraSettingsComponents/cameraCalibrationSettings.vue";
|
||||||
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
|
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
|
||||||
|
import NumericSettingLine from "../../genericComponents/numericSettingLine.vue";
|
||||||
|
import NumericArraySettingLine from "../../genericComponents/numericArraySettingLine.vue";
|
||||||
|
|
||||||
// Export main app
|
// Export main app
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -207,8 +101,10 @@ export default {
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
cameraCalibrationSettings,
|
cameraCalibrationSettings,
|
||||||
miniStreamDisplay
|
miniStreamDisplay,
|
||||||
},
|
NumericSettingLine,
|
||||||
|
NumericArraySettingLine
|
||||||
|
},
|
||||||
|
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -242,74 +138,8 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
settingsUri: function() {
|
cameraUri: function() {
|
||||||
return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
|
return `${this.$store.getters.baseUri}/camera/`;
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.updateSettings();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
updateSettings: function() {
|
|
||||||
axios
|
|
||||||
.get(this.settingsUri)
|
|
||||||
.then(response => {
|
|
||||||
const cameraSettings = response.data.camera;
|
|
||||||
// Get base camera settings
|
|
||||||
this.mjpeg_bitrate = cameraSettings.mjpeg_bitrate;
|
|
||||||
this.jpeg_quality = cameraSettings.jpeg_quality;
|
|
||||||
this.stream_resolution = cameraSettings.stream_resolution;
|
|
||||||
// Get Pi Camera settings if they exist
|
|
||||||
if (cameraSettings.picamera) {
|
|
||||||
this.picamera.analog_gain = cameraSettings.picamera.analog_gain;
|
|
||||||
this.picamera.digital_gain = cameraSettings.picamera.digital_gain;
|
|
||||||
this.picamera.shutter_speed = cameraSettings.picamera.shutter_speed;
|
|
||||||
this.picamera.framerate = cameraSettings.picamera.framerate;
|
|
||||||
this.picamera.awb_gains = cameraSettings.picamera.awb_gains;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.modalError(error); // Let mixin handle error
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
applySettingsRequest: function() {
|
|
||||||
// We have to use parseInt/parseFloat because JS sometimes seems to
|
|
||||||
// make the numbers be strings... TypeScript would solve this...
|
|
||||||
var payload = {
|
|
||||||
camera: {
|
|
||||||
mjpeg_bitrate: parseInt(this.mjpeg_bitrate),
|
|
||||||
jpeg_quality: parseInt(this.jpeg_quality),
|
|
||||||
stream_resolution: this.stream_resolution,
|
|
||||||
picamera: {
|
|
||||||
shutter_speed: parseFloat(this.picamera.shutter_speed),
|
|
||||||
analog_gain: parseFloat(this.picamera.analog_gain),
|
|
||||||
digital_gain: parseFloat(this.picamera.digital_gain),
|
|
||||||
framerate: parseInt(this.picamera.framerate),
|
|
||||||
awb_gains: [
|
|
||||||
parseFloat(this.picamera.awb_gains[0]),
|
|
||||||
parseFloat(this.picamera.awb_gains[1])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
console.log(payload);
|
|
||||||
// Send request
|
|
||||||
axios
|
|
||||||
.put(this.settingsUri, payload)
|
|
||||||
.then(() => {
|
|
||||||
return new Promise(r => setTimeout(r, 500));
|
|
||||||
}) // why is there no built-in for this??!
|
|
||||||
.then(() => {
|
|
||||||
// Update local settings
|
|
||||||
this.updateSettings();
|
|
||||||
this.modalNotify("Camera settings applied.");
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.modalError(error); // Let mixin handle error
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--Show auto calibrate if default plugin is enabled-->
|
<!--Show auto calibrate if default plugin is enabled-->
|
||||||
<div v-if="'recalibrate' in recalibrationLinks" class="uk-margin-small">
|
<div v-if="'full_auto_calibrate' in actions" class="uk-margin-small">
|
||||||
<taskSubmitter
|
<taskSubmitter
|
||||||
:can-terminate="false"
|
:can-terminate="false"
|
||||||
:requires-confirmation="true"
|
:requires-confirmation="true"
|
||||||
:confirmation-message="
|
:confirmation-message="
|
||||||
'Start recalibration? This may take a while, and the microscope will be locked during this time.'
|
'Start recalibration? This may take a while, and the microscope will be locked during this time.'
|
||||||
"
|
"
|
||||||
:submit-url="recalibrationLinks.recalibrate.href"
|
:submit-url="cameraUri + 'full_auto_calibrate'"
|
||||||
:submit-label="'Full Auto-Calibrate'"
|
:submit-label="'Full Auto-Calibrate'"
|
||||||
@response="onRecalibrateResponse"
|
@response="onRecalibrateResponse"
|
||||||
@error="modalError"
|
@error="modalError"
|
||||||
|
|
@ -16,13 +16,13 @@
|
||||||
</taskSubmitter>
|
</taskSubmitter>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="'auto_exposure_from_raw' in recalibrationLinks"
|
v-if="'auto_expose_from_minimum' in actions"
|
||||||
class="uk-margin-small"
|
class="uk-margin-small"
|
||||||
>
|
>
|
||||||
<taskSubmitter
|
<taskSubmitter
|
||||||
:can-terminate="false"
|
:can-terminate="false"
|
||||||
:requires-confirmation="false"
|
:requires-confirmation="false"
|
||||||
:submit-url="recalibrationLinks.auto_exposure_from_raw.href"
|
:submit-url="cameraUri + 'auto_expose_from_minimum'"
|
||||||
:submit-label="'Auto gain & shutter speed'"
|
:submit-label="'Auto gain & shutter speed'"
|
||||||
@response="onRecalibrateResponse"
|
@response="onRecalibrateResponse"
|
||||||
@error="modalError"
|
@error="modalError"
|
||||||
|
|
@ -30,13 +30,13 @@
|
||||||
</taskSubmitter>
|
</taskSubmitter>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="'auto_white_balance_from_raw' in recalibrationLinks"
|
v-if="'calibrate_white_balance' in actions"
|
||||||
class="uk-margin-small"
|
class="uk-margin-small"
|
||||||
>
|
>
|
||||||
<taskSubmitter
|
<taskSubmitter
|
||||||
:can-terminate="false"
|
:can-terminate="false"
|
||||||
:requires-confirmation="false"
|
:requires-confirmation="false"
|
||||||
:submit-url="recalibrationLinks.auto_white_balance_from_raw.href"
|
:submit-url="cameraUri + 'calibrate_white_balance'"
|
||||||
:submit-label="'Auto white balance'"
|
:submit-label="'Auto white balance'"
|
||||||
@response="onRecalibrateResponse"
|
@response="onRecalibrateResponse"
|
||||||
@error="modalError"
|
@error="modalError"
|
||||||
|
|
@ -44,7 +44,7 @@
|
||||||
</taskSubmitter>
|
</taskSubmitter>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="'auto_lens_shading_table' in recalibrationLinks"
|
v-if="'calibrate_lens_shading' in actions"
|
||||||
class="uk-margin-small"
|
class="uk-margin-small"
|
||||||
>
|
>
|
||||||
<taskSubmitter
|
<taskSubmitter
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
'Is the microscope looking at an evenly illuminated, empty field of view? ' +
|
'Is the microscope looking at an evenly illuminated, empty field of view? ' +
|
||||||
'If not, the current image will show through in any images captured afterwards.'
|
'If not, the current image will show through in any images captured afterwards.'
|
||||||
"
|
"
|
||||||
:submit-url="recalibrationLinks.auto_lens_shading_table.href"
|
:submit-url="cameraUri + 'calibrate_lens_shading'"
|
||||||
:submit-label="'Auto flat field correction'"
|
:submit-label="'Auto flat field correction'"
|
||||||
@response="onRecalibrateResponse"
|
@response="onRecalibrateResponse"
|
||||||
@error="modalError"
|
@error="modalError"
|
||||||
|
|
@ -62,23 +62,34 @@
|
||||||
</taskSubmitter>
|
</taskSubmitter>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="showExtraSettings" class="uk-child-width-expand">
|
<div
|
||||||
<button
|
v-show="showExtraSettings"
|
||||||
v-if="'flatten_lens_shading_table' in recalibrationLinks"
|
v-if="'flatten_lens_shading_table' in actions"
|
||||||
class="uk-button uk-button-danger uk-width-1-1"
|
class="uk-child-width-expand"
|
||||||
@click="flattenLensShadingTableRequest"
|
>
|
||||||
|
<taskSubmitter
|
||||||
|
:can-terminate="false"
|
||||||
|
:requires-confirmation="false"
|
||||||
|
:submit-url="cameraUri + 'flat_lens_shading'"
|
||||||
|
:submit-label="'Disable flat field correction'"
|
||||||
|
@response="onRecalibrateResponse"
|
||||||
|
@error="modalError"
|
||||||
>
|
>
|
||||||
Disable flat field correction
|
</taskSubmitter>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
<div v-if="LstDownloadEnabled">
|
v-show="showExtraSettings"
|
||||||
<a
|
v-if="'reset_lens_shading' in actions"
|
||||||
class="uk-button uk-button-default uk-width-large uk-margin-small-top uk-align-center"
|
class="uk-child-width-expand"
|
||||||
:href="LstDownloadUri"
|
> <taskSubmitter
|
||||||
download
|
:can-terminate="false"
|
||||||
>Download Lens-Shading Table</a
|
:requires-confirmation="false"
|
||||||
|
:submit-url="cameraUri + 'reset_lens_shading'"
|
||||||
|
:submit-label="'Reset flat field correction'"
|
||||||
|
@response="onRecalibrateResponse"
|
||||||
|
@error="modalError"
|
||||||
>
|
>
|
||||||
|
</taskSubmitter>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -100,66 +111,35 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
cameraUri: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
recalibrationLinks: {},
|
actions: {},
|
||||||
isCalibrating: false,
|
isCalibrating: false,
|
||||||
LstDownloadEnabled: false
|
LstDownloadEnabled: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
pluginsUri: function() {
|
|
||||||
return `${this.$store.getters.baseUri}/api/v2/extensions`;
|
|
||||||
},
|
|
||||||
LstDownloadUri: function() {
|
|
||||||
return `${this.$store.getters.baseUri}/api/v2/instrument/camera/lst`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.updateRecalibrationLinks();
|
this.updateActions();
|
||||||
this.checkLstDownload();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateRecalibrationLinks: function() {
|
updateActions: async function() {
|
||||||
axios
|
try{
|
||||||
.get(this.pluginsUri) // Get a list of plugins
|
let response = await axios.get(this.cameraUri) // Get the thing description
|
||||||
.then(response => {
|
let td = response.data
|
||||||
var plugins = response.data;
|
this.actions = td.actions
|
||||||
var foundExtension = plugins.find(
|
console.log("full auto calibrate in actions", 'full_auto_calibrate' in this.actions)
|
||||||
e => e.title === "org.openflexure.calibration.picamera"
|
} catch(error) {
|
||||||
);
|
this.modalError(error) // Let mixin handle error
|
||||||
// if AutocalibrationPlugin is enabled
|
}
|
||||||
if (foundExtension) {
|
|
||||||
// Get plugin action link
|
|
||||||
this.recalibrationLinks = foundExtension.links;
|
|
||||||
} else {
|
|
||||||
this.recalibrationLinks = {};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.modalError(error); // Let mixin handle error
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
checkLstDownload: function() {
|
|
||||||
axios
|
|
||||||
.get(this.LstDownloadUri) // Get a list of plugins
|
|
||||||
.then(response => {
|
|
||||||
if (response.status === 200) {
|
|
||||||
this.LstDownloadEnabled = true;
|
|
||||||
} else {
|
|
||||||
this.LstDownloadEnabled = false;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.modalError(error); // Let mixin handle error
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRecalibrateResponse: function() {
|
onRecalibrateResponse: function() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue