mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-01 02:41:42 +00:00
Vue 3 Upgrade (#1900)
## Description Upgrades to Vue 3 and necessary associated dependencies. Also fixes some issues with the layout and adds validation for object detection models. Closes #885, closes #1943, closes #1449. ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [x] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2024.3.1 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --------- Co-authored-by: Matt M <matthew.morley.ca@gmail.com> Co-authored-by: Gold856 <117957790+Gold856@users.noreply.github.com> Co-authored-by: samfreund <techguy763@gmail.com>
This commit is contained in:
@@ -3,22 +3,20 @@ import { PipelineType } from "@/types/PipelineTypes";
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import PvSwitch from "@/components/common/pv-switch.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import type { ActivePipelineSettings } from "@/types/PipelineTypes";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
// TODO fix pipeline typing in order to fix this, the store settings call should be able to infer that only valid pipeline type settings are exposed based on pre-checks for the entire config section
|
||||
// Defer reference to store access method
|
||||
const currentPipelineSettings = computed<ActivePipelineSettings>(
|
||||
() => useCameraSettingsStore().currentPipelineSettings
|
||||
);
|
||||
|
||||
const { mdAndDown } = useDisplay();
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 8
|
||||
: 7
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -29,7 +27,7 @@ const interactiveCols = computed(() =>
|
||||
label="Target family"
|
||||
:items="['AprilTag 36h11 (6.5in)', 'AprilTag 16h5 (6in)']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ tagFamily: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ tagFamily: value }, false)"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.decimate"
|
||||
@@ -38,7 +36,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Increases FPS at the expense of range by reducing image resolution initially"
|
||||
:min="1"
|
||||
:max="8"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decimate: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decimate: value }, false)"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.blur"
|
||||
@@ -48,7 +46,7 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="5"
|
||||
:step="0.1"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ blur: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ blur: value }, false)"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.threads"
|
||||
@@ -57,7 +55,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Number of threads spawned by the AprilTag detector"
|
||||
:min="1"
|
||||
:max="8"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threads: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threads: value }, false)"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.decisionMargin"
|
||||
@@ -66,7 +64,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Tags with a 'margin' (decoding quality score) less than this wil be rejected. Increase this to reduce the number of false positive detections"
|
||||
:min="0"
|
||||
:max="250"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decisionMargin: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decisionMargin: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.numIterations"
|
||||
@@ -75,14 +75,18 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Number of iterations the pose estimation algorithm will run, 50-100 is a good starting point"
|
||||
:min="0"
|
||||
:max="500"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ numIterations: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ numIterations: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="currentPipelineSettings.refineEdges"
|
||||
:switch-cols="interactiveCols"
|
||||
label="Refine Edges"
|
||||
tooltip="Further refines the AprilTag corner position initial estimate, suggested left on"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ refineEdges: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ refineEdges: value }, false)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,20 +5,18 @@ import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import PvSwitch from "@/components/common/pv-switch.vue";
|
||||
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
// TODO fix pipeline typing in order to fix this, the store settings call should be able to infer that only valid pipeline type settings are exposed based on pre-checks for the entire config section
|
||||
// Defer reference to store access method
|
||||
const currentPipelineSettings = computed<ActivePipelineSettings>(
|
||||
() => useCameraSettingsStore().currentPipelineSettings
|
||||
);
|
||||
|
||||
const { mdAndDown } = useDisplay();
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 8
|
||||
: 7
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -29,7 +27,7 @@ const interactiveCols = computed(() =>
|
||||
label="Target family"
|
||||
:items="['AprilTag Family 36h11', 'AprilTag Family 16h5']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ tagFamily: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ tagFamily: value }, false)"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-model="currentPipelineSettings.threshWinSizes"
|
||||
@@ -39,7 +37,9 @@ const interactiveCols = computed(() =>
|
||||
:max="255"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="2"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshWinSizes: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshWinSizes: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.threshStepSize"
|
||||
@@ -49,7 +49,9 @@ const interactiveCols = computed(() =>
|
||||
:min="2"
|
||||
:max="128"
|
||||
:step="1"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshStepSize: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshStepSize: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.threshConstant"
|
||||
@@ -59,21 +61,27 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="128"
|
||||
:step="1"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshConstant: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threshConstant: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="currentPipelineSettings.useCornerRefinement"
|
||||
label="Refine Corners"
|
||||
tooltip="Further refine the initial corners with subpixel accuracy."
|
||||
:switch-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ useCornerRefinement: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ useCornerRefinement: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="currentPipelineSettings.debugThreshold"
|
||||
label="Debug Threshold"
|
||||
tooltip="Display the first threshold step to the color stream."
|
||||
:switch-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ debugThreshold: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ debugThreshold: value }, false)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,8 +4,9 @@ import { type ActivePipelineSettings, PipelineType } from "@/types/PipelineTypes
|
||||
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
// TODO fix pipeline typing in order to fix this, the store settings call should be able to infer that only valid pipeline type settings are exposed based on pre-checks for the entire config section
|
||||
// Defer reference to store access method
|
||||
@@ -48,12 +49,9 @@ const contourRadius = computed<[number, number]>({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const { mdAndDown } = useDisplay();
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 8
|
||||
: 7
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -65,7 +63,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||
:items="['Portrait', 'Landscape']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -75,7 +73,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Chooses the sorting mode used to determine the 'best' targets to provide to user code"
|
||||
:select-cols="interactiveCols"
|
||||
:items="['Largest', 'Smallest', 'Highest', 'Lowest', 'Rightmost', 'Leftmost', 'Centermost']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSortMode: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSortMode: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-model="contourArea"
|
||||
@@ -84,7 +84,9 @@ const interactiveCols = computed(() =>
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.01"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourArea: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourArea: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineType !== PipelineType.ColoredShape"
|
||||
@@ -95,7 +97,9 @@ const interactiveCols = computed(() =>
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.1"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRatio: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRatio: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineType === PipelineType.ColoredShape"
|
||||
@@ -105,7 +109,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFullness: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFullness: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-if="currentPipelineSettings.pipelineType === PipelineType.ColoredShape"
|
||||
@@ -115,7 +121,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="4000"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourPerimeter: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourPerimeter: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourSpecklePercentage"
|
||||
@@ -124,7 +132,7 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSpecklePercentage: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -137,7 +145,9 @@ const interactiveCols = computed(() =>
|
||||
:max="4"
|
||||
:step="0.1"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeX: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeX: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="currentPipelineSettings.contourFilterRangeY"
|
||||
@@ -147,7 +157,9 @@ const interactiveCols = computed(() =>
|
||||
:max="4"
|
||||
:step="0.1"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeY: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeY: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourGroupingMode"
|
||||
@@ -155,7 +167,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Whether or not every two targets are paired with each other (good for e.g. 2019 targets)"
|
||||
:select-cols="interactiveCols"
|
||||
:items="['Single', 'Dual', 'Two or More']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourGroupingMode: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourGroupingMode: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourIntersection"
|
||||
@@ -164,7 +178,9 @@ const interactiveCols = computed(() =>
|
||||
:select-cols="interactiveCols"
|
||||
:items="['None', 'Up', 'Down', 'Left', 'Right']"
|
||||
:disabled="useCameraSettingsStore().currentPipelineSettings.contourGroupingMode === 0"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourIntersection: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourIntersection: value }, false)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="currentPipelineSettings.pipelineType === PipelineType.ColoredShape">
|
||||
@@ -174,7 +190,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="The shape of targets to look for"
|
||||
:select-cols="interactiveCols"
|
||||
:items="['Circle', 'Polygon', 'Triangle', 'Quadrilateral']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourShape: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourShape: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="currentPipelineSettings.contourShape >= 1"
|
||||
@@ -185,7 +203,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ accuracyPercentage: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ accuracyPercentage: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="currentPipelineSettings.contourShape === 0"
|
||||
@@ -196,7 +216,7 @@ const interactiveCols = computed(() =>
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ circleDetectThreshold: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -208,7 +228,9 @@ const interactiveCols = computed(() =>
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ maxCannyThresh: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ maxCannyThresh: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="currentPipelineSettings.contourShape === 0"
|
||||
@@ -218,7 +240,9 @@ const interactiveCols = computed(() =>
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ circleAccuracy: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ circleAccuracy: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-if="currentPipelineSettings.contourShape === 0"
|
||||
@@ -228,7 +252,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRadius: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRadius: value }, false)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -3,10 +3,11 @@ import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import PvSwitch from "@/components/common/pv-switch.vue";
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { getResolutionString } from "@/lib/PhotonUtils";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
// Due to something with libcamera or something else IDK much about, the 90° rotations need to be disabled if the libcamera drivers are being used.
|
||||
const cameraRotations = computed(() =>
|
||||
@@ -62,12 +63,10 @@ const handleStreamResolutionChange = (value: number) => {
|
||||
false
|
||||
);
|
||||
};
|
||||
const { mdAndDown } = useDisplay();
|
||||
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 8
|
||||
: 7
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -75,11 +74,12 @@ const interactiveCols = computed(() =>
|
||||
<div>
|
||||
<pv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraAutoExposure"
|
||||
class="pt-2"
|
||||
label="Auto Exposure"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="Enables or Disables camera automatic adjustment for current lighting conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoExposure: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoExposure: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraExposureRaw"
|
||||
@@ -90,7 +90,9 @@ const interactiveCols = computed(() =>
|
||||
:max="useCameraSettingsStore().maxExposureRaw"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="1"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraExposureRaw: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraExposureRaw: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraBrightness"
|
||||
@@ -98,7 +100,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBrightness: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBrightness: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraGain >= 0"
|
||||
@@ -108,7 +112,7 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraGain: args }, false)"
|
||||
@update:modelValue="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraGain: args }, false)"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraRedGain !== -1"
|
||||
@@ -118,7 +122,9 @@ const interactiveCols = computed(() =>
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
tooltip="Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraBlueGain !== -1"
|
||||
@@ -128,14 +134,18 @@ const interactiveCols = computed(() =>
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
tooltip="Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraAutoWhiteBalance"
|
||||
label="Auto White Balance"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="Enables or Disables camera automatic adjustment for current lighting conditions"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoWhiteBalance: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoWhiteBalance: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraWhiteBalanceTemp"
|
||||
@@ -144,7 +154,9 @@ const interactiveCols = computed(() =>
|
||||
:min="useCameraSettingsStore().minWhiteBalanceTemp"
|
||||
:max="useCameraSettingsStore().maxWhiteBalanceTemp"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraWhiteBalanceTemp: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraWhiteBalanceTemp: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.inputImageRotationMode"
|
||||
@@ -152,7 +164,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Rotates the camera stream. Rotation not available when camera has been calibrated."
|
||||
:items="cameraRotations"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ inputImageRotationMode: args }, false)"
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ inputImageRotationMode: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraVideoModeIndex"
|
||||
@@ -160,7 +174,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Resolution and FPS the camera should directly capture at"
|
||||
:items="cameraResolutions"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(args) => handleResolutionChange(args)"
|
||||
@update:modelValue="(args) => handleResolutionChange(args)"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.streamingFrameDivisor"
|
||||
@@ -168,7 +182,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Resolution to which camera frames are downscaled for streaming to the dashboard"
|
||||
:items="streamResolutions"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(args) => handleStreamResolutionChange(args)"
|
||||
@update:modelValue="(args) => handleStreamResolutionChange(args)"
|
||||
/>
|
||||
<pv-switch
|
||||
v-if="useCameraSettingsStore().isDriverMode"
|
||||
@@ -176,7 +190,7 @@ const interactiveCols = computed(() =>
|
||||
label="Crosshair"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="Enables or disables a crosshair overlay on the camera stream"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ crosshair: args }, false)"
|
||||
@update:modelValue="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ crosshair: args }, false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,7 +11,7 @@ const trackedTargets = computed<PhotonTarget[]>(() => useStateStore().currentPip
|
||||
<div>
|
||||
<v-row style="width: 100%">
|
||||
<v-col>
|
||||
<span class="white--text">Target Visualization</span>
|
||||
<span class="text-white">Target Visualization</span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row style="width: 100%">
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { type ObjectDetectionPipelineSettings, PipelineType } from "@/types/PipelineTypes";
|
||||
import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import PvSelect from "@/components/common/pv-select.vue";
|
||||
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
|
||||
import { computed } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
// TODO fix pipeline typing in order to fix this, the store settings call should be able to infer that only valid pipeline type settings are exposed based on pre-checks for the entire config section
|
||||
// Defer reference to store access method
|
||||
@@ -22,11 +25,10 @@ const contourRatio = computed<[number, number]>({
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.contourRatio = v)
|
||||
});
|
||||
|
||||
const { mdAndDown } = useDisplay();
|
||||
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 9
|
||||
: 8
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 9 : 8
|
||||
);
|
||||
|
||||
// Filters out models that are not supported by the current backend, and returns a flattened list.
|
||||
@@ -36,9 +38,12 @@ const supportedModels = computed(() => {
|
||||
});
|
||||
|
||||
const selectedModel = computed({
|
||||
get: () => supportedModels.value.indexOf(currentPipelineSettings.value.model),
|
||||
get: () => {
|
||||
const index = supportedModels.value.indexOf(currentPipelineSettings.value.model);
|
||||
return index === -1 ? undefined : index;
|
||||
},
|
||||
set: (v) => {
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ model: supportedModels.value[v] }, false);
|
||||
v && useCameraSettingsStore().changeCurrentPipelineSetting({ model: supportedModels.value[v] }, false);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -61,7 +66,9 @@ const selectedModel = computed({
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ confidence: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ confidence: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-model="contourArea"
|
||||
@@ -70,7 +77,9 @@ const selectedModel = computed({
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.01"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourArea: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourArea: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
v-model="contourRatio"
|
||||
@@ -80,7 +89,9 @@ const selectedModel = computed({
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.01"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRatio: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRatio: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOrientation"
|
||||
@@ -88,7 +99,7 @@ const selectedModel = computed({
|
||||
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||
:items="['Portrait', 'Landscape']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -98,7 +109,9 @@ const selectedModel = computed({
|
||||
tooltip="Chooses the sorting mode used to determine the 'best' targets to provide to user code"
|
||||
:select-cols="interactiveCols"
|
||||
:items="['Largest', 'Smallest', 'Highest', 'Lowest', 'Rightmost', 'Leftmost', 'Centermost']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSortMode: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSortMode: value }, false)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,9 +3,10 @@ import PvSelect from "@/components/common/pv-select.vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { type ActivePipelineSettings, PipelineType, RobotOffsetPointMode } from "@/types/PipelineTypes";
|
||||
import PvSwitch from "@/components/common/pv-switch.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { RobotOffsetType } from "@/types/SettingTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
const isTagPipeline = computed(
|
||||
() =>
|
||||
@@ -45,12 +46,10 @@ const offsetPoints = computed<MetricItem[]>(() => {
|
||||
const currentPipelineSettings = computed<ActivePipelineSettings>(
|
||||
() => useCameraSettingsStore().currentPipelineSettings
|
||||
);
|
||||
const { mdAndDown } = useDisplay();
|
||||
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 8
|
||||
: 7
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 8 : 7
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -62,7 +61,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="If enabled, up to five targets will be displayed and sent via PhotonLib, instead of just one"
|
||||
:disabled="isTagPipeline"
|
||||
:switch-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ outputShowMultipleTargets: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -78,7 +77,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="If enabled, all visible fiducial targets will be used to provide a single pose estimate from their combined model."
|
||||
:switch-cols="interactiveCols"
|
||||
:disabled="!isTagPipeline"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doMultiTarget: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doMultiTarget: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-if="
|
||||
@@ -92,7 +93,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="If disabled, visible fiducial targets used for multi-target estimation will not also be used for single-target estimation."
|
||||
:switch-cols="interactiveCols"
|
||||
:disabled="!isTagPipeline || !currentPipelineSettings.doMultiTarget"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doSingleTargetAlways: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ doSingleTargetAlways: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOffsetPointEdge"
|
||||
@@ -100,7 +103,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Changes where the 'center' of the target is (used for calculating e.g. pitch and yaw)"
|
||||
:items="['Center', 'Top', 'Bottom', 'Left', 'Right']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOffsetPointEdge: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -111,7 +114,7 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Used to determine how to calculate target landmarks (e.g. the top, left, or bottom of the target)"
|
||||
:items="['Portrait', 'Landscape']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
||||
"
|
||||
/>
|
||||
@@ -121,7 +124,9 @@ const interactiveCols = computed(() =>
|
||||
tooltip="Used to add an arbitrary offset to the location of the targeting crosshair"
|
||||
:items="['None', 'Single Point', 'Dual Point']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ offsetRobotOffsetMode: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ offsetRobotOffsetMode: value }, false)
|
||||
"
|
||||
/>
|
||||
<table
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode !== RobotOffsetPointMode.None"
|
||||
@@ -148,10 +153,10 @@ const interactiveCols = computed(() =>
|
||||
>
|
||||
<v-col cols="6" class="pl-0">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="accent"
|
||||
class="black--text"
|
||||
class="text-black"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Single)"
|
||||
>
|
||||
Take Point
|
||||
@@ -159,9 +164,9 @@ const interactiveCols = computed(() =>
|
||||
</v-col>
|
||||
<v-col cols="6" class="pr-0">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="yellow darken-3"
|
||||
color="yellow-darken-3"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Clear)"
|
||||
>
|
||||
Clear All Points
|
||||
@@ -174,10 +179,10 @@ const interactiveCols = computed(() =>
|
||||
>
|
||||
<v-col cols="6" lg="4" class="pl-0 pr-2">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="accent"
|
||||
class="black--text"
|
||||
class="text-black"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualFirst)"
|
||||
>
|
||||
Take First Point
|
||||
@@ -185,10 +190,10 @@ const interactiveCols = computed(() =>
|
||||
</v-col>
|
||||
<v-col cols="6" lg="4" class="pl-2 pr-0 pr-lg-2">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="accent"
|
||||
class="black--text"
|
||||
class="text-black"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualSecond)"
|
||||
>
|
||||
Take Second Point
|
||||
@@ -196,9 +201,9 @@ const interactiveCols = computed(() =>
|
||||
</v-col>
|
||||
<v-col cols="12" lg="4" class="pl-0 pl-lg-2 pr-0">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="yellow darken-3"
|
||||
color="yellow-darken-3"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Clear)"
|
||||
>
|
||||
Clear All Points
|
||||
|
||||
@@ -3,14 +3,13 @@ import PvSelect from "@/components/common/pv-select.vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { TargetModel } from "@/types/PipelineTypes";
|
||||
import PvSlider from "@/components/common/pv-slider.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { computed } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useDisplay } from "vuetify";
|
||||
const { mdAndDown } = useDisplay();
|
||||
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 9
|
||||
: 8
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 9 : 8
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -30,7 +29,9 @@ const interactiveCols = computed(() =>
|
||||
{ name: '2025 Algae (16.25in)', value: TargetModel.ReefscapeAlgae }
|
||||
]"
|
||||
:select-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ targetModel: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ targetModel: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cornerDetectionAccuracyPercentage"
|
||||
@@ -39,7 +40,7 @@ const interactiveCols = computed(() =>
|
||||
label="Contour simplification Percentage"
|
||||
:min="0"
|
||||
:max="100"
|
||||
@input="
|
||||
@update:modelValue="
|
||||
(value) =>
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ cornerDetectionAccuracyPercentage: value }, false)
|
||||
"
|
||||
|
||||
@@ -34,8 +34,8 @@ const resetCurrentBuffer = () => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row align="start" class="pb-4">
|
||||
<v-simple-table dense class="pt-2 pb-12">
|
||||
<v-row class="pb-4">
|
||||
<v-table density="compact" class="pt-2 pb-12 pl-3 pr-3">
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -44,24 +44,24 @@ const resetCurrentBuffer = () => {
|
||||
currentPipelineSettings.pipelineType === PipelineType.AprilTag ||
|
||||
currentPipelineSettings.pipelineType === PipelineType.Aruco
|
||||
"
|
||||
class="text-center white--text"
|
||||
class="text-center text-white"
|
||||
>
|
||||
Fiducial ID
|
||||
</th>
|
||||
<template v-if="currentPipelineSettings.pipelineType === PipelineType.ObjectDetection">
|
||||
<th class="text-center white--text">Class</th>
|
||||
<th class="text-center white--text">Confidence</th>
|
||||
<th class="text-center text-white">Class</th>
|
||||
<th class="text-center text-white">Confidence</th>
|
||||
</template>
|
||||
<template v-if="!useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
<th class="text-center white--text">Pitch θ°</th>
|
||||
<th class="text-center white--text">Yaw θ°</th>
|
||||
<th class="text-center white--text">Skew θ°</th>
|
||||
<th class="text-center white--text">Area %</th>
|
||||
<th class="text-center text-white">Pitch θ°</th>
|
||||
<th class="text-center text-white">Yaw θ°</th>
|
||||
<th class="text-center text-white">Skew θ°</th>
|
||||
<th class="text-center text-white">Area %</th>
|
||||
</template>
|
||||
<template v-else>
|
||||
<th class="text-center white--text">X meters</th>
|
||||
<th class="text-center white--text">Y meters</th>
|
||||
<th class="text-center white--text">Z Angle θ°</th>
|
||||
<th class="text-center text-white">X meters</th>
|
||||
<th class="text-center text-white">Y meters</th>
|
||||
<th class="text-center text-white">Z Angle θ°</th>
|
||||
</template>
|
||||
<template
|
||||
v-if="
|
||||
@@ -70,7 +70,7 @@ const resetCurrentBuffer = () => {
|
||||
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
||||
"
|
||||
>
|
||||
<th class="text-center white--text">Ambiguity Ratio</th>
|
||||
<th class="text-center text-white">Ambiguity Ratio</th>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -78,7 +78,7 @@ const resetCurrentBuffer = () => {
|
||||
<tr
|
||||
v-for="(target, index) in useStateStore().currentPipelineResults?.targets"
|
||||
:key="index"
|
||||
class="white--text"
|
||||
class="text-white"
|
||||
>
|
||||
<td
|
||||
v-if="
|
||||
@@ -91,13 +91,13 @@ const resetCurrentBuffer = () => {
|
||||
</td>
|
||||
<td
|
||||
v-if="currentPipelineSettings.pipelineType === PipelineType.ObjectDetection"
|
||||
class="text-center white--text"
|
||||
class="text-center text-white"
|
||||
>
|
||||
{{ useStateStore().currentPipelineResults?.classNames[target.classId] }}
|
||||
</td>
|
||||
<td
|
||||
v-if="currentPipelineSettings.pipelineType === PipelineType.ObjectDetection"
|
||||
class="text-center white--text"
|
||||
class="text-center text-white"
|
||||
>
|
||||
{{ target.confidence.toFixed(2) }}
|
||||
</td>
|
||||
@@ -126,7 +126,7 @@ const resetCurrentBuffer = () => {
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-table>
|
||||
</v-row>
|
||||
<v-container
|
||||
v-if="
|
||||
@@ -136,122 +136,123 @@ const resetCurrentBuffer = () => {
|
||||
useCameraSettingsStore().isCurrentVideoFormatCalibrated &&
|
||||
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
||||
"
|
||||
class="pl-3 pr-3"
|
||||
>
|
||||
<v-row class="pb-4 white--text">
|
||||
<v-row class="pb-4 text-white">
|
||||
<v-card-subtitle class="ma-0 pa-0 pb-4" style="font-size: 16px"
|
||||
>Multi-tag pose, field-to-camera</v-card-subtitle
|
||||
>
|
||||
<v-simple-table dense>
|
||||
<v-table density="compact">
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr class="white--text">
|
||||
<th class="text-center white--text">X meters</th>
|
||||
<th class="text-center white--text">Y meters</th>
|
||||
<th class="text-center white--text">Z meters</th>
|
||||
<th class="text-center white--text">X Angle θ°</th>
|
||||
<th class="text-center white--text">Y Angle θ°</th>
|
||||
<th class="text-center white--text">Z Angle θ°</th>
|
||||
<th class="text-center white--text">Tags</th>
|
||||
<tr class="text-white">
|
||||
<th class="text-center text-white">X meters</th>
|
||||
<th class="text-center text-white">Y meters</th>
|
||||
<th class="text-center text-white">Z meters</th>
|
||||
<th class="text-center text-white">X Angle θ°</th>
|
||||
<th class="text-center text-white">Y Angle θ°</th>
|
||||
<th class="text-center text-white">Z Angle θ°</th>
|
||||
<th class="text-center text-white">Tags</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
|
||||
<tr>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.x.toFixed(3) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.y.toFixed(3) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.bestTransform.z.toFixed(3) }} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_x || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_y || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
toDeg(useStateStore().currentPipelineResults?.multitagResult?.bestTransform.angle_z || 0).toFixed(
|
||||
2
|
||||
)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{ useStateStore().currentPipelineResults?.multitagResult?.fiducialIDsUsed }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-table>
|
||||
</v-row>
|
||||
<v-row class="pb-4 white--text" style="display: flex; flex-direction: column">
|
||||
<v-row class="pb-4 text-white" style="display: flex; flex-direction: column">
|
||||
<v-card-subtitle class="ma-0 pa-0 pb-4 pr-4" style="font-size: 16px"
|
||||
>Multi-tag pose standard deviation over the last
|
||||
{{ useStateStore().currentMultitagBuffer?.length || "NaN" }}/100 samples
|
||||
</v-card-subtitle>
|
||||
<v-btn color="secondary" class="mb-4 mt-1" style="width: min-content" depressed @click="resetCurrentBuffer"
|
||||
<v-btn color="secondary" class="mb-4 mt-1" style="width: min-content" variant="flat" @click="resetCurrentBuffer"
|
||||
>Reset Samples</v-btn
|
||||
>
|
||||
<v-simple-table dense>
|
||||
<v-table density="compact">
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center white--text">X meters</th>
|
||||
<th class="text-center white--text">Y meters</th>
|
||||
<th class="text-center white--text">Z meters</th>
|
||||
<th class="text-center white--text">X Angle θ°</th>
|
||||
<th class="text-center white--text">Y Angle θ°</th>
|
||||
<th class="text-center white--text">Z Angle θ°</th>
|
||||
<th class="text-center text-white">X meters</th>
|
||||
<th class="text-center text-white">Y meters</th>
|
||||
<th class="text-center text-white">Z meters</th>
|
||||
<th class="text-center text-white">X Angle θ°</th>
|
||||
<th class="text-center text-white">Y Angle θ°</th>
|
||||
<th class="text-center text-white">Z Angle θ°</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-show="useStateStore().currentPipelineResults?.multitagResult">
|
||||
<tr>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.x) || []).toFixed(
|
||||
5
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.y) || []).toFixed(
|
||||
5
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(useStateStore().currentMultitagBuffer?.map((v) => v.bestTransform.z) || []).toFixed(
|
||||
5
|
||||
)
|
||||
}} m
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_x)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_y)) || []
|
||||
).toFixed(5)
|
||||
}}°
|
||||
</td>
|
||||
<td class="text-center white--text">
|
||||
<td class="text-center text-white">
|
||||
{{
|
||||
calculateStdDev(
|
||||
useStateStore().currentMultitagBuffer?.map((v) => toDeg(v.bestTransform.angle_z)) || []
|
||||
@@ -261,14 +262,14 @@ const resetCurrentBuffer = () => {
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
</v-table>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.v-data-table {
|
||||
.v-table {
|
||||
background-color: #006492 !important;
|
||||
width: 100%;
|
||||
font-size: 1rem !important;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { computed, getCurrentInstance, onBeforeUnmount, onMounted } from "vue";
|
||||
import { computed, onBeforeUnmount, onMounted } from "vue";
|
||||
import PvRangeSlider from "@/components/common/pv-range-slider.vue";
|
||||
import PvSwitch from "@/components/common/pv-switch.vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { ColorPicker, type HSV } from "@/lib/ColorPicker";
|
||||
import { useDisplay } from "vuetify";
|
||||
|
||||
const averageHue = computed<number>(() => {
|
||||
const isHueInverted = useCameraSettingsStore().currentPipelineSettings.hueInverted;
|
||||
@@ -123,12 +124,10 @@ onBeforeUnmount(() => {
|
||||
|
||||
cameraStream.removeEventListener("click", handleStreamClick);
|
||||
});
|
||||
const { mdAndDown } = useDisplay();
|
||||
|
||||
const interactiveCols = computed(() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
? 9
|
||||
: 8
|
||||
mdAndDown.value && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode) ? 9 : 8
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -144,7 +143,7 @@ const interactiveCols = computed(() =>
|
||||
:max="180"
|
||||
:slider-cols="interactiveCols"
|
||||
:inverted="useCameraSettingsStore().currentPipelineSettings.hueInverted"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvHue: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvHue: value }, false)"
|
||||
/>
|
||||
<pv-range-slider
|
||||
id="sat-slider"
|
||||
@@ -155,7 +154,9 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="255"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvSaturation: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvSaturation: value }, false)
|
||||
"
|
||||
/>
|
||||
<pv-range-slider
|
||||
id="value-slider"
|
||||
@@ -166,53 +167,55 @@ const interactiveCols = computed(() =>
|
||||
:min="0"
|
||||
:max="255"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvValue: value }, false)"
|
||||
@update:modelValue="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvValue: value }, false)"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.hueInverted"
|
||||
label="Invert Hue"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="Selects the hue range outside of the hue slider bounds instead of inside"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hueInverted: value }, false)"
|
||||
@update:modelValue="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hueInverted: value }, false)
|
||||
"
|
||||
/>
|
||||
<div>
|
||||
<div class="white--text pt-3">Color Picker</div>
|
||||
<div class="text-white pt-3">Color Picker</div>
|
||||
<div class="d-flex pt-3">
|
||||
<template v-if="!useStateStore().colorPickingMode">
|
||||
<v-col cols="4" class="pl-0 pr-2">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="accent"
|
||||
class="black--text"
|
||||
class="text-black"
|
||||
@click="enableColorPicking(useCameraSettingsStore().currentPipelineSettings.hueInverted ? 2 : 3)"
|
||||
>
|
||||
<v-icon left> mdi-minus </v-icon>
|
||||
<v-icon start> mdi-minus </v-icon>
|
||||
Shrink Range
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="4" class="pl-0 pr-0">
|
||||
<v-btn color="accent" class="black--text" small block @click="enableColorPicking(1)">
|
||||
<v-icon left> mdi-plus-minus </v-icon>
|
||||
<v-btn color="accent" class="text-black" size="small" block @click="enableColorPicking(1)">
|
||||
<v-icon start> mdi-plus-minus </v-icon>
|
||||
{{ useCameraSettingsStore().currentPipelineSettings.hueInverted ? "Exclude" : "Set to" }} Average
|
||||
</v-btn>
|
||||
</v-col>
|
||||
<v-col cols="4" class="pl-2 pr-0">
|
||||
<v-btn
|
||||
small
|
||||
size="small"
|
||||
block
|
||||
color="accent"
|
||||
class="black--text"
|
||||
class="text-black"
|
||||
@click="enableColorPicking(useCameraSettingsStore().currentPipelineSettings.hueInverted ? 3 : 2)"
|
||||
>
|
||||
<v-icon left> mdi-plus </v-icon>
|
||||
<v-icon start> mdi-plus </v-icon>
|
||||
Expand Range
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-card-text class="pa-0 pt-3 pb-3">
|
||||
<v-btn block color="accent" class="black--text" small @click="disableColorPicking"> Cancel </v-btn>
|
||||
<v-btn block color="accent" class="text-black" size="small" @click="disableColorPicking"> Cancel </v-btn>
|
||||
</v-card-text>
|
||||
</template>
|
||||
</div>
|
||||
@@ -224,32 +227,32 @@ const interactiveCols = computed(() =>
|
||||
.threshold-modifiers {
|
||||
--averageHue: 0;
|
||||
}
|
||||
#hue-slider >>> .v-slider {
|
||||
#hue-slider:deep(.v-slider__container) {
|
||||
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
|
||||
border-radius: 10px;
|
||||
/* prettier-ignore */
|
||||
box-shadow: 0 0 5px #333, inset 0 0 3px #333;
|
||||
}
|
||||
#sat-slider >>> .v-slider {
|
||||
#sat-slider:deep(.v-slider__container) {
|
||||
background: linear-gradient(to right, #fff 0%, hsl(var(--averageHue), 100%, 50%) 100%);
|
||||
border-radius: 10px;
|
||||
/* prettier-ignore */
|
||||
box-shadow: 0 0 5px #333, inset 0 0 3px #333;
|
||||
}
|
||||
#value-slider >>> .v-slider {
|
||||
#value-slider:deep(.v-slider__container) {
|
||||
background: linear-gradient(to right, #000 0%, hsl(var(--averageHue), 100%, 50%) 100%);
|
||||
border-radius: 10px;
|
||||
/* prettier-ignore */
|
||||
box-shadow: 0 0 5px #333, inset 0 0 3px #333;
|
||||
}
|
||||
>>> .v-slider__thumb {
|
||||
:deep(.v-slider__thumb) {
|
||||
outline: black solid thin;
|
||||
}
|
||||
.normal-slider >>> .v-slider__track-fill {
|
||||
.normal-slider:deep(.v-slider__track-fill) {
|
||||
outline: black solid thin;
|
||||
}
|
||||
|
||||
.inverted-slider >>> .v-slider__track-background {
|
||||
.inverted-slider:deep(.v-slider__track-background) {
|
||||
outline: black solid thin;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user