mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-28 02:11:40 +00:00
UI patches (#905)
- Show 0 clients when NT server props are undefined - Add Prettier --------- Co-authored-by: Matthew Morley <matthew.morley.ca@gmail.com>
This commit is contained in:
@@ -11,7 +11,13 @@ import { useStateStore } from "@/stores/StateStore";
|
||||
// Defer reference to store access method
|
||||
const currentPipelineSettings = useCameraSettingsStore().currentPipelineSettings;
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -21,7 +27,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
label="Target family"
|
||||
:items="['AprilTag Family 36h11', 'AprilTag Family 25h9', 'AprilTag Family 16h5']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({tagFamily: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ tagFamily: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.decimate"
|
||||
@@ -31,7 +37,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Increases FPS at the expense of range by reducing image resolution initially"
|
||||
:min="1"
|
||||
:max="8"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({decimate: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decimate: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.blur"
|
||||
@@ -42,7 +48,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="5"
|
||||
:step="0.1"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({blur: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ blur: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.threads"
|
||||
@@ -52,14 +58,14 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Number of threads spawned by the AprilTag detector"
|
||||
:min="1"
|
||||
:max="8"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({threads: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ threads: value }, false)"
|
||||
/>
|
||||
<cv-switch
|
||||
v-model="currentPipelineSettings.refineEdges"
|
||||
class="pt-2"
|
||||
label="Refine Edges"
|
||||
tooltip="Further refines the AprilTag corner position initial estimate, suggested left on"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({refineEdges: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ refineEdges: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.decisionMargin"
|
||||
@@ -69,7 +75,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
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)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decisionMargin: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.numIterations"
|
||||
@@ -79,7 +85,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
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)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ numIterations: value }, false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -9,7 +9,13 @@ import { useStateStore } from "@/stores/StateStore";
|
||||
// Defer reference to store access method
|
||||
const currentPipelineSettings = useCameraSettingsStore().currentPipelineSettings;
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -22,7 +28,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Increases FPS at the expense of range by reducing image resolution initially"
|
||||
:min="1"
|
||||
:max="8"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({decimate: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ decimate: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.numIterations"
|
||||
@@ -33,7 +39,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="30"
|
||||
:max="1000"
|
||||
:step="5"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({numIterations: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ numIterations: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.cornerAccuracy"
|
||||
@@ -44,7 +50,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0.01"
|
||||
:max="100"
|
||||
:step="0.01"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({cornerAccuracy: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ cornerAccuracy: value }, false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -14,34 +14,46 @@ const currentPipelineSettings = useCameraSettingsStore().currentPipelineSettings
|
||||
// TODO fix cv-range-slider so that store access doesn't need to be deferred
|
||||
const contourArea = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.contourArea) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.contourArea = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.contourArea = v)
|
||||
});
|
||||
const contourRatio = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.contourRatio) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.contourRatio = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.contourRatio = v)
|
||||
});
|
||||
const contourFullness = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.contourFullness) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.contourFullness = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.contourFullness = v)
|
||||
});
|
||||
const contourPerimeter = computed<[number, number]>({
|
||||
get: () => currentPipelineSettings.pipelineType === PipelineType.ColoredShape ? Object.values(currentPipelineSettings.contourPerimeter) as [number, number] : [0, 0] as [number, number],
|
||||
set: v => {
|
||||
if(currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
|
||||
get: () =>
|
||||
currentPipelineSettings.pipelineType === PipelineType.ColoredShape
|
||||
? (Object.values(currentPipelineSettings.contourPerimeter) as [number, number])
|
||||
: ([0, 0] as [number, number]),
|
||||
set: (v) => {
|
||||
if (currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
|
||||
currentPipelineSettings.contourPerimeter = v;
|
||||
}
|
||||
}
|
||||
});
|
||||
const contourRadius = computed<[number, number]>({
|
||||
get: () => currentPipelineSettings.pipelineType === PipelineType.ColoredShape ? Object.values(currentPipelineSettings.contourRadius) as [number, number] : [0, 0] as [number, number],
|
||||
set: v => {
|
||||
if(currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
|
||||
get: () =>
|
||||
currentPipelineSettings.pipelineType === PipelineType.ColoredShape
|
||||
? (Object.values(currentPipelineSettings.contourRadius) as [number, number])
|
||||
: ([0, 0] as [number, number]),
|
||||
set: (v) => {
|
||||
if (currentPipelineSettings.pipelineType === PipelineType.ColoredShape) {
|
||||
currentPipelineSettings.contourRadius = v;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -53,7 +65,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.01"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourArea: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourArea: value }, false)"
|
||||
/>
|
||||
<cv-range-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineType !== PipelineType.ColoredShape"
|
||||
@@ -64,7 +76,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.1"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourRatio: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRatio: value }, false)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOrientation"
|
||||
@@ -72,7 +84,9 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Used to determine how to calculate target landmarks, as well as aspect ratio"
|
||||
:items="['Portrait', 'Landscape']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourTargetOrientation: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
||||
"
|
||||
/>
|
||||
<cv-range-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineType === PipelineType.ColoredShape"
|
||||
@@ -82,7 +96,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourFullness: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFullness: value }, false)"
|
||||
/>
|
||||
<cv-range-slider
|
||||
v-if="currentPipelineSettings.pipelineType === PipelineType.ColoredShape"
|
||||
@@ -92,7 +106,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
min="0"
|
||||
max="4000"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourPerimeter: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourPerimeter: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourSpecklePercentage"
|
||||
@@ -101,7 +115,9 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourSpecklePercentage: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSpecklePercentage: value }, false)
|
||||
"
|
||||
/>
|
||||
<template v-if="currentPipelineSettings.pipelineType === PipelineType.Reflective">
|
||||
<cv-slider
|
||||
@@ -112,7 +128,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="4"
|
||||
:step="0.1"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourFilterRangeX: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeX: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.contourFilterRangeY"
|
||||
@@ -122,24 +138,24 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="4"
|
||||
:step="0.1"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourFilterRangeY: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourFilterRangeY: value }, false)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourGroupingMode"
|
||||
label="Target Grouping"
|
||||
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)"
|
||||
:items="['Single', 'Dual', 'Two or More']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourGroupingMode: value }, false)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourIntersection"
|
||||
label="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="interactiveCols"
|
||||
:items="['None','Up','Down','Left','Right']"
|
||||
:items="['None', 'Up', 'Down', 'Left', 'Right']"
|
||||
:disabled="useCameraSettingsStore().currentPipelineSettings.contourGroupingMode === 0"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourIntersection: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourIntersection: value }, false)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="currentPipelineSettings.pipelineType === PipelineType.ColoredShape">
|
||||
@@ -150,7 +166,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="The shape of targets to look for"
|
||||
:select-cols="interactiveCols"
|
||||
:items="['Circle', 'Polygon', 'Triangle', 'Quadrilateral']"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourShape: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourShape: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.accuracyPercentage"
|
||||
@@ -160,7 +176,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({accuracyPercentage: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ accuracyPercentage: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.circleDetectThreshold"
|
||||
@@ -170,7 +186,9 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({circleDetectThreshold: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ circleDetectThreshold: value }, false)
|
||||
"
|
||||
/>
|
||||
<cv-range-slider
|
||||
v-model="contourRadius"
|
||||
@@ -179,7 +197,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourRadius: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourRadius: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.maxCannyThresh"
|
||||
@@ -188,7 +206,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({maxCannyThresh: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ maxCannyThresh: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="currentPipelineSettings.circleAccuracy"
|
||||
@@ -197,7 +215,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="1"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({circleAccuracy: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ circleAccuracy: value }, false)"
|
||||
/>
|
||||
<v-divider class="mt-3" />
|
||||
</template>
|
||||
@@ -206,8 +224,8 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
label="Target Sort"
|
||||
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)"
|
||||
:items="['Largest', 'Smallest', 'Highest', 'Lowest', 'Rightmost', 'Leftmost', 'Centermost']"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourSortMode: value }, false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,26 +8,38 @@ import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
|
||||
// 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(() => ["Normal", "90° CW", "180°", "90° CCW"].map((v, i) => ({ name: v, value: i, disabled: useSettingsStore().gpuAccelerationEnabled ? [1, 3].includes(i) : false })));
|
||||
const cameraRotations = computed(() =>
|
||||
["Normal", "90° CW", "180°", "90° CCW"].map((v, i) => ({
|
||||
name: v,
|
||||
value: i,
|
||||
disabled: useSettingsStore().gpuAccelerationEnabled ? [1, 3].includes(i) : false
|
||||
}))
|
||||
);
|
||||
|
||||
const streamDivisors = [1, 2, 4, 6];
|
||||
const getFilteredStreamDivisors = (): number[] => {
|
||||
const currentResolutionWidth = useCameraSettingsStore().currentVideoFormat.resolution.width;
|
||||
return streamDivisors.filter(x =>
|
||||
useCameraSettingsStore().isDriverMode
|
||||
|| !useSettingsStore().gpuAccelerationEnabled
|
||||
|| currentResolutionWidth / x < 400);
|
||||
return streamDivisors.filter(
|
||||
(x) =>
|
||||
useCameraSettingsStore().isDriverMode ||
|
||||
!useSettingsStore().gpuAccelerationEnabled ||
|
||||
currentResolutionWidth / x < 400
|
||||
);
|
||||
};
|
||||
const getNumberOfSkippedDivisors = () => streamDivisors.length - getFilteredStreamDivisors().length;
|
||||
|
||||
const cameraResolutions = computed(() => useCameraSettingsStore().currentCameraSettings.validVideoFormats.map(f => `${f.resolution.width} X ${f.resolution.height} at ${f.fps} FPS, ${f.pixelFormat}`));
|
||||
const cameraResolutions = computed(() =>
|
||||
useCameraSettingsStore().currentCameraSettings.validVideoFormats.map(
|
||||
(f) => `${f.resolution.width} X ${f.resolution.height} at ${f.fps} FPS, ${f.pixelFormat}`
|
||||
)
|
||||
);
|
||||
const handleResolutionChange = (value: number) => {
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ cameraVideoModeIndex: value }, false);
|
||||
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ streamingFrameDivisor: getNumberOfSkippedDivisors() }, false);
|
||||
useCameraSettingsStore().currentPipelineSettings.streamingFrameDivisor = 0;
|
||||
|
||||
if(!useCameraSettingsStore().isCurrentVideoFormatCalibrated) {
|
||||
if (!useCameraSettingsStore().isCurrentVideoFormatCalibrated) {
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ solvePNPEnabled: false }, true);
|
||||
}
|
||||
};
|
||||
@@ -35,14 +47,24 @@ const handleResolutionChange = (value: number) => {
|
||||
const streamResolutions = computed(() => {
|
||||
const streamDivisors = getFilteredStreamDivisors();
|
||||
const currentResolution = useCameraSettingsStore().currentVideoFormat.resolution;
|
||||
return streamDivisors
|
||||
.map(x => `${Math.floor(currentResolution.width / x)} X ${Math.floor(currentResolution.height / x)}`);
|
||||
return streamDivisors.map(
|
||||
(x) => `${Math.floor(currentResolution.width / x)} X ${Math.floor(currentResolution.height / x)}`
|
||||
);
|
||||
});
|
||||
const handleStreamResolutionChange = (value: number) => {
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ streamingFrameDivisor: value + getNumberOfSkippedDivisors() }, false);
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting(
|
||||
{ streamingFrameDivisor: value + getNumberOfSkippedDivisors() },
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -56,7 +78,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
:step="0.1"
|
||||
@input="args => useCameraSettingsStore().changeCurrentPipelineSetting({cameraExposure: args}, false)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraExposure: args }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraBrightness"
|
||||
@@ -64,7 +86,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="args => useCameraSettingsStore().changeCurrentPipelineSetting({cameraBrightness: args}, false)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBrightness: args }, false)"
|
||||
/>
|
||||
<cv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraAutoExposure"
|
||||
@@ -72,7 +94,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
label="Auto Exposure"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="Enables or Disables camera automatic adjustment for current lighting conditions"
|
||||
@input="args => useCameraSettingsStore().changeCurrentPipelineSetting({cameraAutoExposure: args}, false)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraAutoExposure: args }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraGain >= 0"
|
||||
@@ -82,7 +104,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="100"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="args => useCameraSettingsStore().changeCurrentPipelineSetting({cameraGain: args}, false)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraGain: args }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraRedGain !== -1"
|
||||
@@ -92,7 +114,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
: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)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraRedGain: args }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.cameraBlueGain !== -1"
|
||||
@@ -102,7 +124,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
: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)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraBlueGain: args }, false)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.inputImageRotationMode"
|
||||
@@ -110,7 +132,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Rotates the camera stream"
|
||||
:items="cameraRotations"
|
||||
:select-cols="interactiveCols"
|
||||
@input="args => useCameraSettingsStore().changeCurrentPipelineSetting({inputImageRotationMode: args}, false)"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ inputImageRotationMode: args }, false)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cameraVideoModeIndex"
|
||||
@@ -118,7 +140,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Resolution and FPS the camera should directly capture at"
|
||||
:items="cameraResolutions"
|
||||
:select-cols="interactiveCols"
|
||||
@input="args => handleResolutionChange(args)"
|
||||
@input="(args) => handleResolutionChange(args)"
|
||||
/>
|
||||
<cv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.streamingFrameDivisor"
|
||||
@@ -126,7 +148,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="Resolution to which camera frames are downscaled for streaming to the dashboard"
|
||||
:items="streamResolutions"
|
||||
:select-cols="interactiveCols"
|
||||
@input="args => handleStreamResolutionChange(args)"
|
||||
@input="(args) => handleStreamResolutionChange(args)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -16,9 +16,7 @@ const trackedTargets = computed<PhotonTarget[]>(() => useStateStore().pipelineRe
|
||||
</v-row>
|
||||
<v-row style="width: 100%">
|
||||
<v-col style="display: flex; align-items: center; justify-content: center">
|
||||
<photon3d-visualizer
|
||||
:targets="trackedTargets"
|
||||
/>
|
||||
<photon3d-visualizer :targets="trackedTargets" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
@@ -7,11 +7,15 @@ import { computed, getCurrentInstance } from "vue";
|
||||
import { RobotOffsetType } from "@/types/SettingTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
|
||||
const isTagPipeline = computed(() => useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag || useCameraSettingsStore().currentPipelineType === PipelineType.Aruco);
|
||||
const isTagPipeline = computed(
|
||||
() =>
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
|
||||
);
|
||||
|
||||
interface MetricItem {
|
||||
header: string,
|
||||
value?: string
|
||||
header: string;
|
||||
value?: string;
|
||||
}
|
||||
|
||||
const offsetPoints = computed<MetricItem[]>(() => {
|
||||
@@ -24,10 +28,11 @@ const offsetPoints = computed<MetricItem[]>(() => {
|
||||
const firstPointArea = useCameraSettingsStore().currentPipelineSettings.offsetDualPointAArea;
|
||||
const secondPoint = Object.values(useCameraSettingsStore().currentPipelineSettings.offsetDualPointB);
|
||||
const secondPointArea = useCameraSettingsStore().currentPipelineSettings.offsetDualPointBArea;
|
||||
return [{ header: "First Offset Point", value: `(${firstPoint[0].toFixed(2)}°, ${firstPoint[1].toFixed(2)}°)` },
|
||||
{ header: "First Offset Point Area", value: `${firstPointArea.toFixed(2)}%` },
|
||||
{ header: "Second Offset Point", value: `(${secondPoint[0].toFixed(2)}°, ${secondPoint[1].toFixed(2)}°)` },
|
||||
{ header: "Second Offset Point Area", value: `${secondPointArea.toFixed(2)}%` }
|
||||
return [
|
||||
{ header: "First Offset Point", value: `(${firstPoint[0].toFixed(2)}°, ${firstPoint[1].toFixed(2)}°)` },
|
||||
{ header: "First Offset Point Area", value: `${firstPointArea.toFixed(2)}%` },
|
||||
{ header: "Second Offset Point", value: `(${secondPoint[0].toFixed(2)}°, ${secondPoint[1].toFixed(2)}°)` },
|
||||
{ header: "Second Offset Point Area", value: `${secondPointArea.toFixed(2)}%` }
|
||||
];
|
||||
default:
|
||||
case RobotOffsetPointMode.None:
|
||||
@@ -35,7 +40,13 @@ const offsetPoints = computed<MetricItem[]>(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,9 +55,11 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.contourTargetOffsetPointEdge"
|
||||
label="Target Offset Point"
|
||||
tooltip="Changes where the 'center' of the target is (used for calculating e.g. pitch and yaw)"
|
||||
:items="['Center','Top','Bottom','Left','Right']"
|
||||
:items="['Center', 'Top', 'Bottom', 'Left', 'Right']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourTargetOffsetPointEdge: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOffsetPointEdge: value }, false)
|
||||
"
|
||||
/>
|
||||
<cv-select
|
||||
v-if="!isTagPipeline"
|
||||
@@ -55,7 +68,9 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
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="value => useCameraSettingsStore().changeCurrentPipelineSetting({contourTargetOrientation: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ contourTargetOrientation: value }, false)
|
||||
"
|
||||
/>
|
||||
<cv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.outputShowMultipleTargets"
|
||||
@@ -63,7 +78,9 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
tooltip="If enabled, up to five targets will be displayed and sent to user code, instead of just one"
|
||||
:disabled="isTagPipeline"
|
||||
:switch-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({outputShowMultipleTargets: value}, false)"
|
||||
@input="
|
||||
(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ outputShowMultipleTargets: value }, false)
|
||||
"
|
||||
/>
|
||||
<v-divider />
|
||||
<table
|
||||
@@ -71,20 +88,12 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
class="metrics-table mt-3 mb-3"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
v-for="(item, itemIndex) in offsetPoints"
|
||||
:key="itemIndex"
|
||||
class="metric-item metric-item-title"
|
||||
>
|
||||
<th v-for="(item, itemIndex) in offsetPoints" :key="itemIndex" class="metric-item metric-item-title">
|
||||
{{ item.header }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
v-for="(item, itemIndex) in offsetPoints"
|
||||
:key="itemIndex"
|
||||
class="metric-item"
|
||||
>
|
||||
<td v-for="(item, itemIndex) in offsetPoints" :key="itemIndex" class="metric-item">
|
||||
{{ item.value }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -93,21 +102,23 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode"
|
||||
label="Robot Offset Mode"
|
||||
tooltip="Used to add an arbitrary offset to the location of the targeting crosshair"
|
||||
:items="['None','Single Point','Dual Point']"
|
||||
:items="['None', 'Single Point', 'Dual Point']"
|
||||
:select-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({offsetRobotOffsetMode: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ offsetRobotOffsetMode: value }, false)"
|
||||
/>
|
||||
<v-row
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode !== RobotOffsetPointMode.None"
|
||||
align="center"
|
||||
justify="start"
|
||||
>
|
||||
<v-row v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Single">
|
||||
<v-row
|
||||
v-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Single"
|
||||
>
|
||||
<v-col>
|
||||
<v-btn
|
||||
small
|
||||
color="accent"
|
||||
style="width: 100%;"
|
||||
style="width: 100%"
|
||||
class="black--text"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Single)"
|
||||
>
|
||||
@@ -115,12 +126,14 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Dual">
|
||||
<v-row
|
||||
v-else-if="useCameraSettingsStore().currentPipelineSettings.offsetRobotOffsetMode === RobotOffsetPointMode.Dual"
|
||||
>
|
||||
<v-col>
|
||||
<v-btn
|
||||
small
|
||||
color="accent"
|
||||
style="width: 100%;"
|
||||
style="width: 100%"
|
||||
class="black--text"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualFirst)"
|
||||
>
|
||||
@@ -131,7 +144,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
<v-btn
|
||||
small
|
||||
color="accent"
|
||||
style="width: 100%;"
|
||||
style="width: 100%"
|
||||
class="black--text"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.DualSecond)"
|
||||
>
|
||||
@@ -143,7 +156,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
<v-btn
|
||||
small
|
||||
color="yellow darken-3"
|
||||
style="width: 100%;"
|
||||
style="width: 100%"
|
||||
@click="useCameraSettingsStore().takeRobotOffsetPoint(RobotOffsetType.Clear)"
|
||||
>
|
||||
Clear All Points
|
||||
@@ -154,7 +167,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.metrics-table{
|
||||
.metrics-table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -6,7 +6,13 @@ import CvSlider from "@/components/common/cv-slider.vue";
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -15,18 +21,18 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.targetModel"
|
||||
label="Target Model"
|
||||
:items="[
|
||||
{name: '2020 High Goal Outer', value: TargetModel.InfiniteRechargeHighGoalOuter},
|
||||
{name: '2020 High Goal Inner', value: TargetModel.InfiniteRechargeHighGoalInner},
|
||||
{name: '2019 Dual Target', value: TargetModel.DeepSpaceDualTarget},
|
||||
{name: '2020 Power Cell (7in)', value: TargetModel.CircularPowerCell7in},
|
||||
{name: '2022 Cargo Ball (9.5in)', value: TargetModel.RapidReactCircularCargoBall},
|
||||
{name: '2016 High Goal', value: TargetModel.StrongholdHighGoal},
|
||||
{name: '200mm AprilTag', value: TargetModel.Apriltag_200mm},
|
||||
{name: '6in (16h5) Aruco', value: TargetModel.Aruco6in_16h5},
|
||||
{name: '6in (16h5) AprilTag', value: TargetModel.Apriltag6in_16h5}
|
||||
{ name: '2020 High Goal Outer', value: TargetModel.InfiniteRechargeHighGoalOuter },
|
||||
{ name: '2020 High Goal Inner', value: TargetModel.InfiniteRechargeHighGoalInner },
|
||||
{ name: '2019 Dual Target', value: TargetModel.DeepSpaceDualTarget },
|
||||
{ name: '2020 Power Cell (7in)', value: TargetModel.CircularPowerCell7in },
|
||||
{ name: '2022 Cargo Ball (9.5in)', value: TargetModel.RapidReactCircularCargoBall },
|
||||
{ name: '2016 High Goal', value: TargetModel.StrongholdHighGoal },
|
||||
{ name: '200mm AprilTag', value: TargetModel.Apriltag_200mm },
|
||||
{ name: '6in (16h5) Aruco', value: TargetModel.Aruco6in_16h5 },
|
||||
{ name: '6in (16h5) AprilTag', value: TargetModel.Apriltag6in_16h5 }
|
||||
]"
|
||||
:select-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({targetModel: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ targetModel: value }, false)"
|
||||
/>
|
||||
<cv-slider
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.cornerDetectionAccuracyPercentage"
|
||||
@@ -35,7 +41,10 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
label="Contour simplification Percentage"
|
||||
:min="0"
|
||||
:max="100"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({cornerDetectionAccuracyPercentage: value}, false)"
|
||||
@input="
|
||||
(value) =>
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ cornerDetectionAccuracyPercentage: value }, false)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,69 +6,52 @@ import { useStateStore } from "@/stores/StateStore";
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-row
|
||||
align="start"
|
||||
class="pb-4"
|
||||
style="height: 300px;"
|
||||
>
|
||||
<v-row align="start" class="pb-4" style="height: 300px">
|
||||
<!-- Simple table height must be set here and in the CSS for the fixed-header to work -->
|
||||
<v-simple-table
|
||||
fixed-header
|
||||
height="100%"
|
||||
dense
|
||||
dark
|
||||
>
|
||||
<v-simple-table fixed-header height="100%" dense dark>
|
||||
<template #default>
|
||||
<thead style="font-size: 1.25rem;">
|
||||
<thead style="font-size: 1.25rem">
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
Target Count
|
||||
</th>
|
||||
<th class="text-center">Target Count</th>
|
||||
<th
|
||||
v-if="useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag || useCameraSettingsStore().currentPipelineType === PipelineType.Aruco"
|
||||
v-if="
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
|
||||
"
|
||||
class="text-center"
|
||||
>
|
||||
Fiducial ID
|
||||
</th>
|
||||
<template v-if="!useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
<th class="text-center">
|
||||
Pitch θ°
|
||||
</th>
|
||||
<th class="text-center">
|
||||
Yaw θ°
|
||||
</th>
|
||||
<th class="text-center">
|
||||
Skew θ°
|
||||
</th>
|
||||
<th class="text-center">
|
||||
Area %
|
||||
</th>
|
||||
<th class="text-center">Pitch θ°</th>
|
||||
<th class="text-center">Yaw θ°</th>
|
||||
<th class="text-center">Skew θ°</th>
|
||||
<th class="text-center">Area %</th>
|
||||
</template>
|
||||
<template v-else>
|
||||
<th class="text-center">
|
||||
X meters
|
||||
</th>
|
||||
<th class="text-center">
|
||||
Y meters
|
||||
</th>
|
||||
<th class="text-center">
|
||||
Z Angle θ°
|
||||
</th>
|
||||
<th class="text-center">X meters</th>
|
||||
<th class="text-center">Y meters</th>
|
||||
<th class="text-center">Z Angle θ°</th>
|
||||
</template>
|
||||
<template v-if="useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag && useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
<th class="text-center">
|
||||
Ambiguity %
|
||||
</th>
|
||||
<template
|
||||
v-if="
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag &&
|
||||
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
||||
"
|
||||
>
|
||||
<th class="text-center">Ambiguity %</th>
|
||||
</template>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(target, index) in useStateStore().pipelineResults?.targets"
|
||||
:key="index"
|
||||
>
|
||||
<tr v-for="(target, index) in useStateStore().pipelineResults?.targets" :key="index">
|
||||
<td>{{ index }}</td>
|
||||
<td v-if="useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag || useCameraSettingsStore().currentPipelineType === PipelineType.Aruco">
|
||||
<td
|
||||
v-if="
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag ||
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.Aruco
|
||||
"
|
||||
>
|
||||
{{ target.fiducialId }}
|
||||
</td>
|
||||
<template v-if="!useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
@@ -80,9 +63,14 @@ import { useStateStore } from "@/stores/StateStore";
|
||||
<template v-else-if="useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
<td>{{ target.pose?.x.toFixed(2) }} m</td>
|
||||
<td>{{ target.pose?.y.toFixed(2) }} m</td>
|
||||
<td>{{ (target.pose?.angle_z * 180.0 / Math.PI).toFixed(2) }}°</td>
|
||||
<td>{{ ((target.pose?.angle_z * 180.0) / Math.PI).toFixed(2) }}°</td>
|
||||
</template>
|
||||
<template v-if="useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag && useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled">
|
||||
<template
|
||||
v-if="
|
||||
useCameraSettingsStore().currentPipelineType === PipelineType.AprilTag &&
|
||||
useCameraSettingsStore().currentPipelineSettings.solvePNPEnabled
|
||||
"
|
||||
>
|
||||
<td>{{ target.ambiguity?.toFixed(2) }}%</td>
|
||||
</template>
|
||||
</tr>
|
||||
@@ -100,7 +88,8 @@ import { useStateStore } from "@/stores/StateStore";
|
||||
text-align: center;
|
||||
background-color: #006492 !important;
|
||||
|
||||
th, td {
|
||||
th,
|
||||
td {
|
||||
background-color: #006492 !important;
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const averageHue = computed<number>(() => {
|
||||
const isHueInverted = useCameraSettingsStore().currentPipelineSettings.hueInverted;
|
||||
let val = Object.values(useCameraSettingsStore().currentPipelineSettings.hsvHue).reduce((a, b) => a + b, 0);
|
||||
|
||||
if(isHueInverted) val += 180;
|
||||
if (isHueInverted) val += 180;
|
||||
if (val > 360) val -= 360;
|
||||
|
||||
return val;
|
||||
@@ -19,23 +19,23 @@ const averageHue = computed<number>(() => {
|
||||
// TODO fix cv-range-slider so that store access doesn't need to be deferred
|
||||
const hsvHue = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.hsvHue) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.hsvHue = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.hsvHue = v)
|
||||
});
|
||||
const hsvSaturation = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.hsvSaturation) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.hsvSaturation = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.hsvSaturation = v)
|
||||
});
|
||||
const hsvValue = computed<[number, number]>({
|
||||
get: () => Object.values(useCameraSettingsStore().currentPipelineSettings.hsvValue) as [number, number],
|
||||
set: v => useCameraSettingsStore().currentPipelineSettings.hsvValue = v
|
||||
set: (v) => (useCameraSettingsStore().currentPipelineSettings.hsvValue = v)
|
||||
});
|
||||
|
||||
let selectedEventMode: 0 | 1 | 2 | 3 = 0;
|
||||
const handleStreamClick = (event: MouseEvent) => {
|
||||
if(!useStateStore().colorPickingMode || selectedEventMode === 0) return;
|
||||
if (!useStateStore().colorPickingMode || selectedEventMode === 0) return;
|
||||
|
||||
const cameraStream = document.getElementById("input-camera-stream");
|
||||
if(cameraStream === null) return;
|
||||
if (cameraStream === null) return;
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = cameraStream.clientWidth;
|
||||
@@ -43,18 +43,21 @@ const handleStreamClick = (event: MouseEvent) => {
|
||||
|
||||
// Get the (x, y) position of the click with (0, 0) in the top left corner
|
||||
const rect = cameraStream.getBoundingClientRect();
|
||||
const x = Math.round((event.clientX - rect.left) / rect.width * cameraStream.clientWidth);
|
||||
const y = Math.round((event.clientY - rect.top) / rect.height * cameraStream.clientHeight);
|
||||
const x = Math.round(((event.clientX - rect.left) / rect.width) * cameraStream.clientWidth);
|
||||
const y = Math.round(((event.clientY - rect.top) / rect.height) * cameraStream.clientHeight);
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
if(context === null) return;
|
||||
if (context === null) return;
|
||||
|
||||
context.drawImage(cameraStream as CanvasImageSource, 0, 0, cameraStream.clientWidth, cameraStream.clientHeight);
|
||||
const colorPicker = new ColorPicker(context.getImageData(x, y, 1, 1).data);
|
||||
|
||||
// Calculate HSV values based on the mode
|
||||
let selectedHSVData: [HSV, HSV] = [[0, 0, 0], [0, 0, 0]];
|
||||
if(selectedEventMode === 1) {
|
||||
let selectedHSVData: [HSV, HSV] = [
|
||||
[0, 0, 0],
|
||||
[0, 0, 0]
|
||||
];
|
||||
if (selectedEventMode === 1) {
|
||||
selectedHSVData = colorPicker.selectedColorRange();
|
||||
} else {
|
||||
const currentHue = Object.values(useCameraSettingsStore().currentPipelineSettings.hsvHue);
|
||||
@@ -66,19 +69,22 @@ const handleStreamClick = (event: MouseEvent) => {
|
||||
[currentHue[1], currentSaturation[1], currentValue[1]]
|
||||
];
|
||||
|
||||
if(selectedEventMode === 2) {
|
||||
if (selectedEventMode === 2) {
|
||||
selectedHSVData = colorPicker.expandColorRange(currentData);
|
||||
} else if(selectedEventMode === 3) {
|
||||
} else if (selectedEventMode === 3) {
|
||||
selectedHSVData = colorPicker.shrinkColorRange(currentData);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the store and backend with the new HSV values
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({
|
||||
hsvHue: [selectedHSVData[0][0], selectedHSVData[1][0]],
|
||||
hsvSaturation: [selectedHSVData[0][1], selectedHSVData[1][1]],
|
||||
hsvValue: [selectedHSVData[0][2], selectedHSVData[1][2]]
|
||||
}, true);
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting(
|
||||
{
|
||||
hsvHue: [selectedHSVData[0][0], selectedHSVData[1][0]],
|
||||
hsvSaturation: [selectedHSVData[0][1], selectedHSVData[1][1]],
|
||||
hsvValue: [selectedHSVData[0][2], selectedHSVData[1][2]]
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
disableColorPicking();
|
||||
};
|
||||
@@ -90,36 +96,45 @@ const enableColorPicking = (mode: 1 | 2 | 3) => {
|
||||
useStateStore().colorPickingMode = true;
|
||||
inputShowing = useCameraSettingsStore().currentPipelineSettings.inputShouldShow;
|
||||
outputShowing = useCameraSettingsStore().currentPipelineSettings.outputShouldShow;
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ outputShouldDraw: false, inputShouldShow: true, outputShouldShow: false }, true);
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting(
|
||||
{ outputShouldDraw: false, inputShouldShow: true, outputShouldShow: false },
|
||||
true
|
||||
);
|
||||
selectedEventMode = mode;
|
||||
};
|
||||
const disableColorPicking = () => {
|
||||
useStateStore().colorPickingMode = false;
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting({ outputShouldDraw: true, inputShouldShow: inputShowing, outputShouldShow: outputShowing }, true);
|
||||
useCameraSettingsStore().changeCurrentPipelineSetting(
|
||||
{ outputShouldDraw: true, inputShouldShow: inputShowing, outputShouldShow: outputShowing },
|
||||
true
|
||||
);
|
||||
selectedEventMode = 0;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const cameraStream = document.getElementById("input-camera-stream");
|
||||
if(cameraStream === null) return;
|
||||
if (cameraStream === null) return;
|
||||
|
||||
cameraStream.addEventListener("click", handleStreamClick);
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
const cameraStream = document.getElementById("input-camera-stream");
|
||||
if(cameraStream === null) return;
|
||||
if (cameraStream === null) return;
|
||||
|
||||
cameraStream.removeEventListener("click", handleStreamClick);
|
||||
});
|
||||
|
||||
const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) && (!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)) ? 9 : 8;
|
||||
const interactiveCols = computed(
|
||||
() =>
|
||||
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
|
||||
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
|
||||
)
|
||||
? 9
|
||||
: 8;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="threshold-modifiers"
|
||||
:style="{'--averageHue': averageHue}"
|
||||
>
|
||||
<div class="threshold-modifiers" :style="{ '--averageHue': averageHue }">
|
||||
<cv-range-slider
|
||||
id="hue-slider"
|
||||
v-model="hsvHue"
|
||||
@@ -130,7 +145,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:max="180"
|
||||
:slider-cols="interactiveCols"
|
||||
:inverted="useCameraSettingsStore().currentPipelineSettings.hueInverted"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({hsvHue: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvHue: value }, false)"
|
||||
/>
|
||||
<cv-range-slider
|
||||
id="sat-slider"
|
||||
@@ -141,7 +156,7 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="255"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({hsvSaturation: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvSaturation: value }, false)"
|
||||
/>
|
||||
<cv-range-slider
|
||||
id="value-slider"
|
||||
@@ -152,26 +167,19 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
:min="0"
|
||||
:max="255"
|
||||
:slider-cols="interactiveCols"
|
||||
@input="value => useCameraSettingsStore().changeCurrentPipelineSetting({hsvValue: value}, false)"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hsvValue: value }, false)"
|
||||
/>
|
||||
<cv-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)"
|
||||
/>
|
||||
<v-divider
|
||||
class="mt-3"
|
||||
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ hueInverted: value }, false)"
|
||||
/>
|
||||
<v-divider class="mt-3" />
|
||||
<div>
|
||||
<div class="pt-3 white--text">
|
||||
Color Picker
|
||||
</div>
|
||||
<v-row
|
||||
justify="center"
|
||||
class="mt-3 mb-3"
|
||||
>
|
||||
<div class="pt-3 white--text">Color Picker</div>
|
||||
<v-row justify="center" class="mt-3 mb-3">
|
||||
<template v-if="!useStateStore().colorPickingMode">
|
||||
<v-btn
|
||||
color="accent"
|
||||
@@ -179,42 +187,25 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
small
|
||||
@click="enableColorPicking(useCameraSettingsStore().currentPipelineSettings.hueInverted ? 2 : 3)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-minus
|
||||
</v-icon>
|
||||
<v-icon left> mdi-minus </v-icon>
|
||||
Shrink Range
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="enableColorPicking(1)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-plus-minus
|
||||
</v-icon>
|
||||
<v-btn color="accent" class="ma-2 black--text" small @click="enableColorPicking(1)">
|
||||
<v-icon left> mdi-plus-minus </v-icon>
|
||||
{{ useCameraSettingsStore().currentPipelineSettings.hueInverted ? "Exclude" : "Set to" }} Average
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
small
|
||||
@click="enableColorPicking(useCameraSettingsStore().currentPipelineSettings.hueInverted ? 3: 2)"
|
||||
@click="enableColorPicking(useCameraSettingsStore().currentPipelineSettings.hueInverted ? 3 : 2)"
|
||||
>
|
||||
<v-icon left>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
<v-icon left> mdi-plus </v-icon>
|
||||
Expand Range
|
||||
</v-btn>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-btn
|
||||
color="accent"
|
||||
class="ma-2 black--text"
|
||||
style="width: 30%;"
|
||||
small
|
||||
@click="disableColorPicking"
|
||||
>
|
||||
<v-btn color="accent" class="ma-2 black--text" style="width: 30%" small @click="disableColorPicking">
|
||||
Cancel
|
||||
</v-btn>
|
||||
</template>
|
||||
@@ -228,18 +219,21 @@ const interactiveCols = computed(() => (getCurrentInstance()?.proxy.$vuetify.bre
|
||||
--averageHue: 0;
|
||||
}
|
||||
#hue-slider >>> .v-slider {
|
||||
background: linear-gradient( to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100% );
|
||||
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 {
|
||||
background: linear-gradient( to right, #fff 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||
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 {
|
||||
background: linear-gradient( to right, #000 0%, hsl(var(--averageHue), 100%, 50%) 100% );
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user