Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8936920
Stereo camera-file import/export, display, and length clearing
mattdawkins Jun 21, 2026
9238dd0
Start calibration menu
Louis-Pagnier-KW Jun 25, 2026
8990b8c
refac calibration menu + implement delete & download
Louis-Pagnier-KW Jun 25, 2026
7fa75e7
Show calibration filename and make calibration dialog work on desktop
mattdawkins Jun 26, 2026
16b5cbb
Fix calibration import for multicam child datasets
mattdawkins Jun 26, 2026
a195021
Calibration: convert mislabeled files, retain original name, reset-le…
mattdawkins Jun 26, 2026
a869b4a
Refine calibration import dialog labels and layout
mattdawkins Jun 26, 2026
7b7cd20
Fix lint in getDatasetCalibration request params
mattdawkins Jun 26, 2026
1c88a80
Fix lint errors in CalibrationDialog (v-for keys, unused vars, format…
mattdawkins Jun 26, 2026
50bfdb6
Web: report calibration filename when params can't be parsed
mattdawkins Jun 26, 2026
f44f268
Web: in-viewer calibration import with length reset
mattdawkins Jun 26, 2026
accae28
Web: convert non-JSON calibration to JSON via worker task
mattdawkins Jun 26, 2026
2ecf8d9
Fix web unit tests: lazy-load girderRest in importCalibrationFile
mattdawkins Jun 26, 2026
5d38638
Merge branch 'main' into dev/stereo-camera-file-io
BryonLewis Jun 27, 2026
6d71863
remove commented out code, remove the user settings reset and use onl…
BryonLewis Jun 27, 2026
5eb8f8b
resolve desktop import/export button differences
BryonLewis Jun 27, 2026
393e320
reduce camera selection size
BryonLewis Jun 27, 2026
8493dfa
button groups compressed text area
BryonLewis Jun 27, 2026
83b70d1
disable state for calibration icon when none exists
BryonLewis Jun 27, 2026
850c29b
utilize last calibration file in desktop if no calibration file found
BryonLewis Jun 27, 2026
3ed4f86
add datasetinfo dialog for linking and opening on desktop
BryonLewis Jun 27, 2026
9bdd510
import/export camera info, destop expor multicam all
BryonLewis Jun 27, 2026
8b08c56
use pipelines queue for VIAME access for calibration conversion
BryonLewis Jun 27, 2026
547f790
swap to creating a jsonCalibration file as another item
BryonLewis Jun 27, 2026
f3c4ab0
handle calibration json files with missing parameters
BryonLewis Jun 27, 2026
c8f5db9
add import calibration for stereoscopic web datasets
BryonLewis Jun 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions client/dive-common/apispec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,56 @@ interface DatasetMeta extends DatasetMetaMutable {
originalFps?: Readonly<number>;
subType: Readonly<SubType>; // In future this could have stuff like IR/EO
multiCamMedia: Readonly<MultiCamMedia | null>;
/** Stereo calibration / camera file currently associated with the dataset (desktop). */
calibration?: Readonly<string | null>;
}

interface CameraCalibration {
cx?: number
cy?: number
fx?: number
fy?: number
k1?: number
k2?: number
k3?: number
p1?: number
p2?: number
rmsError?: number
}

interface DatasetStereoCalibration {
R: number[]
T: number[]
gridHeight?: number
gridWidth?: number
imageHeight?: number
imageWidth?: number
squareSize?: number
rmsError?: number
calibrations: Record<string, CameraCalibration>
}

interface DatasetCalibrationResult {
/** Parsed calibration parameters from the JSON camera-rig file. */
calibration?: DatasetStereoCalibration
/** Source calibration item (calibrationFile). Used by pipelines and download. */
itemId?: string;
/** JSON camera-rig item (jsonCalibrationFile). Used for display parameters. */
jsonItemId?: string;
/** Source calibration filename. */
originalName?: string;
/** JSON camera-rig filename. */
jsonPath?: string;
/** Alias for jsonPath (legacy). */
path?: string;
}

interface Api {
getPipelineList(): Promise<Pipelines>;
runPipeline(itemId: string, pipeline: Pipe, pipelineParams?: PipelineParams): Promise<unknown>;
deleteTrainedPipeline(pipeline: Pipe): Promise<void>;
exportTrainedPipeline(path: string, pipeline: Pipe): Promise<unknown>;
getDatasetCalibration(datasetId: string): Promise<DatasetCalibrationResult | null>;

getTrainingConfigurations(): Promise<TrainingConfigs>;
runTraining(
Expand Down Expand Up @@ -257,6 +300,14 @@ interface Api {
// Desktop-only calibration persistence functions
getLastCalibration?(): Promise<string | null>;
saveCalibration?(path: string): Promise<{ savedPath: string; updatedDatasetIds: string[] }>;
/** Desktop: set the stereo camera/calibration file for a single dataset. */
importCalibrationFile?(datasetId: string, path: string): Promise<{ calibration: string }>;
/** Desktop: copy the dataset's current camera/calibration file out to destPath. */
exportCalibrationFile?(datasetId: string, destPath: string): Promise<{ exportedPath: string }>;
/** Download/export the dataset's current calibration file (platform-specific). */
downloadCalibration?(datasetId: string): Promise<void>;
/** Remove the calibration file currently associated with the dataset. */
deleteCalibration?(datasetId: string): Promise<void>;
}
const ApiSymbol = Symbol('api');

Expand Down Expand Up @@ -378,6 +429,9 @@ export {
DatasetMetaMutableKeys,
DatasetType,
DiveParam,
CameraCalibration,
DatasetStereoCalibration,
DatasetCalibrationResult,
SubType,
PipelineParamType,
FrameImage,
Expand Down
186 changes: 111 additions & 75 deletions client/dive-common/components/AnnotationVisibilityMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {

import { VisibleAnnotationTypes } from 'vue-media-annotator/layers';

import OutlinedLabeledGroup from './OutlinedLabeledGroup.vue';
import ToolbarExpandToggle from './ToolbarExpandToggle.vue';

interface ButtonData {
id: string;
icon: string;
Expand All @@ -20,6 +23,10 @@ interface ButtonData {

export default defineComponent({
name: 'AnnotationVisibilityMenu',
components: {
OutlinedLabeledGroup,
ToolbarExpandToggle,
},
props: {
visibleModes: {
type: Array as PropType<(VisibleAnnotationTypes)[]>,
Expand Down Expand Up @@ -117,6 +124,14 @@ export default defineComponent({
},
]));

const primaryViewButtons = computed(
() => viewButtons.value.filter((button) => button.id !== 'tooltip'),
);

const advancedVisibilityActive = computed(
() => isVisible('tooltip') || isVisible('TrackTail'),
);

const updateTailSettings = (type: 'before' | 'after', event: Event) => {
const value = Number.parseFloat((event.target as HTMLInputElement).value);
const settings = { ...props.tailSettings, [type]: value };
Expand All @@ -131,6 +146,8 @@ export default defineComponent({
isExpanded,
layoutKey,
viewButtons,
primaryViewButtons,
advancedVisibilityActive,
isVisible,
toggleVisible,
toggleExpanded,
Expand All @@ -142,7 +159,7 @@ export default defineComponent({
</script>

<template>
<span class="pb-1">
<span class="toolbar-group-host">
<!-- Dropdown mode when collapsed -->
<v-menu
v-if="!isExpanded"
Expand All @@ -154,19 +171,15 @@ export default defineComponent({
<template #activator="{ on, attrs }">
<v-btn
v-bind="attrs"
class="mx-1 mode-button"
class="mx-1 mode-button toolbar-group-activator"
small
v-on="on"
>
<v-icon>mdi-eye</v-icon>
<v-btn
icon
x-small
class="ml-1 expand-toggle"
@click.stop="toggleExpanded"
>
<v-icon small>mdi-chevron-right</v-icon>
</v-btn>
<toolbar-expand-toggle
:expanded="false"
@click="toggleExpanded"
/>
</v-btn>
</template>
<v-list dense>
Expand Down Expand Up @@ -254,29 +267,27 @@ export default defineComponent({
</v-menu>

<!-- Full button mode when expanded -->
<span
<outlined-labeled-group
v-else
:key="`visibility-${layoutKey}`"
class="visibility-expanded d-inline-flex align-center flex-wrap"
>
<span class="mr-1 px-3 py-1">
<v-icon class="pr-1">
mdi-eye
</v-icon>
<span class="text-subtitle-2">
Visibility
<template #legend>
<span class="d-inline-flex align-center">
<v-icon
small
class="pr-1"
>
mdi-eye
</v-icon>
<span>Visibility</span>
<toolbar-expand-toggle
:expanded="true"
@click="toggleExpanded"
/>
</span>
<v-btn
icon
x-small
class="ml-1 expand-toggle"
@click="toggleExpanded"
>
<v-icon small>mdi-chevron-left</v-icon>
</v-btn>
</span>
</template>
<template
v-for="button in viewButtons"
v-for="button in primaryViewButtons"
>
<v-menu
v-if="button.id === 'text'"
Expand Down Expand Up @@ -323,71 +334,96 @@ export default defineComponent({
</v-btn>
</template>
<v-menu
key="track-tail-settings"
open-on-hover
bottom
key="visibility-advanced"
offset-y
:close-on-content-click="false"
min-width="280"
>
<template #activator="{ on, attrs }">
<v-btn
v-bind="attrs"
:color="isVisible('TrackTail') ? 'grey darken-2' : ''"
class="mx-1 mode-button"
small
v-on="on"
@click="toggleVisible('TrackTail')"
>
<v-icon>mdi-navigation</v-icon>
</v-btn>
<template #activator="{ on: menuOn, attrs: menuAttrs }">
<v-tooltip bottom>
<template #activator="{ on: tooltipOn, attrs: tooltipAttrs }">
<v-btn
v-bind="{ ...menuAttrs, ...tooltipAttrs }"
:color="advancedVisibilityActive ? 'grey darken-2' : ''"
class="mx-1 mode-button"
small
v-on="{ ...menuOn, ...tooltipOn }"
>
<v-icon>mdi-tune</v-icon>
</v-btn>
</template>
<span>Advanced settings</span>
</v-tooltip>
</template>
<v-card
class="pa-4 flex-column d-flex"
class="pa-3 flex-column d-flex"
outlined
>
<label for="frames-before-full">Frames before: {{ tailSettings.before }}</label>
<input
id="frames-before-full"
type="range"
name="frames-before-full"
class="tail-slider-width"
label
min="0"
max="100"
:value="tailSettings.before"
@input="updateTailSettings('before', $event)"
>
<div class="py-2" />
<label for="frames-after-full">Frames after: {{ tailSettings.after }}</label>
<input
id="frames-after-full"
type="range"
name="frames-after-full"
class="tail-slider-width"
min="0"
max="100"
:value="tailSettings.after"
@input="updateTailSettings('after', $event)"
>
<div class="d-flex align-center advanced-menu-row">
<v-btn
:color="isVisible('tooltip') ? 'grey darken-2' : ''"
class="mode-button"
small
@click="toggleVisible('tooltip')"
>
<v-icon>mdi-tooltip-text-outline</v-icon>
</v-btn>
<span class="ml-2">Tooltip</span>
</div>
<div class="d-flex align-center advanced-menu-row">
<v-btn
:color="isVisible('TrackTail') ? 'grey darken-2' : ''"
class="mode-button"
small
@click="toggleVisible('TrackTail')"
>
<v-icon>mdi-navigation</v-icon>
</v-btn>
<span class="ml-2">Track Trails</span>
</div>
<template v-if="isVisible('TrackTail')">
<v-divider class="my-2" />
<label for="frames-before-full">Frames before: {{ tailSettings.before }}</label>
<input
id="frames-before-full"
type="range"
name="frames-before-full"
class="tail-slider-width"
min="0"
max="100"
:value="tailSettings.before"
@input="updateTailSettings('before', $event)"
>
<div class="py-2" />
<label for="frames-after-full">Frames after: {{ tailSettings.after }}</label>
<input
id="frames-after-full"
type="range"
name="frames-after-full"
class="tail-slider-width"
min="0"
max="100"
:value="tailSettings.after"
@input="updateTailSettings('after', $event)"
>
</template>
</v-card>
</v-menu>
</span>
</outlined-labeled-group>
</span>
</template>

<style scoped>
<style scoped lang="scss">
@import './toolbarGroup.scss';

.mode-button {
border: 1px solid grey;
min-width: 36px;
}
.tail-slider-width {
width: 240px;
}
.expand-toggle {
opacity: 0.5;
transition: opacity 0.2s;
}
.expand-toggle:hover {
opacity: 1;
.advanced-menu-row + .advanced-menu-row {
margin-top: 8px;
}
</style>
Loading
Loading