Skip to content
Merged
21 changes: 15 additions & 6 deletions client/dive-common/components/RunPipelineMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
SubType,
} from 'dive-common/apispec';
import JobLaunchDialog from 'dive-common/components/JobLaunchDialog.vue';
import { stereoPipelineMarker } from 'dive-common/constants';
import { stereoPipelineMarker, multiCamPipelineMarkers } from 'dive-common/constants';
import { useRequest } from 'dive-common/use';

export default defineComponent({
Expand All @@ -30,16 +30,23 @@ export default defineComponent({
type: Object,
default: () => ({}),
},
/* Which pipelines to show based on dataset subtypes */
subTypeList: {
type: Array as PropType<SubType[]>,
default: () => ([]),
},
/* Which pipelines to show based on how many cameras they accept */
cameraNumbers: {
type: Array as PropType<number[]>,
default: () => ([1]),
},
},

setup(props) {
const { runPipeline, getPipelineList } = useApi();
const unsortedPipelines = ref({} as Pipelines);
const selectedPipe = ref(null as Pipe | null);
const camNumberStringArray = computed(() => props.cameraNumbers.map((v) => v.toString()));
const {
request: _runPipelineRequest,
reset: dismissLaunchDialog,
Expand Down Expand Up @@ -69,13 +76,15 @@ export default defineComponent({
});
// Filter out unsupported pipelines based on subTypeList
// measurement can only be operated on stereo subtypes
if (name === stereoPipelineMarker) {
if (props.subTypeList.length === props.subTypeList.filter((item) => item === 'stereo').length) {
if (props.subTypeList.every((item) => item === 'stereo') && (name === stereoPipelineMarker)) {
sortedPipelines[name] = category;
} else if (props.subTypeList.every((item) => item === 'multicam') && (multiCamPipelineMarkers.includes(name))) {
const pipelineExpectedCameraCount = name.split('-')[0];
if (camNumberStringArray.value.includes(pipelineExpectedCameraCount)) {
sortedPipelines[name] = category;
}
} else if (
props.subTypeList.length === props.subTypeList.filter((item) => item === null).length
) {
} else if (props.subTypeList.every((item) => item === null)
&& name !== stereoPipelineMarker && !multiCamPipelineMarkers.includes(name)) {
sortedPipelines[name] = category;
}
});
Expand Down
4 changes: 2 additions & 2 deletions client/dive-common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const listFileTypes = [
];

const stereoPipelineMarker = 'measurement';
const multiCamPipelineMarker = ''; //Placeholder
const multiCamPipelineMarkers = ['2-cam', '3-cam'];


export {
Expand All @@ -122,5 +122,5 @@ export {
inputAnnotationFileTypes,
listFileTypes,
stereoPipelineMarker,
multiCamPipelineMarker,
multiCamPipelineMarkers,
};
4 changes: 2 additions & 2 deletions client/platform/desktop/backend/native/common.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,8 @@ describe('native.common', () => {

await common.dataFileImport(settings, final.id, '/home/user/data/annotationImport/foreign.meta.json');
const meta2 = await common.loadMetadata(settings, final.id, urlMapper);
expect(meta2.confidenceFilters).toStrictEqual({ "default": 0.8 });
expect(meta2.type).toBe("image-sequence"); // Ensure meta import cannot change immutable fields.
expect(meta2.confidenceFilters).toStrictEqual({ default: 0.8 });
expect(meta2.type).toBe('image-sequence'); // Ensure meta import cannot change immutable fields.
});

it('import with CSV annotations without specifying track file', async () => {
Expand Down
11 changes: 8 additions & 3 deletions client/platform/desktop/backend/native/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ async function autodiscoverData(settings: Settings): Promise<JsonMeta[]> {
*/
async function getPipelineList(settings: Settings): Promise<Pipelines> {
const pipelinePath = npath.join(settings.viamePath, 'configs/pipelines');
const allowedPatterns = /^detector_.+|^tracker_.+|^generate_.+|^utility_|^measurement_gmm_.+/;
const allowedPatterns = /^detector_.+|^tracker_.+|^generate_.+|^utility_|^measurement_gmm_.+|.*[2,3]-cam.+/;
const disallowedPatterns = /.*local.*|detector_svm_models.pipe|tracker_svm_models.pipe/;
const exists = await fs.pathExists(pipelinePath);
if (!exists) return {};
Expand All @@ -351,8 +351,13 @@ async function getPipelineList(settings: Settings): Promise<Pipelines> {
const ret: Pipelines = {};
pipes.forEach((p) => {
const parts = cleanString(p.replace('.pipe', '')).split('_');
const pipeType = parts[0];
const pipeName = parts.slice(1).join(' ');
let pipeType = parts[0];
let pipeName = parts.slice(1).join(' ');
// Extract out only 2-cam and 3-cam pipelines to own category, 1-cam remain in tracker/detector
if (parts.length > 1 && parts[parts.length - 1] === 'cam' && parts[parts.length - 2] !== '1') {
pipeType = `${parts[parts.length - 2]}-cam`;
pipeName = parts.join(' ');
}
const pipeInfo = {
name: pipeName,
type: pipeType,
Expand Down
2 changes: 2 additions & 0 deletions client/platform/desktop/backend/native/multiCamUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ function writeMultiCamStereoPipelineArgs(jobWorkDir: string, meta: JsonMeta) {
const { originalBasePath } = list;
const outputFileName = `computed_tracks_${key}.csv`;
const outputArg = `detector_writer${i + 1}:file_name`;
const outputArgWriteTracks = `track_writer${i + 1}:file_name`;
argFilePair[outputArg] = outputFileName;
argFilePair[outputArgWriteTracks] = outputFileName;
outFiles[key] = outputFileName;
const inputArg = `input${i + 1}:video_filename`;
if (list.type === 'image-sequence') {
Expand Down
6 changes: 4 additions & 2 deletions client/platform/desktop/backend/native/viame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { cleanString } from 'platform/desktop/sharedUtils';
import { serialize } from 'platform/desktop/backend/serializers/viame';
import { observeChild } from 'platform/desktop/backend/native/processManager';

import { MultiType, stereoPipelineMarker } from 'dive-common/constants';
import { MultiType, stereoPipelineMarker, multiCamPipelineMarkers } from 'dive-common/constants';
import * as common from './common';
import { jobFileEchoMiddleware } from './utils';
import {
Expand Down Expand Up @@ -132,7 +132,9 @@ async function runPipeline(
}

let multiOutFiles: Record<string, string>;
if (meta.multiCam && pipeline.type === stereoPipelineMarker) {
const stereoOrMultiCam = (pipeline.type === stereoPipelineMarker
|| multiCamPipelineMarkers.includes(pipeline.type));
if (meta.multiCam && stereoOrMultiCam) {
const { argFilePair, outFiles } = writeMultiCamStereoPipelineArgs(jobWorkDir, meta);
Object.entries(argFilePair).forEach(([arg, file]) => {
command.push(`-s ${arg}="${file}"`);
Expand Down
3 changes: 3 additions & 0 deletions client/platform/desktop/frontend/components/ViewerLoader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default defineComponent({
const viewerRef = ref();
const compoundId = ref(props.id);
const subTypeList = computed(() => [datasets.value[props.id]?.subType || null]);
const camNumbers = computed(() => [datasets.value[props.id]?.cameraNumber || 1]);
const readonlyMode = computed(() => settings.value?.readonlyMode || false);

watch(runningJobs, async (_previous, current) => {
Expand All @@ -73,6 +74,7 @@ export default defineComponent({
buttonOptions,
menuOptions,
subTypeList,
camNumbers,
readonlyMode,
};
},
Expand Down Expand Up @@ -108,6 +110,7 @@ export default defineComponent({
<RunPipelineMenu
:selected-dataset-ids="[id]"
:sub-type-list="subTypeList"
:camera-numbers="camNumbers"
v-bind="{ buttonOptions, menuOptions }"
/>
<ImportAnnotations
Expand Down
3 changes: 3 additions & 0 deletions client/platform/desktop/frontend/store/dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface JsonMetaCache {
imageListPath: string;
transcodedVideoFile?: string;
subType: SubType;
cameraNumber: number;
}

/**
Expand All @@ -40,6 +41,7 @@ function hydrateJsonMetaCacheValue(input: any): JsonMetaCache {
transcodedVideoFile: '',
accessedAt: input.createdAt,
subType: null,
cameraNumber: 1,
...input,
};
}
Expand All @@ -62,6 +64,7 @@ function setRecents(meta: JsonMeta, accessTime?: string) {
imageListPath: meta.imageListPath,
transcodedVideoFile: meta.transcodedVideoFile,
subType: meta.subType,
cameraNumber: Object.keys(meta.multiCam || {}).length,
} as JsonMetaCache);
const values = Object.values(datasets.value);
window.localStorage.setItem(RecentsKey, JSON.stringify(values));
Expand Down