Skip to content

Commit 3f4de06

Browse files
authored
Updated MIL tracker implementation (#8942)
1 parent 8613254 commit 3f4de06

File tree

13 files changed

+544
-364
lines changed

13 files changed

+544
-364
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
### Changed
2+
3+
- Enhanced MIL tracker. Optimized memory usage. Now it is runnable on many frames, and applicable to drawn rectangles.
4+
(<https://github.com/cvat-ai/cvat/pull/8942>)

cvat-core/src/frames.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (C) 2021-2022 Intel Corporation
2-
// Copyright (C) 2022-2024 CVAT.ai Corporation
2+
// Copyright (C) 2022-2025 CVAT.ai Corporation
33
//
44
// SPDX-License-Identifier: MIT
55

@@ -300,7 +300,11 @@ export class FrameData {
300300
);
301301
}
302302

303-
async data(onServerRequest = () => {}): Promise<ImageBitmap | Blob> {
303+
async data(onServerRequest = () => {}): Promise<{
304+
renderWidth: number;
305+
renderHeight: number;
306+
imageData: ImageBitmap | Blob;
307+
}> {
304308
const result = await PluginRegistry.apiWrapper.call(this, FrameData.prototype.data, onServerRequest);
305309
return result;
306310
}
@@ -372,7 +376,7 @@ Object.defineProperty(FrameData.prototype.data, 'implementation', {
372376
renderWidth: number;
373377
renderHeight: number;
374378
imageData: ImageBitmap | Blob;
375-
} | Blob>((resolve, reject) => {
379+
}>((resolve, reject) => {
376380
const requestId = +_.uniqueId();
377381
const requestedDataFrameNumber = meta.getDataFrameNumber(this.number - jobStartFrame);
378382
const chunkIndex = meta.getFrameChunkIndex(requestedDataFrameNumber);

cvat-ui/src/components/annotation-page/annotations-actions/annotations-actions-modal.tsx

+34-36
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2023-2024 CVAT.ai Corporation
1+
// Copyright (C) 2023-2025 CVAT.ai Corporation
22
//
33
// SPDX-License-Identifier: MIT
44

@@ -37,7 +37,6 @@ const core = getCore();
3737
interface State {
3838
actions: BaseAction[];
3939
activeAction: BaseAction | null;
40-
initialized: boolean;
4140
fetching: boolean;
4241
progress: number | null;
4342
progressMessage: string | null;
@@ -50,7 +49,6 @@ interface State {
5049
}
5150

5251
enum ReducerActionType {
53-
SET_INITIALIZED = 'SET_INITIALIZED',
5452
SET_ANNOTATIONS_ACTIONS = 'SET_ANNOTATIONS_ACTIONS',
5553
SET_ACTIVE_ANNOTATIONS_ACTION = 'SET_ACTIVE_ANNOTATIONS_ACTION',
5654
UPDATE_PROGRESS = 'UPDATE_PROGRESS',
@@ -65,9 +63,6 @@ enum ReducerActionType {
6563
}
6664

6765
export const reducerActions = {
68-
setInitialized: (initialized: boolean) => (
69-
createAction(ReducerActionType.SET_INITIALIZED, { initialized })
70-
),
7166
setAnnotationsActions: (actions: BaseAction[]) => (
7267
createAction(ReducerActionType.SET_ANNOTATIONS_ACTIONS, { actions })
7368
),
@@ -105,7 +100,6 @@ export const reducerActions = {
105100

106101
const defaultState = {
107102
actions: [],
108-
initialized: false,
109103
fetching: false,
110104
activeAction: null,
111105
progress: null,
@@ -119,23 +113,13 @@ const defaultState = {
119113
};
120114

121115
const reducer = (state: State = { ...defaultState }, action: ActionUnion<typeof reducerActions>): State => {
122-
if (action.type === ReducerActionType.SET_INITIALIZED) {
123-
return {
124-
...state,
125-
initialized: action.payload.initialized,
126-
};
127-
}
128-
129116
if (action.type === ReducerActionType.SET_ANNOTATIONS_ACTIONS) {
130117
const { actions } = action.payload;
131-
const { targetObjectState } = state;
132118

133-
const filteredActions = targetObjectState ? actions
134-
.filter((_action) => _action.isApplicableForObject(targetObjectState)) : actions;
135119
return {
136120
...state,
137121
actions,
138-
activeAction: filteredActions[0] ?? null,
122+
activeAction: state.activeAction ?? actions[0] ?? null,
139123
};
140124
}
141125

@@ -246,7 +230,6 @@ type ActionParameterProps = NonNullable<BaseAction['parameters']>[keyof BaseActi
246230

247231
const componentStorage = createStore(reducer, {
248232
actions: [],
249-
initialized: false,
250233
fetching: false,
251234
activeAction: null,
252235
progress: null,
@@ -319,15 +302,16 @@ function ActionParameterComponent(props: ActionParameterProps & { onChange: (val
319302
interface Props {
320303
onClose: () => void;
321304
targetObjectState?: ObjectState;
305+
defaultAnnotationAction?: string;
322306
}
323307

324308
function AnnotationsActionsModalContent(props: Props): JSX.Element {
325-
const { onClose, targetObjectState: defaultTargetObjectState } = props;
309+
const { onClose, targetObjectState: defaultTargetObjectState, defaultAnnotationAction } = props;
326310
const dispatch = useDispatch();
327311
const storage = getCVATStore();
328312
const cancellationRef = useRef<boolean>(false);
329313
const {
330-
initialized, actions, activeAction, fetching, targetObjectState, cancelled,
314+
actions, activeAction, fetching, targetObjectState, cancelled,
331315
progress, progressMessage, frameFrom, frameTo, actionParameters, modalVisible,
332316
} = useSelector((state: State) => ({ ...state }), shallowEqual);
333317

@@ -337,20 +321,25 @@ function AnnotationsActionsModalContent(props: Props): JSX.Element {
337321
const currentFrameAction = activeAction instanceof BaseCollectionAction || targetObjectState !== null;
338322

339323
useEffect(() => {
340-
dispatch(reducerActions.setVisible(true));
341-
dispatch(reducerActions.updateFrameFrom(jobInstance.startFrame));
342-
dispatch(reducerActions.updateFrameTo(jobInstance.stopFrame));
343-
dispatch(reducerActions.updateTargetObjectState(defaultTargetObjectState ?? null));
344-
}, []);
324+
core.actions.list().then((list: BaseAction[]) => {
325+
dispatch(reducerActions.setAnnotationsActions(list));
326+
327+
if (defaultAnnotationAction) {
328+
const defaultAction = list.find((action) => action.name === defaultAnnotationAction);
329+
if (
330+
defaultAction &&
331+
(!defaultTargetObjectState || defaultAction.isApplicableForObject(defaultTargetObjectState))
332+
) {
333+
dispatch(reducerActions.setActiveAnnotationsAction(defaultAction));
334+
}
335+
}
345336

346-
useEffect(() => {
347-
if (!initialized) {
348-
core.actions.list().then((list: BaseAction[]) => {
349-
dispatch(reducerActions.setAnnotationsActions(list));
350-
dispatch(reducerActions.setInitialized(true));
351-
});
352-
}
353-
}, [initialized]);
337+
dispatch(reducerActions.setVisible(true));
338+
dispatch(reducerActions.updateFrameFrom(jobInstance.startFrame));
339+
dispatch(reducerActions.updateFrameTo(jobInstance.stopFrame));
340+
dispatch(reducerActions.updateTargetObjectState(defaultTargetObjectState ?? null));
341+
});
342+
}, []);
354343

355344
return (
356345
<Modal
@@ -643,14 +632,23 @@ function AnnotationsActionsModalContent(props: Props): JSX.Element {
643632

644633
const MemoizedAnnotationsActionsModalContent = React.memo(AnnotationsActionsModalContent);
645634

646-
export function openAnnotationsActionModal(objectState?: ObjectState): void {
635+
export function openAnnotationsActionModal({
636+
defaultObjectState,
637+
defaultAnnotationAction,
638+
}: {
639+
defaultObjectState?: ObjectState,
640+
defaultAnnotationAction?: string,
641+
} = {}): void {
642+
window.document.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
643+
647644
const div = window.document.createElement('div');
648645
window.document.body.append(div);
649646
const root = createRoot(div);
650647
root.render(
651648
<Provider store={componentStorage}>
652649
<MemoizedAnnotationsActionsModalContent
653-
targetObjectState={objectState}
650+
targetObjectState={defaultObjectState}
651+
defaultAnnotationAction={defaultAnnotationAction}
654652
onClose={() => {
655653
root.unmount();
656654
div.remove();

0 commit comments

Comments
 (0)