Skip to content

Commit 618072c

Browse files
Add Camera Focus Mode (#2180)
## Description Camera focus tool pipeline using a Laplacian and finding the variance. Similar to Limelight. closes #1597 ## 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_ - [x] This PR has been [linted](https://docs.photonvision.org/en/latest/docs/contributing/linting.html). - [x] 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 v2025.3.2 - [x] 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
1 parent 7d2c69d commit 618072c

File tree

19 files changed

+312
-10
lines changed

19 files changed

+312
-10
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Camera Focusing
2+
3+
## Prepare Camera
4+
:::{warning}
5+
Refocusing your camera **will** make your calibration inaccurate, make sure to recalibrate after focusing.
6+
:::
7+
To ensure that your camera is focused properly, mount it to a secure surface and ensure it does not move drastically. Point your camera at a detailed surface like a calibration board, and make sure that it not too close to the camera.
8+
9+
## Using Focus Mode
10+
:::{important}
11+
When you enable Focus Mode, it will assign a *Score* to the current focus, this score depends on your environment and the lighting. This score cannot be compared to a focus score collected from other environments.
12+
:::
13+
- In the Cameras tab, turn on Focus Mode.
14+
- Rotate the lens on your camera to try and get the focus score as high as possible.
15+
- Once you cannot get a higher score, this indicates that your camera is fully focused and can be set in place using glue if desired.
16+
17+
```{image} images/focusModeExample.png
18+
:scale: 50%
19+
```
313 KB
Loading

docs/source/docs/quick-start/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ wiring
99
networking
1010
camera-matching
1111
camera-calibration
12+
camera-focusing
1213
quick-configure
1314
```

photon-client/src/components/cameras/CameraSettingsCard.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
33
import PvInput from "@/components/common/pv-input.vue";
44
import PvNumberInput from "@/components/common/pv-number-input.vue";
5+
import PvSwitch from "@/components/common/pv-switch.vue";
56
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
67
import { useStateStore } from "@/stores/StateStore";
78
import { computed, ref, watchEffect } from "vue";
@@ -15,7 +16,14 @@ const tempSettingsStruct = ref<CameraSettingsChangeRequest>({
1516
fov: useCameraSettingsStore().currentCameraSettings.fov.value,
1617
quirksToChange: Object.assign({}, useCameraSettingsStore().currentCameraSettings.cameraQuirks.quirks)
1718
});
18-
19+
const focusMode = computed<boolean>({
20+
get: () => useCameraSettingsStore().isFocusMode,
21+
set: (v) =>
22+
useCameraSettingsStore().changeCurrentPipelineIndex(
23+
v ? -3 : useCameraSettingsStore().currentCameraSettings.lastPipelineIndex || 0,
24+
true
25+
)
26+
});
1927
const arducamSelectWrapper = computed<number>({
2028
get: () => {
2129
if (tempSettingsStruct.value.quirksToChange.ArduOV9281Controls) return 1;
@@ -166,6 +174,11 @@ const wrappedCameras = computed<SelectItem[]>(() =>
166174
]"
167175
:select-cols="8"
168176
/>
177+
<pv-switch
178+
v-model="focusMode"
179+
tooltip="Enable Focus Mode to start focusing the lens on your camera"
180+
label="Focus Mode"
181+
></pv-switch>
169182
</v-card-text>
170183
<v-card-text class="d-flex pt-0">
171184
<v-col cols="6" class="pa-0 pr-2">

photon-client/src/components/cameras/CamerasView.vue

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ const fpsTooLow = computed<boolean>(() => {
5858
<v-chip v-else label color="red" variant="text" style="font-size: 1rem; padding: 0; margin: 0">
5959
<span class="pr-1">Camera not connected</span>
6060
</v-chip>
61+
<v-chip
62+
v-if="useCameraSettingsStore().isFocusMode"
63+
label
64+
color="primary"
65+
variant="text"
66+
style="font-size: 1rem; padding: 0; margin: auto"
67+
>
68+
<span class="pr-1"> Focus: {{ Math.round(useStateStore().currentPipelineResults?.focus || 0) }} </span>
69+
</v-chip>
6170
<v-switch
6271
v-model="driverMode"
6372
:disabled="useCameraSettingsStore().isCalibrationMode || useCameraSettingsStore().pipelineNames.length === 0"
@@ -95,7 +104,11 @@ const fpsTooLow = computed<boolean>(() => {
95104
color="buttonPassive"
96105
class="fill"
97106
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
98-
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
107+
:disabled="
108+
useCameraSettingsStore().isDriverMode ||
109+
useCameraSettingsStore().isCalibrationMode ||
110+
useCameraSettingsStore().isFocusMode
111+
"
99112
>
100113
<v-icon start class="mode-btn-icon" size="large">mdi-import</v-icon>
101114
<span class="mode-btn-label">Raw</span>
@@ -104,7 +117,11 @@ const fpsTooLow = computed<boolean>(() => {
104117
color="buttonPassive"
105118
class="fill"
106119
:variant="theme.global.name.value === 'LightTheme' ? 'elevated' : 'outlined'"
107-
:disabled="useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isCalibrationMode"
120+
:disabled="
121+
useCameraSettingsStore().isDriverMode ||
122+
useCameraSettingsStore().isCalibrationMode ||
123+
useCameraSettingsStore().isFocusMode
124+
"
108125
>
109126
<v-icon start class="mode-btn-icon" size="large">mdi-export</v-icon>
110127
<span class="mode-btn-label">Processed</span>

photon-client/src/components/dashboard/CameraAndPipelineSelectCard.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ const pipelineNamesWrapper = computed<SelectItem[]>(() => {
9292
if (useCameraSettingsStore().isDriverMode) {
9393
pipelineNames.push({ name: "Driver Mode", value: WebsocketPipelineType.DriverMode });
9494
}
95+
if (useCameraSettingsStore().isFocusMode) {
96+
pipelineNames.push({ name: "Focus Mode", value: WebsocketPipelineType.FocusCamera });
97+
}
9598
if (useCameraSettingsStore().isCalibrationMode) {
9699
pipelineNames.push({ name: "3D Calibration Mode", value: WebsocketPipelineType.Calib3d });
97100
}
@@ -177,6 +180,9 @@ const pipelineTypesWrapper = computed<{ name: string; value: number }[]>(() => {
177180
if (useCameraSettingsStore().isDriverMode) {
178181
pipelineTypes.push({ name: "Driver Mode", value: WebsocketPipelineType.DriverMode });
179182
}
183+
if (useCameraSettingsStore().isFocusMode) {
184+
pipelineTypes.push({ name: "Focus Mode", value: WebsocketPipelineType.FocusCamera });
185+
}
180186
if (useCameraSettingsStore().isCalibrationMode) {
181187
pipelineTypes.push({ name: "3D Calibration Mode", value: WebsocketPipelineType.Calib3d });
182188
}
@@ -187,6 +193,7 @@ const pipelineType = ref<WebsocketPipelineType>(useCameraSettingsStore().current
187193
const currentPipelineType = computed<WebsocketPipelineType>({
188194
get: () => {
189195
if (useCameraSettingsStore().isDriverMode) return WebsocketPipelineType.DriverMode;
196+
if (useCameraSettingsStore().isFocusMode) return WebsocketPipelineType.FocusCamera;
190197
if (useCameraSettingsStore().isCalibrationMode) return WebsocketPipelineType.Calib3d;
191198
return pipelineType.value;
192199
},
@@ -290,6 +297,7 @@ const wrappedCameras = computed<SelectItem[]>(() =>
290297
tooltip="Each pipeline runs on a camera output and stores a unique set of processing settings"
291298
:disabled="
292299
useCameraSettingsStore().isDriverMode ||
300+
useCameraSettingsStore().isFocusMode ||
293301
useCameraSettingsStore().isCalibrationMode ||
294302
!useCameraSettingsStore().hasConnected
295303
"
@@ -366,6 +374,7 @@ const wrappedCameras = computed<SelectItem[]>(() =>
366374
tooltip="Changes the pipeline type, which changes the type of processing that will happen on input frames"
367375
:disabled="
368376
useCameraSettingsStore().isDriverMode ||
377+
useCameraSettingsStore().isFocusMode ||
369378
useCameraSettingsStore().isCalibrationMode ||
370379
!useCameraSettingsStore().hasConnected
371380
"

photon-client/src/components/dashboard/StreamConfigCard.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ const processingMode = computed<number>({
2121

2222
<template>
2323
<v-card
24-
:disabled="useCameraSettingsStore().isDriverMode || useStateStore().colorPickingMode"
24+
:disabled="
25+
useCameraSettingsStore().isDriverMode || useCameraSettingsStore().isFocusMode || useStateStore().colorPickingMode
26+
"
2527
class="mt-3 rounded-12"
2628
color="surface"
2729
style="flex-grow: 1; display: flex; flex-direction: column"

photon-client/src/stores/settings/CameraSettingsStore.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
7676
isCalibrationMode(): boolean {
7777
return this.currentCameraSettings.currentPipelineIndex == WebsocketPipelineType.Calib3d;
7878
},
79+
isFocusMode(): boolean {
80+
return this.currentCameraSettings.currentPipelineIndex == WebsocketPipelineType.FocusCamera;
81+
},
7982
isCSICamera(): boolean {
8083
return this.currentCameraSettings.isCSICamera;
8184
},

photon-client/src/types/PhotonTrackingTypes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ export interface PipelineResult {
7070
sequenceID: number;
7171
fps: number;
7272
latency: number;
73+
// Focus pipeline
74+
focus?: number;
7375
targets: PhotonTarget[];
7476
// undefined if multitag failed or non-tag pipeline
7577
multitagResult?: MultitagResult;

photon-client/src/types/WebsocketDataTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export interface IncomingWebsocketData {
110110
}
111111

112112
export enum WebsocketPipelineType {
113+
FocusCamera = -3,
113114
Calib3d = -2,
114115
DriverMode = -1,
115116
Reflective = 0,

0 commit comments

Comments
 (0)