Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the feature to Remove annotation objects in a specified range of frames #3617

Merged
Merged
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
25527db
Test Commit for Remove Range
gudipudiramanakumar Aug 27, 2021
aab67f4
Remove annotations in range merged with remove annotations button merged
gudipudiramanakumar Aug 28, 2021
a085554
Update annotation-reducer.ts
gudipudiramanakumar Aug 28, 2021
7839fe8
Update annotation-actions.ts
gudipudiramanakumar Aug 28, 2021
c092a56
Update annotation-reducer.ts
gudipudiramanakumar Aug 28, 2021
4d39b94
Merge branch 'openvinotoolkit:develop' into feature-removeannotations…
gudipudiramanakumar Sep 4, 2021
cde900f
Converting remove range component to hook based component
gudipudiramanakumar Oct 12, 2021
5ed81c3
Improved clear in cvat core and implemented remove range
gudipudiramanakumar Oct 18, 2021
6f5b922
Merge branch 'feature-removeannotationsinrange' into develop
gudipudiramanakumar Oct 18, 2021
d47db3c
Merge pull request #1 from gudipudiramanakumar/develop
gudipudiramanakumar Oct 18, 2021
25bbb49
Matching only the needed parts
gudipudiramanakumar Oct 18, 2021
6dba4e8
Merge branch 'feature-removeannotationsinrange' of https://github.com…
gudipudiramanakumar Oct 18, 2021
d72833d
Delete out.json
gudipudiramanakumar Oct 18, 2021
abca64f
Update annotations-collection.js
gudipudiramanakumar Oct 18, 2021
fb30089
Added a checkbox to remove range modal
gudipudiramanakumar Oct 19, 2021
2e714f1
ESLint fixed
gudipudiramanakumar Oct 20, 2021
88d1ec1
Merge branch 'openvinotoolkit:develop' into feature-removeannotations…
gudipudiramanakumar Oct 20, 2021
6cc2403
More ESLint and other updates
gudipudiramanakumar Oct 20, 2021
5317c04
Merge branch 'feature-removeannotationsinrange' of https://github.com…
gudipudiramanakumar Oct 20, 2021
c7a4a03
Update annotation-menu.tsx
gudipudiramanakumar Oct 20, 2021
e5c23b0
Update remove-range-confirm.tsx
gudipudiramanakumar Oct 21, 2021
455466f
Changed the approach of removeAnnotations modal
gudipudiramanakumar Oct 23, 2021
a313f46
Merge branch 'openvinotoolkit:develop' into feature-removeannotations…
gudipudiramanakumar Oct 25, 2021
8b0dc67
Added to changelog
gudipudiramanakumar Oct 26, 2021
96e73a7
Merge branch 'feature-removeannotationsinrange' of https://github.com…
gudipudiramanakumar Oct 26, 2021
b92b93c
Merge branch 'openvinotoolkit:develop' into feature-removeannotations…
gudipudiramanakumar Oct 26, 2021
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Progress bar for manifest creating (<https://github.com/openvinotoolkit/cvat/pull/3712>)
- Add a tutorial on attaching cloud storage AWS-S3 (<https://github.com/openvinotoolkit/cvat/pull/3745>)
and Azure Blob Container (<https://github.com/openvinotoolkit/cvat/pull/3778>)
- The feature to remove annotations in a specified range of frames (<https://github.com/openvinotoolkit/cvat/pull/3617>)

### Changed

Expand Down
4 changes: 2 additions & 2 deletions cvat-core/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "3.16.1",
"version": "3.17.0",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "babel.config.js",
"scripts": {
Expand Down
42 changes: 34 additions & 8 deletions cvat-core/src/annotations-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,40 @@
return groupIdx;
}

clear() {
this.shapes = {};
this.tags = {};
this.tracks = [];
this.objects = {}; // by id
this.count = 0;

this.flush = true;
clear(startframe, endframe, delTrackKeyframesOnly) {
if (startframe !== undefined && endframe !== undefined) {
// If only a range of annotations need to be cleared
for (let frame = startframe; frame <= endframe; frame++) {
this.shapes[frame] = [];
this.tags[frame] = [];
}
const { tracks } = this;
tracks.forEach((track) => {
if (track.frame <= endframe) {
if (delTrackKeyframesOnly) {
for (const keyframe in track.shapes) {
if (keyframe >= startframe && keyframe <= endframe) { delete track.shapes[keyframe]; }
}
} else if (track.frame >= startframe) {
const index = tracks.indexOf(track);
if (index > -1) { tracks.splice(index, 1); }
}
}
});
} else if (startframe === undefined && endframe === undefined) {
// If all annotations need to be cleared
this.shapes = {};
this.tags = {};
this.tracks = [];
this.objects = {}; // by id
this.count = 0;

this.flush = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe if remove from range, this flag should not be set to true.
If this flag is true, client sends put annotation request and all annotations are removed from the database.
If this flag is false, client sends only changes.

} else {
// If inputs provided were wrong
throw Error('Could not remove the annotations, please provide both inputs or'
+ ' leave the inputs below empty to remove all the annotations from this job');
}
}

statistics() {
Expand Down
4 changes: 2 additions & 2 deletions cvat-core/src/annotations.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,13 @@
return false;
}

async function clearAnnotations(session, reload) {
async function clearAnnotations(session, reload, startframe, endframe, delTrackKeyframesOnly) {
checkObjectType('reload', reload, 'boolean', null);
const sessionType = session instanceof Task ? 'task' : 'job';
const cache = getCache(sessionType);

if (cache.has(session)) {
cache.get(session).collection.clear();
cache.get(session).collection.clear(startframe, endframe, delTrackKeyframesOnly);
}

if (reload) {
Expand Down
8 changes: 4 additions & 4 deletions cvat-core/src/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
return result;
},

async clear(reload = false) {
const result = await PluginRegistry.apiWrapper.call(this, prototype.annotations.clear, reload);
async clear(reload = false, startframe = undefined, endframe = undefined, delTrackKeyframesOnly = true) {
const result = await PluginRegistry.apiWrapper.call(this, prototype.annotations.clear, reload, startframe, endframe, delTrackKeyframesOnly);
return result;
},

Expand Down Expand Up @@ -1897,8 +1897,8 @@
return result;
};

Job.prototype.annotations.clear.implementation = async function (reload) {
const result = await clearAnnotations(this, reload);
Job.prototype.annotations.clear.implementation = async function (reload, startframe, endframe, delTrackKeyframesOnly) {
const result = await clearAnnotations(this, reload, startframe, endframe, delTrackKeyframesOnly);
return result;
};

Expand Down
4 changes: 2 additions & 2 deletions cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.24.1",
"version": "1.25.0",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
15 changes: 11 additions & 4 deletions cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,17 +306,24 @@ export function updateCanvasContextMenu(
};
}

export function removeAnnotationsAsync(sessionInstance: any): ThunkAction {
export function removeAnnotationsAsync(
startFrame: number, endFrame: number, delTrackKeyframesOnly: boolean,
): ThunkAction {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
try {
await sessionInstance.annotations.clear();
await sessionInstance.actions.clear();
const history = await sessionInstance.actions.get();
const {
filters, frame, showAllInterpolationTracks, jobInstance,
} = receiveAnnotationsParameters();
await jobInstance.annotations.clear(false, startFrame, endFrame, delTrackKeyframesOnly);
await jobInstance.actions.clear();
const history = await jobInstance.actions.get();
const states = await jobInstance.annotations.get(frame, showAllInterpolationTracks, filters);

dispatch({
type: AnnotationActionTypes.REMOVE_JOB_ANNOTATIONS_SUCCESS,
payload: {
history,
states,
},
});
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
// SPDX-License-Identifier: MIT

import React from 'react';

import Menu from 'antd/lib/menu';
import Modal from 'antd/lib/modal';
import Text from 'antd/lib/typography/Text';
import {
InputNumber, Tooltip, Checkbox, Collapse,
} from 'antd';
// eslint-disable-next-line import/no-extraneous-dependencies
import { MenuInfo } from 'rc-menu/lib/interface';

Expand All @@ -20,6 +25,8 @@ interface Props {
jobInstance: any;
onClickMenu(params: MenuInfo): void;
onUploadAnnotations(format: string, file: File): void;
stopFrame: number;
removeAnnotations(startnumber: number, endnumber: number, delTrackKeyframesOnly:boolean): void;
setForceExitAnnotationFlag(forceExit: boolean): void;
saveAnnotations(jobInstance: any, afterSave?: () => void): void;
}
Expand All @@ -41,8 +48,10 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
loadActivity,
isReviewer,
jobInstance,
stopFrame,
onClickMenu,
onUploadAnnotations,
removeAnnotations,
setForceExitAnnotationFlag,
saveAnnotations,
} = props;
Expand Down Expand Up @@ -80,14 +89,52 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
}

if (params.key === Actions.REMOVE_ANNO) {
let removeFrom: number;
let removeUpTo: number;
let removeOnlyKeyframes = false;
const { Panel } = Collapse;
Modal.confirm({
title: 'All the annotations will be removed',
content:
'You are going to remove all the annotations from the client. ' +
'It will stay on the server till you save the job. Continue?',
title: 'Remove Annotations',
content: (
<div>
<Text>You are going to remove the annotations from the client. </Text>
<Text>It will stay on the server till you save the job. Continue?</Text>
<br />
<br />
<Collapse bordered={false}>
<Panel header={<Text>Select Range</Text>} key={1}>
<Text>From: </Text>
<InputNumber
min={0}
max={stopFrame}
onChange={(value) => {
removeFrom = value;
}}
/>
<Text> To: </Text>
<InputNumber
min={0}
max={stopFrame}
onChange={(value) => { removeUpTo = value; }}
/>
<Tooltip title='Applicable only for annotations in range'>
<br />
<br />
<Checkbox
onChange={(check) => {
removeOnlyKeyframes = check.target.checked;
}}
>
Delete only keyframes for tracks
</Checkbox>
</Tooltip>
</Panel>
</Collapse>
</div>
),
className: 'cvat-modal-confirm-remove-annotation',
onOk: () => {
onClickMenu(params);
removeAnnotations(removeFrom, removeUpTo, removeOnlyKeyframes);
},
okButtonProps: {
type: 'primary',
Expand Down Expand Up @@ -127,7 +174,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
const is2d = jobInstance.task.dimension === DimensionType.DIM_2D;

return (
<Menu onClick={onClickMenuWrapper} className='cvat-annotation-menu' selectable={false}>
<Menu onClick={(params: MenuInfo) => onClickMenuWrapper(params)} className='cvat-annotation-menu' selectable={false}>
{LoadSubmenu({
loaders,
loadActivity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,26 @@ import AnnotationMenuComponent, { Actions } from 'components/annotation-page/top
import { updateJobAsync } from 'actions/tasks-actions';
import {
uploadJobAnnotationsAsync,
removeAnnotationsAsync,
saveAnnotationsAsync,
switchRequestReviewDialog as switchRequestReviewDialogAction,
switchSubmitReviewDialog as switchSubmitReviewDialogAction,
setForceExitAnnotationFlag as setForceExitAnnotationFlagAction,
removeAnnotationsAsync as removeAnnotationsAsyncAction,
} from 'actions/annotation-actions';
import { exportActions } from 'actions/export-actions';

interface StateToProps {
annotationFormats: any;
jobInstance: any;
stopFrame: number;
loadActivity: string | null;
user: any;
}

interface DispatchToProps {
loadAnnotations(job: any, loader: any, file: File): void;
showExportModal(task: any): void;
removeAnnotations(sessionInstance: any): void;
removeAnnotations(startnumber:number, endnumber:number, delTrackKeyframesOnly:boolean): void;
switchRequestReviewDialog(visible: boolean): void;
switchSubmitReviewDialog(visible: boolean): void;
setForceExitAnnotationFlag(forceExit: boolean): void;
Expand All @@ -43,7 +44,10 @@ function mapStateToProps(state: CombinedState): StateToProps {
const {
annotation: {
activities: { loads: jobLoads },
job: { instance: jobInstance },
job: {
instance: jobInstance,
instance: { stopFrame },
},
},
formats: { annotationFormats },
tasks: {
Expand All @@ -58,6 +62,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
return {
loadActivity: taskID in loads || jobID in jobLoads ? loads[taskID] || jobLoads[jobID] : null,
jobInstance,
stopFrame,
annotationFormats,
user,
};
Expand All @@ -71,8 +76,8 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
showExportModal(task: any): void {
dispatch(exportActions.openExportModal(task));
},
removeAnnotations(sessionInstance: any): void {
dispatch(removeAnnotationsAsync(sessionInstance));
removeAnnotations(startnumber: number, endnumber: number, delTrackKeyframesOnly:boolean) {
dispatch(removeAnnotationsAsyncAction(startnumber, endnumber, delTrackKeyframesOnly));
},
switchRequestReviewDialog(visible: boolean): void {
dispatch(switchRequestReviewDialogAction(visible));
Expand All @@ -97,6 +102,7 @@ type Props = StateToProps & DispatchToProps & RouteComponentProps;
function AnnotationMenuContainer(props: Props): JSX.Element {
const {
jobInstance,
stopFrame,
user,
annotationFormats: { loaders, dumpers },
history,
Expand All @@ -122,8 +128,6 @@ function AnnotationMenuContainer(props: Props): JSX.Element {
const [action] = params.keyPath;
if (action === Actions.EXPORT_TASK_DATASET) {
showExportModal(jobInstance.task);
} else if (action === Actions.REMOVE_ANNO) {
removeAnnotations(jobInstance);
} else if (action === Actions.REQUEST_REVIEW) {
switchRequestReviewDialog(true);
} else if (action === Actions.SUBMIT_REVIEW) {
Expand Down Expand Up @@ -151,10 +155,12 @@ function AnnotationMenuContainer(props: Props): JSX.Element {
loadActivity={loadActivity}
onUploadAnnotations={onUploadAnnotations}
onClickMenu={onClickMenu}
removeAnnotations={removeAnnotations}
setForceExitAnnotationFlag={setForceExitAnnotationFlag}
saveAnnotations={saveAnnotations}
jobInstance={jobInstance}
isReviewer={isReviewer}
stopFrame={stopFrame}
/>
);
}
Expand Down
5 changes: 4 additions & 1 deletion cvat-ui/src/reducers/annotation-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -917,16 +917,19 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
},
};
}
// Added Remove Annotations
case AnnotationActionTypes.REMOVE_JOB_ANNOTATIONS_SUCCESS: {
const { history } = action.payload;
const { states } = action.payload;
return {
...state,
annotations: {
...state.annotations,
history,
states,
selectedStatesID: [],
activatedStateID: null,
collapsed: {},
states: [],
},
};
}
Expand Down