mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-02 02:51:40 +00:00
Convert to user selected camera matching (#1556)
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, ref, onBeforeUnmount } from "vue";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import loadingImage from "@/assets/images/loading.svg";
|
||||
import type { StyleValue } from "vue/types/jsx";
|
||||
import PvIcon from "@/components/common/pv-icon.vue";
|
||||
import type { UiCameraConfiguration } from "@/types/SettingTypes";
|
||||
|
||||
const props = defineProps<{
|
||||
streamType: "Raw" | "Processed";
|
||||
id: string;
|
||||
cameraSettings: UiCameraConfiguration;
|
||||
}>();
|
||||
|
||||
const emptyStreamSrc = "//:0";
|
||||
const streamSrc = computed<string>(() => {
|
||||
const port =
|
||||
useCameraSettingsStore().currentCameraSettings.stream[props.streamType === "Raw" ? "inputPort" : "outputPort"];
|
||||
const port = props.cameraSettings.stream[props.streamType === "Raw" ? "inputPort" : "outputPort"];
|
||||
|
||||
if (!useStateStore().backendConnected || port === 0) {
|
||||
return emptyStreamSrc;
|
||||
@@ -32,8 +32,12 @@ const streamStyle = computed<StyleValue>(() => {
|
||||
});
|
||||
|
||||
const containerStyle = computed<StyleValue>(() => {
|
||||
const resolution = useCameraSettingsStore().currentVideoFormat.resolution;
|
||||
const rotation = useCameraSettingsStore().currentPipelineSettings.inputImageRotationMode;
|
||||
if (props.cameraSettings.validVideoFormats.length === 0) {
|
||||
return { aspectRatio: "1/1" };
|
||||
}
|
||||
const resolution =
|
||||
props.cameraSettings.validVideoFormats[props.cameraSettings.pipelineSettings.cameraVideoModeIndex].resolution;
|
||||
const rotation = props.cameraSettings.pipelineSettings.inputImageRotationMode;
|
||||
if (rotation === 1 || rotation === 3) {
|
||||
return {
|
||||
aspectRatio: `${resolution.height}/${resolution.width}`
|
||||
@@ -54,9 +58,9 @@ const overlayStyle = computed<StyleValue>(() => {
|
||||
|
||||
const handleCaptureClick = () => {
|
||||
if (props.streamType === "Raw") {
|
||||
useCameraSettingsStore().saveInputSnapshot();
|
||||
props.cameraSettings.pipelineSettings[props.cameraSettings.currentPipelineIndex].saveInputSnapshot();
|
||||
} else {
|
||||
useCameraSettingsStore().saveOutputSnapshot();
|
||||
props.cameraSettings.pipelineSettings[props.cameraSettings.currentPipelineIndex].saveOutputSnapshot();
|
||||
}
|
||||
};
|
||||
const handlePopoutClick = () => {
|
||||
@@ -69,6 +73,16 @@ const handleFullscreenRequest = () => {
|
||||
};
|
||||
|
||||
const mjpgStream: any = ref(null);
|
||||
|
||||
const handleStreamError = () => {
|
||||
if (streamSrc.value && streamSrc.value !== emptyStreamSrc) {
|
||||
console.error("Error loading stream:", streamSrc.value, " Trying again.");
|
||||
setTimeout(() => {
|
||||
mjpgStream.value.src = streamSrc.value;
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (!mjpgStream.value) return;
|
||||
mjpgStream.value["src"] = emptyStreamSrc;
|
||||
@@ -79,7 +93,6 @@ onBeforeUnmount(() => {
|
||||
<div class="stream-container" :style="containerStyle">
|
||||
<img :src="loadingImage" class="stream-loading" />
|
||||
<img
|
||||
v-show="streamSrc !== emptyStreamSrc"
|
||||
:id="id"
|
||||
ref="mjpgStream"
|
||||
class="stream-video"
|
||||
@@ -87,6 +100,7 @@ onBeforeUnmount(() => {
|
||||
:src="streamSrc"
|
||||
:alt="streamDesc"
|
||||
:style="streamStyle"
|
||||
@error="handleStreamError"
|
||||
/>
|
||||
<div class="stream-overlay" :style="overlayStyle">
|
||||
<pv-icon
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
import { computed, getCurrentInstance } from "vue";
|
||||
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
|
||||
import { PlaceholderCameraSettings } from "@/types/SettingTypes";
|
||||
import { useRoute } from "vue2-helpers/vue-router";
|
||||
|
||||
const compact = computed<boolean>({
|
||||
get: () => {
|
||||
@@ -14,6 +17,12 @@ const compact = computed<boolean>({
|
||||
|
||||
// Vuetify2 doesn't yet support the useDisplay API so this is required to access the prop when using the Composition API
|
||||
const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndUp || false);
|
||||
|
||||
const needsCamerasConfigured = computed<boolean>(() => {
|
||||
return (
|
||||
useCameraSettingsStore().cameras.length === 0 || useCameraSettingsStore().cameras[0] === PlaceholderCameraSettings
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -35,14 +44,6 @@ const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.bre
|
||||
<v-list-item-title>Dashboard</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item ref="camerasTabOpener" link to="/cameras">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-camera</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Cameras</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item link to="/settings">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-cog</v-icon>
|
||||
@@ -51,6 +52,26 @@ const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.bre
|
||||
<v-list-item-title>Settings</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item ref="camerasTabOpener" link to="/cameras">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-camera</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>Camera</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
link
|
||||
to="/cameraConfigs"
|
||||
:class="{ cameraicon: needsCamerasConfigured && useRoute().path !== '/cameraConfigs' }"
|
||||
>
|
||||
<v-list-item-icon>
|
||||
<v-icon :class="{ 'red--text': needsCamerasConfigured }">mdi-swap-horizontal-bold</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title :class="{ 'red--text': needsCamerasConfigured }">Camera Matching</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item link to="/docs">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-bookshelf</v-icon>
|
||||
@@ -119,4 +140,18 @@ const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.bre
|
||||
height: 70px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.cameraicon {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,6 +20,7 @@ const settingsValid = ref(true);
|
||||
|
||||
const getUniqueVideoFormatsByResolution = (): VideoFormat[] => {
|
||||
const uniqueResolutions: VideoFormat[] = [];
|
||||
if (useCameraSettingsStore().currentCameraSettings.validVideoFormats.length === 0) return uniqueResolutions;
|
||||
useCameraSettingsStore().currentCameraSettings.validVideoFormats.forEach((format) => {
|
||||
const index = uniqueResolutions.findIndex((v) => resolutionsAreEqual(v.resolution, format.resolution));
|
||||
const contains = index != -1;
|
||||
@@ -248,7 +249,7 @@ const setSelectedVideoFormat = (format: VideoFormat) => {
|
||||
</v-simple-table>
|
||||
</v-row>
|
||||
<v-divider />
|
||||
<v-row style="display: flex; flex-direction: column" class="mt-4">
|
||||
<v-row v-if="useCameraSettingsStore().isConnected" style="display: flex; flex-direction: column" class="mt-4">
|
||||
<v-card-subtitle v-show="!isCalibrating" class="pl-3 pa-0 ma-0"> Configure New Calibration</v-card-subtitle>
|
||||
<v-form ref="form" v-model="settingsValid" class="pl-4 mb-10 pr-5">
|
||||
<!-- TODO: the default videoFormatIndex is 0, but the list of unique video mode indexes might not include 0. getUniqueVideoResolutionStrings indexing is also different from the normal video mode indexing -->
|
||||
|
||||
@@ -57,6 +57,7 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
</div>
|
||||
<div>
|
||||
<v-chip
|
||||
v-if="useCameraSettingsStore().currentCameraSettings.isConnected"
|
||||
label
|
||||
:color="fpsTooLow ? 'error' : 'transparent'"
|
||||
:text-color="fpsTooLow ? '#C7EA46' : '#ff4d00'"
|
||||
@@ -67,6 +68,9 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
{{ Math.min(Math.round(useStateStore().currentPipelineResults?.latency || 0), 9999) }} ms latency
|
||||
</span>
|
||||
</v-chip>
|
||||
<v-chip v-else label color="transparent" text-color="red" style="font-size: 1rem; padding: 0; margin: 0">
|
||||
<span class="pr-1"> Camera not connected </span>
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,6 +90,7 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
<photon-camera-stream
|
||||
v-if="value.includes(0)"
|
||||
id="input-camera-stream"
|
||||
:camera-settings="useCameraSettingsStore().currentCameraSettings"
|
||||
stream-type="Raw"
|
||||
style="max-width: 100%"
|
||||
/>
|
||||
@@ -94,6 +99,7 @@ const fpsTooLow = computed<boolean>(() => {
|
||||
<photon-camera-stream
|
||||
v-if="value.includes(1)"
|
||||
id="output-camera-stream"
|
||||
:camera-settings="useCameraSettingsStore().currentCameraSettings"
|
||||
stream-type="Processed"
|
||||
style="max-width: 100%"
|
||||
/>
|
||||
|
||||
75
photon-client/src/components/common/pv-camera-info-card.vue
Normal file
75
photon-client/src/components/common/pv-camera-info-card.vue
Normal file
@@ -0,0 +1,75 @@
|
||||
<script setup lang="ts">
|
||||
import { PVCameraInfo } from "@/types/SettingTypes";
|
||||
|
||||
const { camera, showTitle } = defineProps({
|
||||
camera: {
|
||||
type: PVCameraInfo,
|
||||
required: true
|
||||
},
|
||||
showTitle: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
const cameraInfoFor: any = (camera: PVCameraInfo) => {
|
||||
if (camera.PVUsbCameraInfo) {
|
||||
return camera.PVUsbCameraInfo;
|
||||
}
|
||||
if (camera.PVCSICameraInfo) {
|
||||
return camera.PVCSICameraInfo;
|
||||
}
|
||||
if (camera.PVFileCameraInfo) {
|
||||
return camera.PVFileCameraInfo;
|
||||
}
|
||||
return {};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="showTitle === true">
|
||||
<h3 v-if="camera.PVUsbCameraInfo" class="mb-3">USB Camera Info</h3>
|
||||
<h3 v-if="camera.PVCSICameraInfo" class="mb-3">CSI Camera Info</h3>
|
||||
<h3 v-if="camera.PVFileCameraInfo" class="mb-3">File Camera Info</h3>
|
||||
</div>
|
||||
|
||||
<v-simple-table dense :style="{ backgroundColor: 'var(--v-primary-base)' }">
|
||||
<tbody>
|
||||
<tr v-if="cameraInfoFor(camera).dev !== undefined && cameraInfoFor(camera).dev !== null">
|
||||
<td>Device Number:</td>
|
||||
<td>{{ cameraInfoFor(camera).dev }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).name !== undefined && cameraInfoFor(camera).name !== null">
|
||||
<td>Name:</td>
|
||||
<td>{{ cameraInfoFor(camera).name }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).baseName !== undefined && cameraInfoFor(camera).baseName !== null">
|
||||
<td>Base Name:</td>
|
||||
<td>{{ cameraInfoFor(camera).baseName }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).vendorId !== undefined && cameraInfoFor(camera).vendorId !== null">
|
||||
<td>Vendor ID:</td>
|
||||
<td>{{ cameraInfoFor(camera).vendorId }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).productId !== undefined && cameraInfoFor(camera).productId !== null">
|
||||
<td>Product ID:</td>
|
||||
<td>{{ cameraInfoFor(camera).productId }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).path !== undefined && cameraInfoFor(camera).path !== null">
|
||||
<td>Path:</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(camera).path }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).otherPaths !== undefined && cameraInfoFor(camera).otherPaths !== null">
|
||||
<td>Other Paths:</td>
|
||||
<td>{{ cameraInfoFor(camera).otherPaths }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(camera).uniquePath !== undefined && cameraInfoFor(camera).uniquePath !== null">
|
||||
<td>Unique Path:</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(camera).uniquePath }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</div>
|
||||
</template>
|
||||
85
photon-client/src/components/common/pv-camera-match-card.vue
Normal file
85
photon-client/src/components/common/pv-camera-match-card.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<script setup lang="ts">
|
||||
import { PVCameraInfo } from "@/types/SettingTypes";
|
||||
|
||||
const { saved, matched } = defineProps({
|
||||
saved: {
|
||||
type: PVCameraInfo,
|
||||
required: true
|
||||
},
|
||||
matched: {
|
||||
type: PVCameraInfo,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
|
||||
const cameraInfoFor = (camera: PVCameraInfo): any => {
|
||||
if (camera.PVUsbCameraInfo) {
|
||||
return camera.PVUsbCameraInfo;
|
||||
}
|
||||
if (camera.PVCSICameraInfo) {
|
||||
return camera.PVCSICameraInfo;
|
||||
}
|
||||
if (camera.PVFileCameraInfo) {
|
||||
return camera.PVFileCameraInfo;
|
||||
}
|
||||
return {};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h3 v-if="saved.PVUsbCameraInfo" class="mb-3">USB Camera Info</h3>
|
||||
<h3 v-if="saved.PVCSICameraInfo" class="mb-3">CSI Camera Info</h3>
|
||||
<h3 v-if="saved.PVFileCameraInfo" class="mb-3">File Camera Info</h3>
|
||||
|
||||
<v-simple-table dense :style="{ backgroundColor: 'var(--v-primary-base)' }">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Saved</th>
|
||||
<th>Matched</th>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).dev !== undefined && cameraInfoFor(saved).dev !== null">
|
||||
<td>Device Number:</td>
|
||||
<td>{{ cameraInfoFor(saved).dev }}</td>
|
||||
<td>{{ cameraInfoFor(matched).dev }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).name !== undefined && cameraInfoFor(saved).name !== null">
|
||||
<td>Name:</td>
|
||||
<td>{{ cameraInfoFor(saved).name }}</td>
|
||||
<td>{{ cameraInfoFor(matched).name }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).baseName !== undefined && cameraInfoFor(saved).baseName !== null">
|
||||
<td>Base Name:</td>
|
||||
<td>{{ cameraInfoFor(saved).baseName }}</td>
|
||||
<td>{{ cameraInfoFor(matched).baseName }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).vendorId !== undefined && cameraInfoFor(saved).vendorId !== null">
|
||||
<td>Vendor ID:</td>
|
||||
<td>{{ cameraInfoFor(saved).vendorId }}</td>
|
||||
<td>{{ cameraInfoFor(matched).vendorId }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).productId !== undefined && cameraInfoFor(saved).productId !== null">
|
||||
<td>Product ID:</td>
|
||||
<td>{{ cameraInfoFor(saved).productId }}</td>
|
||||
<td>{{ cameraInfoFor(matched).productId }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).path !== undefined && cameraInfoFor(saved).path !== null">
|
||||
<td>Path:</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(saved).path }}</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(matched).path }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).otherPaths !== undefined && cameraInfoFor(saved).otherPaths !== null">
|
||||
<td>Other Paths:</td>
|
||||
<td>{{ cameraInfoFor(saved).otherPaths }}</td>
|
||||
<td>{{ cameraInfoFor(matched).otherPaths }}</td>
|
||||
</tr>
|
||||
<tr v-if="cameraInfoFor(saved).uniquePath !== undefined && cameraInfoFor(saved).uniquePath !== null">
|
||||
<td>Unique Path:</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(saved).uniquePath }}</td>
|
||||
<td style="word-break: break-all">{{ cameraInfoFor(matched).uniquePath }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</div>
|
||||
</template>
|
||||
@@ -81,7 +81,7 @@ const localValue = computed({
|
||||
type="number"
|
||||
style="width: 45px"
|
||||
:step="step"
|
||||
hide-spin-buttons="true"
|
||||
:hide-spin-buttons="true"
|
||||
@keyup.enter="localValue = $event.target.value"
|
||||
@blur="localValue = $event.target.value"
|
||||
/>
|
||||
|
||||
@@ -14,7 +14,8 @@ const props = withDefaults(
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
labelCols: 2
|
||||
labelCols: 2,
|
||||
switchCols: 8
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -282,7 +282,11 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
|
||||
:value="useCameraSettingsStore().currentCameraSettings.currentPipelineIndex"
|
||||
label="Pipeline"
|
||||
tooltip="Each pipeline runs on a camera output and stores a unique set of processing settings"
|
||||
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
|
||||
:disabled="
|
||||
useCameraSettingsStore().isDriverMode ||
|
||||
useCameraSettingsStore().isCalibrationMode ||
|
||||
!useCameraSettingsStore().hasConnected
|
||||
"
|
||||
:items="pipelineNamesWrapper"
|
||||
@input="(args) => useCameraSettingsStore().changeCurrentPipelineIndex(args, true)"
|
||||
/>
|
||||
@@ -349,7 +353,11 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
|
||||
v-model="currentPipelineType"
|
||||
label="Type"
|
||||
tooltip="Changes the pipeline type, which changes the type of processing that will happen on input frames"
|
||||
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
|
||||
:disabled="
|
||||
useCameraSettingsStore().isDriverMode ||
|
||||
useCameraSettingsStore().isCalibrationMode ||
|
||||
!useCameraSettingsStore().hasConnected
|
||||
"
|
||||
:items="pipelineTypesWrapper"
|
||||
@input="showPipelineTypeChangeDialog = true"
|
||||
/>
|
||||
|
||||
@@ -49,6 +49,7 @@ const performanceRecommendation = computed<string>(() => {
|
||||
</v-col>
|
||||
<v-col class="align-self-center" style="text-align: right; margin-right: 12px; padding-left: 24px">
|
||||
<v-chip
|
||||
v-if="useCameraSettingsStore().currentCameraSettings.isConnected"
|
||||
label
|
||||
:color="fpsTooLow ? 'error' : 'transparent'"
|
||||
:text-color="fpsTooLow ? '#C7EA46' : '#ff4d00'"
|
||||
@@ -58,6 +59,9 @@ const performanceRecommendation = computed<string>(() => {
|
||||
>Processing @ {{ Math.round(useStateStore().currentPipelineResults?.fps || 0) }} FPS –</span
|
||||
><span>{{ performanceRecommendation }}</span>
|
||||
</v-chip>
|
||||
<v-chip v-else label color="transparent" text-color="red" style="font-size: 1rem; padding: 0; margin: 0">
|
||||
<span class="pr-1"> Camera not connected </span>
|
||||
</v-chip>
|
||||
</v-col>
|
||||
<v-col
|
||||
class="align-self-center"
|
||||
@@ -82,10 +86,20 @@ const performanceRecommendation = computed<string>(() => {
|
||||
<v-divider style="border-color: white" />
|
||||
<v-row class="stream-viewer-container pa-3">
|
||||
<v-col v-if="value.includes(0)" class="stream-view">
|
||||
<photon-camera-stream id="input-camera-stream" stream-type="Raw" style="width: 100%; height: auto" />
|
||||
<photon-camera-stream
|
||||
id="input-camera-stream"
|
||||
:camera-settings="useCameraSettingsStore().currentCameraSettings"
|
||||
stream-type="Raw"
|
||||
style="width: 100%; height: auto"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col v-if="value.includes(1)" class="stream-view">
|
||||
<photon-camera-stream id="output-camera-stream" stream-type="Processed" style="width: 100%; height: auto" />
|
||||
<photon-camera-stream
|
||||
id="output-camera-stream"
|
||||
:camera-settings="useCameraSettingsStore().currentCameraSettings"
|
||||
stream-type="Processed"
|
||||
style="width: 100%; height: auto"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
|
||||
@@ -145,31 +145,42 @@ onBeforeUpdate(() => {
|
||||
|
||||
<template>
|
||||
<v-row no-gutters class="tabGroups">
|
||||
<v-col
|
||||
v-for="(tabGroupData, tabGroupIndex) in tabGroups"
|
||||
:key="tabGroupIndex"
|
||||
:class="tabGroupIndex !== tabGroups.length - 1 && 'pr-3'"
|
||||
>
|
||||
<v-card color="primary" height="100%" class="pr-4 pl-4">
|
||||
<v-tabs
|
||||
v-model="selectedTabs[tabGroupIndex]"
|
||||
grow
|
||||
background-color="primary"
|
||||
dark
|
||||
height="48"
|
||||
slider-color="accent"
|
||||
>
|
||||
<v-tab v-for="(tabConfig, index) in tabGroupData" :key="index">
|
||||
{{ tabConfig.tabName }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<div class="pl-4 pr-4 pt-4 pb-2">
|
||||
<KeepAlive>
|
||||
<Component :is="tabGroupData[selectedTabs[tabGroupIndex]].component" />
|
||||
</KeepAlive>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<template v-if="!useCameraSettingsStore().hasConnected">
|
||||
<v-col v-if="!useCameraSettingsStore().hasConnected" cols="12">
|
||||
<v-card color="error">
|
||||
<v-card-title class="white--text">
|
||||
Camera has not connected. Please check your connection and try again.
|
||||
</v-card-title>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-col
|
||||
v-for="(tabGroupData, tabGroupIndex) in tabGroups"
|
||||
:key="tabGroupIndex"
|
||||
:class="tabGroupIndex !== tabGroups.length - 1 && 'pr-3'"
|
||||
>
|
||||
<v-card color="primary" height="100%" class="pr-4 pl-4">
|
||||
<v-tabs
|
||||
v-model="selectedTabs[tabGroupIndex]"
|
||||
grow
|
||||
background-color="primary"
|
||||
dark
|
||||
height="48"
|
||||
slider-color="accent"
|
||||
>
|
||||
<v-tab v-for="(tabConfig, index) in tabGroupData" :key="index">
|
||||
{{ tabConfig.tabName }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<div class="pl-4 pr-4 pt-4 pb-2">
|
||||
<KeepAlive>
|
||||
<Component :is="tabGroupData[selectedTabs[tabGroupIndex]].component" />
|
||||
</KeepAlive>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</template>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -38,11 +38,16 @@ const processingMode = computed<number>({
|
||||
<v-col>
|
||||
<p style="color: white">Processing Mode</p>
|
||||
<v-btn-toggle v-model="processingMode" mandatory dark class="fill">
|
||||
<v-btn color="secondary">
|
||||
<v-btn color="secondary" :disabled="!useCameraSettingsStore().hasConnected">
|
||||
<v-icon left>mdi-square-outline</v-icon>
|
||||
<span>2D</span>
|
||||
</v-btn>
|
||||
<v-btn color="secondary" :disabled="!useCameraSettingsStore().isCurrentVideoFormatCalibrated">
|
||||
<v-btn
|
||||
color="secondary"
|
||||
:disabled="
|
||||
!useCameraSettingsStore().hasConnected || !useCameraSettingsStore().isCurrentVideoFormatCalibrated
|
||||
"
|
||||
>
|
||||
<v-icon left>mdi-cube-outline</v-icon>
|
||||
<span>3D</span>
|
||||
</v-btn>
|
||||
|
||||
Reference in New Issue
Block a user