diff --git a/photon-client/src/App.vue b/photon-client/src/App.vue index a0411a0a0..ecc6b8aec 100644 --- a/photon-client/src/App.vue +++ b/photon-client/src/App.vue @@ -104,7 +104,9 @@ - {{ $store.state.backendConnected ? "Connected" : "Trying to connect..." }} + + {{ $store.state.backendConnected ? "Connected" : "Trying to connect..." }} + @@ -152,7 +154,7 @@ }, data: () => ({ // Used so that we can switch back to the previously selected pipeline after camera calibration - previouslySelectedIndex: null, + previouslySelectedIndex: undefined, timer: undefined, isLogger: false, log: "", @@ -169,9 +171,9 @@ compact: { get() { if (this.$store.state.compactMode === undefined) { - return this.$vuetify.breakpoint.smAndDown; + return this.$vuetify.breakpoint.smAndDown; } else { - return this.$store.state.compactMode || this.$vuetify.breakpoint.smAndDown; + return this.$store.state.compactMode || this.$vuetify.breakpoint.smAndDown; } }, set(value) { @@ -179,7 +181,7 @@ this.$store.commit("compactMode", value); localStorage.setItem("compactMode", value); }, - } + }, }, created() { document.addEventListener("keydown", e => { @@ -210,16 +212,16 @@ } } } catch (error) { - console.error('error: ' + data.data + " , " + error); + console.error('error: ' + JSON.stringify(data.data) + " , " + error); } }; this.$options.sockets.onopen = () => { - this.$store.state.backendConnected = true; + this.$store.state.backendConnected = true; }; let closed = () => { - this.$store.state.backendConnected = false; - } + this.$store.state.backendConnected = false; + }; this.$options.sockets.onclose = closed; this.$options.sockets.onerror = closed; @@ -228,14 +230,15 @@ methods: { handleMessage(key, value) { if (key === "logMessage") { - console.log("[FROM BACKEND]" + value); - this.logMessage(value, 0); + this.logMessage(value["logMessage"], value["logLevel"]); } else if (key === "updatePipelineResult") { this.$store.commit('mutatePipelineResults', value) } else if (this.$store.state.hasOwnProperty(key)) { this.$store.commit(key, value); } else if (this.$store.getters.currentPipelineSettings.hasOwnProperty(key)) { this.$store.commit('mutatePipeline', {[key]: value}); + } else if (this.$store.state.settings.hasOwnProperty(key)) { + this.$store.commit('mutateSettings', {[key]: value}); } else { switch (key) { default: { @@ -259,9 +262,10 @@ this.timer = setInterval(this.saveSettings, 4000); }, logMessage(message, level) { - const colors = ["\u001b[31m", "\u001b[32m", "\u001b[33m", "\u001b[34m"] + const colors = ["\u001B[30m", "\u001B[31m", "\u001B[33m", "\u001B[32m", "\u001B[37m", "\u001B[36m"] const reset = "\u001b[0m" this.log += `${colors[level]}${message}${reset}\n` + console.log(message) }, switchToDriverMode() { this.previouslySelectedIndex = this.$store.getters.currentPipelineIndex; @@ -269,7 +273,7 @@ }, rollbackPipelineIndex() { if (this.previouslySelectedIndex !== null) { - this.handleInputWithIndex('currentPipeline', this.previouslySelectedIndex) + this.handleInputWithIndex('currentPipeline', this.previouslySelectedIndex || 0); } this.previouslySelectedIndex = null; } @@ -278,7 +282,7 @@ \ No newline at end of file diff --git a/photon-client/src/components/common/cv-number-input.vue b/photon-client/src/components/common/cv-number-input.vue index efbbfe43d..7448a7392 100644 --- a/photon-client/src/components/common/cv-number-input.vue +++ b/photon-client/src/components/common/cv-number-input.vue @@ -21,6 +21,7 @@ type="number" style="width: 70px" :step="step" + :disabled="disabled" :rules="rules" /> @@ -37,7 +38,7 @@ TooltippedLabel, }, // eslint-disable-next-line vue/require-prop-types - props: ['name', 'value', 'step', 'labelCols', 'rules', 'tooltip'], + props: ['name', 'value', 'step', 'labelCols', 'rules', 'tooltip', 'disabled'], computed: { localValue: { get() { diff --git a/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue b/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue index db4ca176b..0909827eb 100644 --- a/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue +++ b/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue @@ -148,22 +148,10 @@ - - @@ -249,11 +237,7 @@ namingDialog: false, newPipelineName: "", duplicateDialog: false, - anotherCamera: false, - pipelineDuplicate: { - pipeline: undefined, - camera: -1 - }, + pipeIndexToDuplicate: undefined } }, computed: { @@ -299,10 +283,10 @@ }, currentPipelineIndex: { get() { - return this.$store.getters.currentPipelineIndex + this.$store.getters.isDriverMode ? 1 : 0; + return this.$store.getters.currentPipelineIndex + (this.$store.getters.isDriverMode ? 1 : 0); }, set(value) { - this.$store.commit('currentPipelineIndex', value - this.$store.getters.isDriverMode ? 1 : 0); + this.$store.commit('currentPipelineIndex', value - (this.$store.getters.isDriverMode ? 1 : 0)); } } }, @@ -332,10 +316,7 @@ this.namingDialog = true; }, openDuplicateDialog() { - this.pipelineDuplicate = { - pipeline: this.currentPipelineIndex - 1, - camera: -1 - }; + this.pipeIndexToDuplicate = this.currentPipelineIndex - 1; this.duplicateDialog = true; }, deleteCurrentPipeline() { @@ -356,19 +337,17 @@ } }, duplicatePipeline() { - if (!this.anotherCamera) { - this.pipelineDuplicate.camera = -1 - } - // this.handleInput("duplicatePipeline", this.pipelineDuplicate); - this.axios.post("http://" + this.$address + "/api/vision/duplicate", this.pipelineDuplicate); + // 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.pipelineDuplicate = { - pipeline: undefined, - camera: -1 - } + this.pipeIndexToDuplicate = undefined; }, discardPipelineNameChange() { this.namingDialog = false; diff --git a/photon-client/src/store/index.js b/photon-client/src/store/index.js index 7b759ef6f..36de173e9 100644 --- a/photon-client/src/store/index.js +++ b/photon-client/src/store/index.js @@ -1,7 +1,6 @@ import Vue from 'vue' import Vuex from 'vuex' -import networkSettings from "./modules/networkSettings" import undoRedo from "./modules/undoRedo"; Vue.use(Vuex); @@ -17,7 +16,6 @@ export default new Vuex.Store({ currentResolutionIndex: 0, }, }, - networkSettings: networkSettings, undoRedo: undoRedo }, state: { @@ -43,6 +41,7 @@ export default new Vuex.Store({ "pixelFormat": "BGR" } ], + calibrations: [ ], fov: 70.0, isFovConfigurable: true, calibrated: false, @@ -76,14 +75,14 @@ export default new Vuex.Store({ solvePNPEnabled: false, targetRegion: 0, contourTargetOrientation: 1, - is3D: false, + + cornerDetectionAccuracyPercentage: 10, // Settings that apply to shape } } ], - pipelineResults: [ - { + pipelineResults: { fps: 0, latency: 0, targets: [{ @@ -95,8 +94,7 @@ export default new Vuex.Store({ // 3D only pose: {x: 0, y: 0, rotation: 0}, }] - } - ], + }, settings: { general: { version: "Unknown", @@ -106,7 +104,7 @@ export default new Vuex.Store({ hardwareModel: "Unknown", hardwarePlatform: "Unknown", }, - networking: { + networkSettings: { teamNumber: 0, supported: true, @@ -120,19 +118,29 @@ export default new Vuex.Store({ supported: true, brightness: 0.0, }, - } + }, + calibrationData: { + count: 0, + videoModeIndex: 0, + minCount: 25, + hasEnough: false, + squareSizeIn: 1.0, + patternWidth: 7, + patternHeight: 7, + boardType: 0, // Chessboard, dotboard + }, }, mutations: { saveBar: set('saveBar'), compactMode: set('compactMode'), cameraSettings: set('cameraSettings'), currentCameraIndex: set('currentCameraIndex'), - pipelineResults: set('pipelineResults'), - networkSettings: set('networkSettings'), selectedOutputs: set('selectedOutputs'), + settings: set('settings'), + calibrationData: set('calibrationData'), - is3D: (state, val) => { - state.cameraSettings[state.currentCameraIndex].currentPipelineSettings.is3D = val; + solvePNPEnabled: (state, val) => { + state.cameraSettings[state.currentCameraIndex].currentPipelineSettings.solvePNPEnabled = val; }, currentPipelineIndex: (state, val) => { @@ -152,27 +160,50 @@ export default new Vuex.Store({ } }, + mutateSettings: (state, payload) => { + for (let key in payload) { + if (!payload.hasOwnProperty(key)) continue; + const value = payload[key]; + const settings = state.settings; + if (settings.hasOwnProperty(key)) { + Vue.set(settings, key, value); + } + } + }, + mutatePipelineResults(state, payload) { // Key: index, value: result - let newResultArray = []; for (let key in payload) { if (!payload.hasOwnProperty(key)) continue; const index = parseInt(key); - newResultArray[index] = payload[key]; + if(index === state.currentCameraIndex) { + Vue.set(state, 'pipelineResults', payload[key]) + } } - Vue.set(state, 'pipelineResults', newResultArray) - } + + }, + + mutateCalibrationState: (state, payload) => { + for (let key in payload) { + if (!payload.hasOwnProperty(key)) continue; + const value = payload[key]; + const calibration = state.calibrationData; + if (calibration.hasOwnProperty(key)) { + calibration[key] = value + } + Vue.set(state, 'calibrationData', calibration) + } + }, }, getters: { isDriverMode: state => state.cameraSettings[state.currentCameraIndex].currentPipelineIndex === -1, - pipelineSettings: state => state.pipelineSettings, streamAddress: state => ["http://" + location.hostname + ":" + state.cameraSettings[state.currentCameraIndex].inputStreamPort + "/stream.mjpg", "http://" + location.hostname + ":" + state.cameraSettings[state.currentCameraIndex].outputStreamPort + "/stream.mjpg"], - targets: state => state.pipelineResults.length, - currentPipelineResults: state => - state.pipelineResults[state.cameraSettings[state.currentCameraIndex].currentPipelineIndex], + currentPipelineResults: state => { + return state.pipelineResults; + }, cameraList: state => state.cameraSettings.map(it => it.nickname), currentCameraSettings: state => state.cameraSettings[state.currentCameraIndex], currentCameraIndex: state => state.currentCameraIndex, @@ -182,6 +213,6 @@ export default new Vuex.Store({ return Object.values(state.cameraSettings[state.currentCameraIndex].videoFormatList); // convert to a list }, pipelineList: state => state.cameraSettings[state.currentCameraIndex].pipelineNicknames, - currentCameraFPS: state => state.pipelineResults[state.currentCameraIndex].fps + calibrationList: state => state.cameraSettings[state.currentCameraIndex].calibrations, } }) \ No newline at end of file diff --git a/photon-client/src/store/modules/networkSettings.js b/photon-client/src/store/modules/networkSettings.js deleted file mode 100644 index a13ba586e..000000000 --- a/photon-client/src/store/modules/networkSettings.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - state: { - netmask: "", - ip: "", - teamNumber: "", - connectionType: "", - gateway: "" - }, - mutations: { - }, - actions: {}, - getters: { - pipeline: state => { - return state - } - } -}; \ No newline at end of file diff --git a/photon-client/src/store/modules/pipeline.js b/photon-client/src/store/modules/pipeline.js deleted file mode 100644 index 3788a50cf..000000000 --- a/photon-client/src/store/modules/pipeline.js +++ /dev/null @@ -1,45 +0,0 @@ -import Vue from 'vue' - -export default { - state: { - exposure: 0, - brightness: 0, - gain: 0, - rotationMode: 0, - hue: [0, 15], - saturation: [0, 15], - value: [0, 25], - erode: false, - dilate: false, - area: [0, 12], - ratio: [0, 12], - fullness: [0, 12], - speckle: 5, - targetGrouping: 0, - targetIntersection: 0, - sortMode: 0, - multiple: false, - isBinary: 0, - calibrationMode: 0, - videoModeIndex: 0, - streamDivisor: 0, - is3D: false, - targetRegion: 0, - targetOrientation: 1 - }, - mutations: { - isBinary: (state, value) => { - state.isBinary = value - }, - mutatePipeline: (state, {key, value}) => { - Vue.set(state, key, value) - } - - }, - actions: {}, - getters: { - pipeline: state => { - return state - } - } -}; \ No newline at end of file diff --git a/photon-client/src/views/CamerasView.vue b/photon-client/src/views/CamerasView.vue index 7e2666751..6f4f7a850 100644 --- a/photon-client/src/views/CamerasView.vue +++ b/photon-client/src/views/CamerasView.vue @@ -8,6 +8,7 @@ cols="12" md="7" > +
+ + Camera Calibration +
- + + + + + + + + - + + + + + + + + + + + + + + + + + {{ value.width }} X {{ value.height }} + + {{ isCalibrated(value) ? value.mean.toFixed(2) + "px" : "—" }} + + {{ isCalibrated(value) ? value.standardDeviation.toFixed(2) + "px" : "—" }} + + + + + + + Snapshots: {{ snapshotAmount }} of at least {{ minSnapshots }} + + + + + + + + + + + - + - {{ calibrationModeButton.text }} + {{ isCalibrating ? "Take Snapshot" : "Start Calibration" }} - + - {{ cancellationModeButton.text }} + {{ hasEnough ? "End Calibration" : "Cancel Calibration" }} @@ -102,6 +226,7 @@ color="accent" small outlined + style="width: 100%;" @click="downloadBoard" > @@ -113,52 +238,10 @@ ref="calibrationFile" style="color: black; text-decoration: none; display: none" :href="require('../assets/chessboard.png')" - download="Calibration Board.png" + download="chessboard.png" /> - - - Snapshot Amount: {{ snapshotAmount }} - - -
- -
- - - - -
-
@@ -186,207 +269,265 @@ - \ No newline at end of file diff --git a/photon-client/src/views/PipelineView.vue b/photon-client/src/views/PipelineView.vue index fd1023bb4..094943c14 100644 --- a/photon-client/src/views/PipelineView.vue +++ b/photon-client/src/views/PipelineView.vue @@ -25,12 +25,7 @@ class="pb-0 mb-0 pl-4 pt-1" style="height: 15%; min-height: 50px;" > -
- Cameras {{ parseFloat(fps).toFixed(2) }} FPS -
+ Cameras - @@ -166,7 +160,7 @@ slider-color="accent" > {{ tab.name }} @@ -299,11 +293,11 @@ }, processingMode: { get() { - return this.$store.getters.currentPipelineSettings.is3D ? 1 : 0; + return this.$store.getters.currentPipelineSettings.solvePNPEnabled ? 1 : 0; }, set(value) { - this.$store.getters.currentPipelineSettings.is3D = value === 1; - this.handlePipelineUpdate("is3D", value === 1); + this.$store.getters.currentPipelineSettings.solvePNPEnabled = value === 1; + this.handlePipelineUpdate("solvePNPEnabled", value === 1); } }, driverMode: { @@ -349,11 +343,6 @@ // this.handlePipelineUpdate('selectedOutputs', valToCommit); } }, - fps: { - get() { - return this.$store.getters.currentCameraFPS; - } - }, latency: { get() { return this.$store.getters.currentPipelineResults.latency; @@ -384,14 +373,6 @@ height: 100%; } - .fps-indicator { - position: absolute; - top: 2%; - left: 2%; - font-size: 1.75rem; - text-shadow: 1px 1px 5px rgba(1, 1, 1, 0.65); - } - th { width: 80px; text-align: center; diff --git a/photon-client/src/views/PipelineViews/PnPTab.vue b/photon-client/src/views/PipelineViews/PnPTab.vue index 402378ec1..9c41e3060 100644 --- a/photon-client/src/views/PipelineViews/PnPTab.vue +++ b/photon-client/src/views/PipelineViews/PnPTab.vue @@ -22,15 +22,15 @@ @change="onModelSelect" /> Target -