mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-01 02:41:42 +00:00
Add colored shape to the UI (#258)
* Fixup colored shape backend code * More colored shape stuff * Start adding shape change to drawing * Mostly works! * Add powercell image for shape test mode * Make super-duper-sure to release stuff Fixes colored shape leak * Move approx poly dp into Contour * Adjust epsilon threshold * Add dialog to change pipeline type * Run spotless * Make yes red :> * Move "no" button * Fix duplication/deletion name logic and switching * Fix compilation errors from rebase * Update VisionSourceManager.java * Update type dialog, remove duplicate popup The dropdown still switches even if the user says "no" tho Co-authored-by: Banks Troutman <btrout.dhrs@gmail.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
:value="localValue"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:disabled="disabled"
|
||||
hide-details
|
||||
class="align-center"
|
||||
dark
|
||||
@@ -34,7 +35,7 @@
|
||||
hide-details
|
||||
single-line
|
||||
type="number"
|
||||
style="width: 50px"
|
||||
style="width: 60px"
|
||||
:step="step"
|
||||
@input="handleChange"
|
||||
@focus="prependFocused = true"
|
||||
@@ -53,7 +54,7 @@
|
||||
hide-details
|
||||
single-line
|
||||
type="number"
|
||||
style="width: 50px"
|
||||
style="width: 60px"
|
||||
:step="step"
|
||||
@input="handleChange"
|
||||
@focus="appendFocused = true"
|
||||
@@ -75,7 +76,7 @@ export default {
|
||||
TooltippedLabel,
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ["name", "min", "max", "value", "step", "tooltip"],
|
||||
props: ["name", "min", "max", "value", "step", "tooltip", "disabled"],
|
||||
data() {
|
||||
return {
|
||||
prependFocused: false,
|
||||
|
||||
@@ -88,7 +88,11 @@
|
||||
menu
|
||||
</v-icon>
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list
|
||||
dark
|
||||
dense
|
||||
color="primary"
|
||||
>
|
||||
<v-list-item @click="toPipelineNameChange">
|
||||
<v-list-item-title>
|
||||
<CVicon
|
||||
@@ -119,7 +123,7 @@
|
||||
/>
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="openDuplicateDialog">
|
||||
<v-list-item @click="duplicatePipeline">
|
||||
<v-list-item-title>
|
||||
<CVicon
|
||||
color="#c5c5c5"
|
||||
@@ -132,66 +136,51 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col
|
||||
v-if="currentPipelineType >= 0"
|
||||
cols="10"
|
||||
md="5"
|
||||
lg="10"
|
||||
class="pt-0 pb-0 pl-6 ml-16"
|
||||
>
|
||||
<CVselect
|
||||
v-model="currentPipelineType"
|
||||
name="Type"
|
||||
:list="['Reflective', 'Shape']"
|
||||
@input="e => showTypeDialog(e)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<!--pipeline duplicate dialog-->
|
||||
<v-dialog
|
||||
v-model="duplicateDialog"
|
||||
dark
|
||||
width="500"
|
||||
height="357"
|
||||
>
|
||||
<v-card dark>
|
||||
<v-card-title
|
||||
class="headline"
|
||||
primary-title
|
||||
>
|
||||
Duplicate Pipeline
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<CVselect
|
||||
v-model="pipeIndexToDuplicate"
|
||||
name="Pipeline"
|
||||
:list="$store.getters.pipelineList"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="#ffd843"
|
||||
@click="duplicatePipeline"
|
||||
>
|
||||
Duplicate
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
@click="closeDuplicateDialog"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!--pipeline naming dialog-->
|
||||
<v-dialog
|
||||
v-model="namingDialog"
|
||||
dark
|
||||
persistent
|
||||
width="500"
|
||||
height="357"
|
||||
>
|
||||
<v-card dark>
|
||||
<v-card
|
||||
dark
|
||||
color="primary"
|
||||
>
|
||||
<v-card-title
|
||||
class="headline"
|
||||
primary-title
|
||||
>
|
||||
Pipeline Name
|
||||
{{ isPipelineNameEdit ? "Edit Pipeline Name" : "Create Pipeline" }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<CVinput
|
||||
v-model="newPipelineName"
|
||||
name="Pipeline"
|
||||
:error-message="checkPipelineName"
|
||||
@Enter="savePipelineNameChange"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="newPipelineType"
|
||||
name="Pipeline Type"
|
||||
:list="['Reflective', 'Shape']"
|
||||
:disabled="isPipelineNameEdit"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
@@ -213,161 +202,205 @@
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<v-dialog
|
||||
v-model="showPipeTypeDialog"
|
||||
width="600"
|
||||
>
|
||||
<v-card
|
||||
color="primary"
|
||||
dark
|
||||
>
|
||||
<v-card-title>Change Pipeline Type</v-card-title>
|
||||
<v-card-text>
|
||||
Changing the type of this pipeline will erase the current pipeline's settings and replace it with a new {{ ['Reflective', 'Shape'][proposedPipelineType] }} pipeline. <b class="red--text format_bold">You will lose all settings for the pipeline
|
||||
"{{ ($store.getters.isDriverMode ? ['Driver Mode'] : []).concat($store.getters.pipelineList)[currentPipelineIndex] }}."</b> Are you sure you want to do this?
|
||||
<v-row
|
||||
class="mt-6"
|
||||
style="display: flex; align-items: center; justify-content: center"
|
||||
align="center"
|
||||
>
|
||||
<v-btn
|
||||
class="mr-3"
|
||||
color="red"
|
||||
width="250"
|
||||
@click="e => changePipeType(true)"
|
||||
>
|
||||
Yes, replace this pipeline
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="ml-10"
|
||||
color="secondary"
|
||||
width="250"
|
||||
@click="e => changePipeType(false)"
|
||||
>
|
||||
No, take me back
|
||||
</v-btn>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CVicon from '../common/cv-icon'
|
||||
import CVselect from '../common/cv-select'
|
||||
import CVinput from '../common/cv-input'
|
||||
|
||||
export default {
|
||||
name: "CameraAndPipelineSelect",
|
||||
components: {
|
||||
CVicon,
|
||||
CVselect,
|
||||
CVinput
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
re: RegExp("^[A-Za-z0-9 \\-)(]*[A-Za-z0-9][A-Za-z0-9 \\-)(.]*$"),
|
||||
isCameraNameEdit: false,
|
||||
newCameraName: "",
|
||||
cameraNameError: "",
|
||||
isPipelineNameEdit: false,
|
||||
namingDialog: false,
|
||||
newPipelineName: "",
|
||||
duplicateDialog: false,
|
||||
pipeIndexToDuplicate: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
checkCameraName() {
|
||||
if (this.newCameraName !== this.$store.getters.cameraList[this.currentCameraIndex]) {
|
||||
if (this.re.test(this.newCameraName)) {
|
||||
for (let cam in this.cameraList) {
|
||||
if (this.cameraList.hasOwnProperty(cam)) {
|
||||
if (this.newCameraName === this.cameraList[cam]) {
|
||||
return "A camera by that name already Exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "A camera name can only contain letters, numbers and spaces"
|
||||
}
|
||||
}
|
||||
return "";
|
||||
},
|
||||
checkPipelineName() {
|
||||
if (this.newPipelineName !== this.$store.getters.pipelineList[this.currentPipelineIndex - 1] || this.isPipelineNameEdit === false) {
|
||||
if (this.re.test(this.newPipelineName)) {
|
||||
for (let pipe in this.$store.getters.pipelineList) {
|
||||
if (this.$store.getters.pipelineList.hasOwnProperty(pipe)) {
|
||||
if (this.newPipelineName === this.$store.getters.pipelineList[pipe]) {
|
||||
return "A pipeline with this name already exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "A pipeline name can only contain letters, numbers, and spaces"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
},
|
||||
currentCameraIndex: {
|
||||
get() {
|
||||
return this.$store.getters.currentCameraIndex;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('currentCameraIndex', value);
|
||||
}
|
||||
},
|
||||
currentPipelineIndex: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineIndex + (this.$store.getters.isDriverMode ? 1 : 0);
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('currentPipelineIndex', value - (this.$store.getters.isDriverMode ? 1 : 0));
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeCameraName() {
|
||||
this.newCameraName = this.$store.getters.cameraList[this.currentCameraIndex];
|
||||
this.isCameraNameEdit = true;
|
||||
},
|
||||
saveCameraNameChange() {
|
||||
if (this.checkCameraName === "") {
|
||||
// this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
||||
this.axios.post('http://' + this.$address + '/api/setCameraNickname',
|
||||
{name: this.newCameraName, cameraIndex: this.$store.getters.currentCameraIndex})
|
||||
// eslint-disable-next-line
|
||||
.then(r => {
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
.catch(e => {
|
||||
console.log("HTTP error while changing camera name " + e);
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
this.discardCameraNameChange();
|
||||
}
|
||||
},
|
||||
discardCameraNameChange() {
|
||||
this.isCameraNameEdit = false;
|
||||
this.newCameraName = "";
|
||||
},
|
||||
toPipelineNameChange() {
|
||||
this.newPipelineName = this.$store.getters.pipelineList[this.currentPipelineIndex - 1];
|
||||
this.isPipelineNameEdit = true;
|
||||
this.namingDialog = true;
|
||||
},
|
||||
toCreatePipeline() {
|
||||
this.newPipelineName = "New Pipeline";
|
||||
this.isPipelineNameEdit = false;
|
||||
this.namingDialog = true;
|
||||
},
|
||||
openDuplicateDialog() {
|
||||
this.pipeIndexToDuplicate = this.currentPipelineIndex - 1;
|
||||
this.duplicateDialog = true;
|
||||
},
|
||||
deleteCurrentPipeline() {
|
||||
if (this.$store.getters.pipelineList.length > 1) {
|
||||
this.handleInputWithIndex('deleteCurrentPipeline', {});
|
||||
} else {
|
||||
this.snackbar = true;
|
||||
}
|
||||
},
|
||||
savePipelineNameChange() {
|
||||
if (this.checkPipelineName === "") {
|
||||
if (this.isPipelineNameEdit) {
|
||||
this.handleInputWithIndex("changePipelineName", this.newPipelineName);
|
||||
} else {
|
||||
this.handleInputWithIndex("addNewPipeline", this.newPipelineName);
|
||||
}
|
||||
this.discardPipelineNameChange();
|
||||
}
|
||||
},
|
||||
duplicatePipeline() {
|
||||
// if (!this.anotherCamera) {
|
||||
// this.pipelineDuplicate.camera = -1
|
||||
// }
|
||||
this.handleInputWithIndex("duplicatePipeline", this.pipeIndexToDuplicate);
|
||||
// this.axios.post("http://" + this.$address + "/api/vision/duplicate", this.pipeIndexToDuplicate);
|
||||
|
||||
this.closeDuplicateDialog();
|
||||
},
|
||||
closeDuplicateDialog() {
|
||||
this.duplicateDialog = false;
|
||||
this.pipeIndexToDuplicate = undefined;
|
||||
},
|
||||
discardPipelineNameChange() {
|
||||
this.namingDialog = false;
|
||||
this.isPipelineNameEdit = false;
|
||||
this.newPipelineName = "";
|
||||
},
|
||||
}
|
||||
import CVicon from '../common/cv-icon'
|
||||
import CVselect from '../common/cv-select'
|
||||
import CVinput from '../common/cv-input'
|
||||
|
||||
export default {
|
||||
name: "CameraAndPipelineSelect",
|
||||
components: {
|
||||
CVicon,
|
||||
CVselect,
|
||||
CVinput
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
re: RegExp("^[A-Za-z0-9 \\-)(]*[A-Za-z0-9][A-Za-z0-9 \\-)(.]*$"),
|
||||
isCameraNameEdit: false,
|
||||
newCameraName: "",
|
||||
cameraNameError: "",
|
||||
isPipelineNameEdit: false,
|
||||
namingDialog: false,
|
||||
newPipelineName: "",
|
||||
newPipelineType: 0,
|
||||
duplicateDialog: false,
|
||||
showPipeTypeDialog: false,
|
||||
proposedPipelineType : 0,
|
||||
pipeIndexToDuplicate: undefined
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
checkCameraName() {
|
||||
if (this.newCameraName !== this.$store.getters.cameraList[this.currentCameraIndex]) {
|
||||
if (this.re.test(this.newCameraName)) {
|
||||
for (let cam in this.cameraList) {
|
||||
if (this.cameraList.hasOwnProperty(cam)) {
|
||||
if (this.newCameraName === this.cameraList[cam]) {
|
||||
return "A camera by that name already Exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "A camera name can only contain letters, numbers and spaces"
|
||||
}
|
||||
}
|
||||
return "";
|
||||
},
|
||||
checkPipelineName() {
|
||||
if (this.newPipelineName !== this.$store.getters.pipelineList[this.currentPipelineIndex - 1] || this.isPipelineNameEdit === false) {
|
||||
if (this.re.test(this.newPipelineName)) {
|
||||
for (let pipe in this.$store.getters.pipelineList) {
|
||||
if (this.$store.getters.pipelineList.hasOwnProperty(pipe)) {
|
||||
if (this.newPipelineName === this.$store.getters.pipelineList[pipe]) {
|
||||
return "A pipeline with this name already exists"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "A pipeline name can only contain letters, numbers, and spaces"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
},
|
||||
currentCameraIndex: {
|
||||
get() {
|
||||
return this.$store.getters.currentCameraIndex;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('currentCameraIndex', value);
|
||||
}
|
||||
},
|
||||
currentPipelineIndex: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineIndex + (this.$store.getters.isDriverMode ? 1 : 0);
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('currentPipelineIndex', value - (this.$store.getters.isDriverMode ? 1 : 0));
|
||||
}
|
||||
},
|
||||
currentPipelineType: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.pipelineType - 2;
|
||||
},
|
||||
set(value) {
|
||||
value; // nop, since we have the dialog for this
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTypeDialog(idx) {
|
||||
// Only show the dialog if it's a new type
|
||||
this.showPipeTypeDialog = idx !== this.currentPipelineType;
|
||||
this.proposedPipelineType = idx;
|
||||
},
|
||||
changePipeType(actuallyChange) {
|
||||
const newIdx = actuallyChange ? this.proposedPipelineType : this.currentPipelineType
|
||||
this.handleInputWithIndex('pipelineType', newIdx);
|
||||
this.showPipeTypeDialog = false;
|
||||
},
|
||||
changeCameraName() {
|
||||
this.newCameraName = this.$store.getters.cameraList[this.currentCameraIndex];
|
||||
this.isCameraNameEdit = true;
|
||||
},
|
||||
saveCameraNameChange() {
|
||||
if (this.checkCameraName === "") {
|
||||
// this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
||||
this.axios.post('http://' + this.$address + '/api/setCameraNickname',
|
||||
{name: this.newCameraName, cameraIndex: this.$store.getters.currentCameraIndex})
|
||||
// eslint-disable-next-line
|
||||
.then(r => {
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
.catch(e => {
|
||||
console.log("HTTP error while changing camera name " + e);
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
this.discardCameraNameChange();
|
||||
}
|
||||
},
|
||||
discardCameraNameChange() {
|
||||
this.isCameraNameEdit = false;
|
||||
this.newCameraName = "";
|
||||
},
|
||||
toPipelineNameChange() {
|
||||
this.newPipelineName = this.$store.getters.pipelineList[this.currentPipelineIndex - 1];
|
||||
this.isPipelineNameEdit = true;
|
||||
this.namingDialog = true;
|
||||
},
|
||||
toCreatePipeline() {
|
||||
this.newPipelineName = "New Pipeline";
|
||||
this.isPipelineNameEdit = false;
|
||||
this.namingDialog = true;
|
||||
},
|
||||
deleteCurrentPipeline() {
|
||||
if (this.$store.getters.pipelineList.length > 1) {
|
||||
this.handleInputWithIndex('deleteCurrentPipeline', {});
|
||||
} else {
|
||||
this.snackbar = true;
|
||||
}
|
||||
},
|
||||
savePipelineNameChange() {
|
||||
if (this.checkPipelineName === "") {
|
||||
if (this.isPipelineNameEdit) {
|
||||
this.handleInputWithIndex("changePipelineName", this.newPipelineName);
|
||||
} else {
|
||||
this.handleInputWithIndex("addNewPipeline", [this.newPipelineName, this.newPipelineType]); // 0 for reflective, 1 for colored shpae
|
||||
}
|
||||
this.discardPipelineNameChange();
|
||||
}
|
||||
},
|
||||
duplicatePipeline() {
|
||||
this.handleInputWithIndex("duplicatePipeline", this.currentPipelineIndex);
|
||||
},
|
||||
discardPipelineNameChange() {
|
||||
this.namingDialog = false;
|
||||
this.isPipelineNameEdit = false;
|
||||
this.newPipelineName = "";
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -29,9 +29,11 @@ Vue.use(VueAxios, axios);
|
||||
Vue.prototype.$msgPack = msgPack(true);
|
||||
|
||||
import {dataHandleMixin} from './mixins/global/dataHandleMixin'
|
||||
|
||||
Vue.mixin(dataHandleMixin);
|
||||
|
||||
import {stateMixin} from './mixins/global/stateMixin'
|
||||
Vue.mixin(stateMixin);
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
|
||||
10
photon-client/src/mixins/global/stateMixin.js
Normal file
10
photon-client/src/mixins/global/stateMixin.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export const stateMixin = {
|
||||
methods: {
|
||||
currentPipelineType() {
|
||||
return this.$store.getters.pipelineType
|
||||
},
|
||||
currentPipelineSettings() {
|
||||
return this.$store.getters.currentPipelineSettings
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -42,7 +42,7 @@ export default new Vuex.Store({
|
||||
isFovConfigurable: true,
|
||||
calibrated: false,
|
||||
currentPipelineSettings: {
|
||||
pipelineType: 2, // One of "driver", "reflective", "shape"
|
||||
pipelineType: 2, // One of "calib", "driver", "reflective", "shape"
|
||||
// 2 is reflective
|
||||
|
||||
// Settings that apply to all pipeline types
|
||||
@@ -245,5 +245,6 @@ export default new Vuex.Store({
|
||||
},
|
||||
pipelineList: state => state.cameraSettings[state.currentCameraIndex].pipelineNicknames,
|
||||
calibrationList: state => state.cameraSettings[state.currentCameraIndex].calibrations,
|
||||
pipelineType: state => state.cameraSettings[state.currentCameraIndex].currentPipelineSettings.pipelineType
|
||||
}
|
||||
})
|
||||
@@ -1,160 +1,286 @@
|
||||
<template>
|
||||
<div>
|
||||
<CVrangeSlider
|
||||
v-model="contourArea"
|
||||
name="Area"
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourArea')"
|
||||
@rollback="e=> rollback('contourArea',e)"
|
||||
v-model="contourArea"
|
||||
name="Area"
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourArea')"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="contourRatio"
|
||||
name="Ratio (W/H)"
|
||||
tooltip="Min and max ratio between the width and height of a contour's bounding rectangle"
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourRatio')"
|
||||
@rollback="e=> rollback('contourRatio',e)"
|
||||
v-model="contourRatio"
|
||||
v-if="currentPipelineType() !== 3"
|
||||
name="Ratio (W/H)"
|
||||
tooltip="Min and max ratio between the width and height of a contour's bounding rectangle"
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.1"
|
||||
@input="handlePipelineData('contourRatio')"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="contourFullness"
|
||||
name="Fullness"
|
||||
tooltip="Min and max ratio between a contour's area and its bounding rectangle"
|
||||
min="0"
|
||||
max="100"
|
||||
@input="handlePipelineData('contourFullness')"
|
||||
@rollback="e=> rollback('contourFullness',e)"
|
||||
v-model="contourFullness"
|
||||
v-if="currentPipelineType() !== 3"
|
||||
name="Fullness"
|
||||
tooltip="Min and max ratio between a contour's area and its bounding rectangle"
|
||||
min="0"
|
||||
max="100"
|
||||
@input="handlePipelineData('contourFullness')"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="contourPerimeter"
|
||||
v-if="currentPipelineType() === 3"
|
||||
name="Perimeter"
|
||||
tooltip="Min and max perimeter of the shape, in pixels"
|
||||
min="0"
|
||||
max="4000"
|
||||
@input="handlePipelineData('contourPerimeter')"
|
||||
/>
|
||||
<CVslider
|
||||
v-model="contourSpecklePercentage"
|
||||
name="Speckle Rejection"
|
||||
tooltip="Rejects contours whose average area is less than the given percentage of the average area of all the other contours"
|
||||
min="0"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('contourSpecklePercentage')"
|
||||
@rollback="e=> rollback('contourSpecklePercentage',e)"
|
||||
v-model="contourSpecklePercentage"
|
||||
name="Speckle Rejection"
|
||||
tooltip="Rejects contours whose average area is less than the given percentage of the average area of all the other contours"
|
||||
min="0"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('contourSpecklePercentage')"
|
||||
/>
|
||||
<template v-if="currentPipelineType() !== 3">
|
||||
<CVselect
|
||||
v-model="contourGroupingMode"
|
||||
name="Target Grouping"
|
||||
tooltip="Whether or not every two targets are paired with each other (good for e.g. 2019 targets)"
|
||||
:select-cols="largeBox"
|
||||
:list="['Single','Dual']"
|
||||
@input="handlePipelineData('contourGroupingMode')"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourIntersection"
|
||||
name="Target Intersection"
|
||||
tooltip="If target grouping is in dual mode it will use this dropdown to decide how targets are grouped with adjacent targets"
|
||||
:select-cols="largeBox"
|
||||
:list="['None','Up','Down','Left','Right']"
|
||||
:disabled="contourGroupingMode === 0"
|
||||
@input="handlePipelineData('contourIntersection')"
|
||||
/>
|
||||
</template>
|
||||
<!-- If we arent not a shape, we are a shape-->
|
||||
<template v-else>
|
||||
<v-divider class="mt-3"/>
|
||||
<CVselect
|
||||
v-model="contourShape"
|
||||
name="Target Shape"
|
||||
tooltip="The shape of targets to look for"
|
||||
:select-cols="largeBox"
|
||||
:list="['Circle', 'Polygon', 'Triangle', 'Quadrilateral']"
|
||||
@input="handlePipelineData('contourShape')"
|
||||
/>
|
||||
|
||||
<!-- Accuracy % is only for polygons-->
|
||||
<CVslider
|
||||
v-model="accuracyPercentage"
|
||||
:disabled="currentPipelineSettings().contourShape < 1"
|
||||
name="Shape Simplification"
|
||||
tooltip="How much we should simply the input contour before checking how many sides it has"
|
||||
min="0"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('accuracyPercentage')"
|
||||
/>
|
||||
<!-- Similarly, the threshold is only for circles -->
|
||||
<CVslider
|
||||
v-model="circleDetectThreshold"
|
||||
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||
name="Circle match distance"
|
||||
tooltip="How close the centroid of a contour must be to the center of a circle in order for them to be matched"
|
||||
min="1"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('circleDetectThreshold')"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="contourRadius"
|
||||
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||
name="Radius"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
@input="handlePipelineData('contourRadius')"
|
||||
/>
|
||||
<CVslider
|
||||
v-model="maxCannyThresh"
|
||||
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||
name="Max Canny Threshold"
|
||||
min="1"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('maxCannyThresh')"
|
||||
/>
|
||||
<CVslider
|
||||
v-model="circleAccuracy"
|
||||
:disabled="currentPipelineSettings().contourShape !== 0"
|
||||
name="Circle Accuracy"
|
||||
min="0"
|
||||
max="100"
|
||||
:slider-cols="largeBox"
|
||||
@input="handlePipelineData('circleAccuracy')"
|
||||
/>
|
||||
<v-divider class="mt-3"/>
|
||||
</template>
|
||||
<CVselect
|
||||
v-model="contourGroupingMode"
|
||||
name="Target Grouping"
|
||||
tooltip="Whether or not every two targets are paired with each other (good for e.g. 2019 targets)"
|
||||
:select-cols="largeBox"
|
||||
:list="['Single','Dual']"
|
||||
@input="handlePipelineData('contourGroupingMode')"
|
||||
@rollback="e=> rollback('contourGroupingMode',e)"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourIntersection"
|
||||
name="Target Intersection"
|
||||
tooltip="If target grouping is in dual mode it will use this dropdown to decide how targets are grouped with adjacent targets"
|
||||
:select-cols="largeBox"
|
||||
:list="['None','Up','Down','Left','Right']"
|
||||
:disabled="contourGroupingMode === 0"
|
||||
@input="handlePipelineData('contourIntersection')"
|
||||
@rollback="e=> rollback('contourIntersection',e)"
|
||||
/>
|
||||
<CVselect
|
||||
v-model="contourSortMode"
|
||||
name="Target Sort"
|
||||
tooltip="Chooses the sorting mode used to determine the 'best' targets to provide to user code"
|
||||
:select-cols="largeBox"
|
||||
:list="['Largest','Smallest','Highest','Lowest','Rightmost','Leftmost','Centermost']"
|
||||
@input="handlePipelineData('contourSortMode')"
|
||||
@rollback="e => rollback('contourSortMode', e)"
|
||||
v-model="contourSortMode"
|
||||
name="Target Sort"
|
||||
tooltip="Chooses the sorting mode used to determine the 'best' targets to provide to user code"
|
||||
:select-cols="largeBox"
|
||||
:list="['Largest','Smallest','Highest','Lowest','Rightmost','Leftmost','Centermost']"
|
||||
@input="handlePipelineData('contourSortMode')"
|
||||
@rollback="e => rollback('contourSortMode', e)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||
import CVselect from '../../components/common/cv-select'
|
||||
import CVslider from '../../components/common/cv-slider'
|
||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||
import CVselect from '../../components/common/cv-select'
|
||||
import CVslider from '../../components/common/cv-slider'
|
||||
|
||||
export default {
|
||||
name: 'Contours',
|
||||
components: {
|
||||
CVrangeSlider,
|
||||
CVselect,
|
||||
CVslider
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['value'],
|
||||
export default {
|
||||
name: 'Contours',
|
||||
components: {
|
||||
CVrangeSlider,
|
||||
CVselect,
|
||||
CVslider
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['value'],
|
||||
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
largeBox: {
|
||||
get() {
|
||||
// Sliders and selectors should be fuller width if we're on screen size medium and
|
||||
// up and either not in compact mode (because the tab will be 100% screen width),
|
||||
// or in driver mode (where the card will also be 100% screen width).
|
||||
return this.$vuetify.breakpoint.mdAndUp && (!this.$store.state.compactMode || this.$store.getters.isDriverMode) ? 10 : 8;
|
||||
}
|
||||
},
|
||||
contourArea: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourArea
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourArea": val});
|
||||
}
|
||||
},
|
||||
contourRatio: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourRatio
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
||||
}
|
||||
},
|
||||
contourFullness: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourFullness
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourFullness": val});
|
||||
}
|
||||
},
|
||||
contourSpecklePercentage: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourSpecklePercentage
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourSpecklePercentage": val});
|
||||
}
|
||||
},
|
||||
contourGroupingMode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourGroupingMode
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourGroupingMode": val});
|
||||
}
|
||||
},
|
||||
contourSortMode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourSortMode
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourSortMode": val});
|
||||
}
|
||||
},
|
||||
contourIntersection: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourIntersection
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourIntersection": val});
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
largeBox: {
|
||||
get() {
|
||||
// Sliders and selectors should be fuller width if we're on screen size medium and
|
||||
// up and either not in compact mode (because the tab will be 100% screen width),
|
||||
// or in driver mode (where the card will also be 100% screen width).
|
||||
return this.$vuetify.breakpoint.mdAndUp && (!this.$store.state.compactMode || this.$store.getters.isDriverMode) ? 10 : 8;
|
||||
}
|
||||
},
|
||||
contourArea: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourArea
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourArea": val});
|
||||
}
|
||||
},
|
||||
contourRatio: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourRatio
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourRatio": val});
|
||||
}
|
||||
},
|
||||
contourFullness: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourFullness
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourFullness": val});
|
||||
}
|
||||
},
|
||||
contourPerimeter: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourPerimeter
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourPerimeter": val});
|
||||
}
|
||||
},
|
||||
contourSpecklePercentage: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourSpecklePercentage
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourSpecklePercentage": val});
|
||||
}
|
||||
},
|
||||
contourGroupingMode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourGroupingMode
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourGroupingMode": val});
|
||||
}
|
||||
},
|
||||
contourSortMode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourSortMode
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourSortMode": val});
|
||||
}
|
||||
},
|
||||
contourShape: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourShape
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourShape": val});
|
||||
}
|
||||
},
|
||||
contourIntersection: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourIntersection
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourIntersection": val});
|
||||
}
|
||||
},
|
||||
accuracyPercentage: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.accuracyPercentage
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"accuracyPercentage": val});
|
||||
}
|
||||
},
|
||||
contourRadius: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.contourRadius
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"contourRadius": val});
|
||||
}
|
||||
},
|
||||
circleDetectThreshold: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.circleDetectThreshold
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"circleDetectThreshold": val});
|
||||
}
|
||||
},
|
||||
maxCannyThresh: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.maxCannyThresh
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"maxCannyThresh": val});
|
||||
}
|
||||
},
|
||||
circleAccuracy: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.circleAccuracy
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"circleAccuracy": val});
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="" scoped>
|
||||
|
||||
@@ -1,48 +1,66 @@
|
||||
<template>
|
||||
<div>
|
||||
<CVrangeSlider
|
||||
v-model="hsvHue"
|
||||
name="Hue"
|
||||
tooltip="Describes color"
|
||||
:min="0"
|
||||
:max="180"
|
||||
@input="handlePipelineData('hsvHue')"
|
||||
@rollback="e => rollback('hue',e)"
|
||||
v-model="hsvHue"
|
||||
name="Hue"
|
||||
tooltip="Describes color"
|
||||
:min="0"
|
||||
:max="180"
|
||||
@input="handlePipelineData('hsvHue')"
|
||||
@rollback="e => rollback('hue',e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="hsvSaturation"
|
||||
name="Saturation"
|
||||
tooltip="Describes colorfulness; the smaller this value the 'whiter' the color becomes"
|
||||
:min="0"
|
||||
:max="255"
|
||||
@input="handlePipelineData('hsvSaturation')"
|
||||
@rollback="e => rollback('saturation',e)"
|
||||
v-model="hsvSaturation"
|
||||
name="Saturation"
|
||||
tooltip="Describes colorfulness; the smaller this value the 'whiter' the color becomes"
|
||||
:min="0"
|
||||
:max="255"
|
||||
@input="handlePipelineData('hsvSaturation')"
|
||||
@rollback="e => rollback('saturation',e)"
|
||||
/>
|
||||
<CVrangeSlider
|
||||
v-model="hsvValue"
|
||||
name="Value"
|
||||
tooltip="Describes lightness; the smaller this value the 'blacker' the color becomes"
|
||||
:min="0"
|
||||
:max="255"
|
||||
@input="handlePipelineData('hsvValue')"
|
||||
@rollback="e => rollback('value',e)"
|
||||
v-model="hsvValue"
|
||||
name="Value"
|
||||
tooltip="Describes lightness; the smaller this value the 'blacker' the color becomes"
|
||||
:min="0"
|
||||
:max="255"
|
||||
@input="handlePipelineData('hsvValue')"
|
||||
@rollback="e => rollback('value',e)"
|
||||
/>
|
||||
<template v-if="this.currentPipelineType() === 3">
|
||||
<CVSwitch
|
||||
v-model="erode"
|
||||
name="Erode"
|
||||
tooltip="Removes pixels around the edges of white areas in the thresholded image"
|
||||
@input="handlePipelineData('erode')"
|
||||
@rollback="e => rollback('erode',e)"
|
||||
/>
|
||||
<CVSwitch
|
||||
v-model="dilate"
|
||||
class="mb-0"
|
||||
name="Dilate"
|
||||
tooltip="Adds pixels around the edges of white areas in the thresholded image"
|
||||
@input="handlePipelineData('dilate')"
|
||||
@rollback="e => rollback('dilate',e)"
|
||||
/>
|
||||
</template>
|
||||
<v-divider class="mb-3 mt-3"/>
|
||||
<div class="pt-3 white--text">
|
||||
Color Picker
|
||||
</div>
|
||||
<v-divider
|
||||
class="mt-3"
|
||||
class="mt-3"
|
||||
/>
|
||||
<v-row
|
||||
justify="center"
|
||||
class="mt-3 mb-3"
|
||||
justify="center"
|
||||
class="mt-3 mb-3"
|
||||
>
|
||||
<template v-if="!$store.state.colorPicking">
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(3)"
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(3)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-minus
|
||||
@@ -50,10 +68,10 @@
|
||||
Shrink Range
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(1)"
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(1)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-plus-minus
|
||||
@@ -61,10 +79,10 @@
|
||||
Set To Average
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(2)"
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="setFunction(2)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-plus
|
||||
@@ -74,11 +92,11 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
style="width: 30%;"
|
||||
small
|
||||
@click="setFunction(0)"
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
style="width: 30%;"
|
||||
small
|
||||
@click="setFunction(0)"
|
||||
>
|
||||
Cancel
|
||||
</v-btn>
|
||||
@@ -88,112 +106,130 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||
|
||||
export default {
|
||||
name: 'Threshold',
|
||||
components: {
|
||||
CVrangeSlider
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['value'],
|
||||
data() {
|
||||
return {
|
||||
currentFunction: undefined,
|
||||
colorPicker: undefined,
|
||||
showThresholdState: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hsvHue: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvHue
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvHue": val})
|
||||
}
|
||||
},
|
||||
hsvSaturation: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvSaturation
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvSaturation": val})
|
||||
}
|
||||
},
|
||||
hsvValue: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvValue
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvValue": val})
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
const self = this;
|
||||
this.colorPicker = require('../../plugins/ColorPicker').default;
|
||||
this.$nextTick(() => {
|
||||
self.colorPicker.initColorPicker();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
onClick(event) {
|
||||
if (this.currentFunction !== undefined) {
|
||||
this.colorPicker.initColorPicker();
|
||||
import CVrangeSlider from '../../components/common/cv-range-slider'
|
||||
import CVSwitch from "@/components/common/cv-switch";
|
||||
|
||||
let s = this.$store.getters.currentPipelineSettings;
|
||||
let hsvArray = this.colorPicker.colorPickerClick(event, this.currentFunction,
|
||||
[
|
||||
[s.hsvHue[0], s.hsvSaturation[0], s.hsvValue[0]],
|
||||
[s.hsvHue[1], s.hsvSaturation[1], s.hsvValue[1]]
|
||||
].map(hsv => hsv.map(it => it || 0)));
|
||||
// That `map` calls are to make sure that we don't let any undefined/null values slip in
|
||||
this.currentFunction = undefined;
|
||||
this.$store.state.colorPicking = false;
|
||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||
|
||||
s.hsvHue = [hsvArray[0][0], hsvArray[1][0]];
|
||||
s.hsvSaturation = [hsvArray[0][1], hsvArray[1][1]];
|
||||
s.hsvValue = [hsvArray[0][2], hsvArray[1][2]];
|
||||
|
||||
let msg = this.$msgPack.encode({
|
||||
"changePipelineSetting": {
|
||||
'hsvHue': s.hsvHue,
|
||||
'hsvSaturation': s.hsvSaturation,
|
||||
'hsvValue': s.hsvValue,
|
||||
'cameraIndex': this.$store.state.currentCameraIndex
|
||||
}
|
||||
});
|
||||
this.$socket.send(msg);
|
||||
this.$emit('update');
|
||||
}
|
||||
},
|
||||
setFunction(index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this.currentFunction = undefined;
|
||||
this.$store.state.colorPicking = false;
|
||||
|
||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||
return;
|
||||
case 1:
|
||||
this.currentFunction = this.colorPicker.eyeDrop;
|
||||
break;
|
||||
case 2:
|
||||
this.currentFunction = this.colorPicker.expand;
|
||||
break;
|
||||
case 3:
|
||||
this.currentFunction = this.colorPicker.shrink;
|
||||
break;
|
||||
}
|
||||
this.$store.state.colorPicking = true;
|
||||
|
||||
this.handlePipelineUpdate("outputShouldDraw", false);
|
||||
this.$store.commit("mutatePipeline", {"inputShouldShow": true});
|
||||
this.handlePipelineUpdate("inputShouldShow", true);
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'Threshold',
|
||||
components: {
|
||||
CVSwitch,
|
||||
CVrangeSlider
|
||||
},
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['value'],
|
||||
data() {
|
||||
return {
|
||||
currentFunction: undefined,
|
||||
colorPicker: undefined,
|
||||
showThresholdState: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hsvHue: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvHue
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvHue": val})
|
||||
}
|
||||
},
|
||||
hsvSaturation: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvSaturation
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvSaturation": val})
|
||||
}
|
||||
},
|
||||
hsvValue: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.hsvValue
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"hsvValue": val})
|
||||
}
|
||||
},
|
||||
erode: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.erode
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"erode": val});
|
||||
}
|
||||
},
|
||||
dilate: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineSettings.dilate
|
||||
},
|
||||
set(val) {
|
||||
this.$store.commit("mutatePipeline", {"dilate": val});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted: function () {
|
||||
const self = this;
|
||||
this.colorPicker = require('../../plugins/ColorPicker').default;
|
||||
this.$nextTick(() => {
|
||||
self.colorPicker.initColorPicker();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
onClick(event) {
|
||||
if (this.currentFunction !== undefined) {
|
||||
this.colorPicker.initColorPicker();
|
||||
|
||||
let s = this.$store.getters.currentPipelineSettings;
|
||||
let hsvArray = this.colorPicker.colorPickerClick(event, this.currentFunction,
|
||||
[
|
||||
[s.hsvHue[0], s.hsvSaturation[0], s.hsvValue[0]],
|
||||
[s.hsvHue[1], s.hsvSaturation[1], s.hsvValue[1]]
|
||||
].map(hsv => hsv.map(it => it || 0)));
|
||||
// That `map` calls are to make sure that we don't let any undefined/null values slip in
|
||||
this.currentFunction = undefined;
|
||||
this.$store.state.colorPicking = false;
|
||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||
|
||||
s.hsvHue = [hsvArray[0][0], hsvArray[1][0]];
|
||||
s.hsvSaturation = [hsvArray[0][1], hsvArray[1][1]];
|
||||
s.hsvValue = [hsvArray[0][2], hsvArray[1][2]];
|
||||
|
||||
let msg = this.$msgPack.encode({
|
||||
"changePipelineSetting": {
|
||||
'hsvHue': s.hsvHue,
|
||||
'hsvSaturation': s.hsvSaturation,
|
||||
'hsvValue': s.hsvValue,
|
||||
'cameraIndex': this.$store.state.currentCameraIndex
|
||||
}
|
||||
});
|
||||
this.$socket.send(msg);
|
||||
this.$emit('update');
|
||||
}
|
||||
},
|
||||
setFunction(index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
this.currentFunction = undefined;
|
||||
this.$store.state.colorPicking = false;
|
||||
|
||||
this.handlePipelineUpdate("outputShouldDraw", true);
|
||||
return;
|
||||
case 1:
|
||||
this.currentFunction = this.colorPicker.eyeDrop;
|
||||
break;
|
||||
case 2:
|
||||
this.currentFunction = this.colorPicker.expand;
|
||||
break;
|
||||
case 3:
|
||||
this.currentFunction = this.colorPicker.shrink;
|
||||
break;
|
||||
}
|
||||
this.$store.state.colorPicking = true;
|
||||
|
||||
this.handlePipelineUpdate("outputShouldDraw", false);
|
||||
this.$store.commit("mutatePipeline", {"inputShouldShow": true});
|
||||
this.handlePipelineUpdate("inputShouldShow", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user