未验证 提交 78158cbc 编写于 作者: G gudipudiramanakumar 提交者: GitHub

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

* Test Commit for Remove Range

Test Commit for Remove Range

* Remove annotations in range merged with remove annotations button merged

Remove annotations in range merged with remove annotations button merged

* Update annotation-reducer.ts

* Update annotation-actions.ts

* Update annotation-reducer.ts

* Converting remove range component to hook based component

Removed all the global states previously used and converted all the parameters to local state in annotation menu and remove range component.

* Improved clear in cvat core and implemented remove range

Added arguments of startframe and endframe to clear method in annotation-collection, and also added the updating of the states with payload on removeannotationsinrangeasync action in the reducer.

* Matching only the needed parts

There are few additional old files that were needed to be removed to be completely matched with develop branch of cvat

* Delete out.json

* Update annotations-collection.js

* Added a checkbox to remove range modal

Added a checkbox to remove range modal that can be used to select if only the keyframes should be deleted in tracks or the whole track

* ESLint fixed

All the updated files were formatted as per ESLint except one line in that even cvat base is also overlooking i.e.
Row 162, Column 15: "JSX props should not use functions" in cvat\cvat-ui\src\components\annotation-page\top-bar\annotation-menu.tsx.

* More ESLint and other updates

Changed all the suggested changes and also removed unnecessary files in dist.
Removed unnecessary explicit removals in objects and additional wrappers.

* Update annotation-menu.tsx

Fixed the mistake of wrong variable name.

* Update remove-range-confirm.tsx

Additional ESLint Issue fixed

* Changed the approach of removeAnnotations modal

Changed the approach of removeAnnotations modal so that it could match the implementation of all the other components

* Added to changelog

Fixed type annotations in the annotation-menu component for remove annotations, and updated cvat-ui and cvat-core npm versions.
上级 4b2769c3
......@@ -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
......
{
"name": "cvat-core",
"version": "3.16.1",
"version": "3.17.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cvat-core",
"version": "3.16.1",
"version": "3.17.0",
"license": "MIT",
"dependencies": {
"axios": "^0.21.4",
......
{
"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": {
......
......@@ -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;
} 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() {
......
......@@ -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) {
......
......@@ -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;
},
......@@ -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;
};
......
{
"name": "cvat-ui",
"version": "1.24.1",
"version": "1.25.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cvat-ui",
"version": "1.24.1",
"version": "1.25.0",
"license": "MIT",
"dependencies": {
"@ant-design/icons": "^4.6.3",
......
{
"name": "cvat-ui",
"version": "1.24.1",
"version": "1.25.0",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
......
......@@ -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) {
......
......@@ -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';
......@@ -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;
}
......@@ -41,8 +48,10 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element {
loadActivity,
isReviewer,
jobInstance,
stopFrame,
onClickMenu,
onUploadAnnotations,
removeAnnotations,
setForceExitAnnotationFlag,
saveAnnotations,
} = props;
......@@ -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',
......@@ -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,
......
......@@ -13,17 +13,18 @@ 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;
}
......@@ -31,7 +32,7 @@ interface StateToProps {
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;
......@@ -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: {
......@@ -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,
};
......@@ -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));
......@@ -97,6 +102,7 @@ type Props = StateToProps & DispatchToProps & RouteComponentProps;
function AnnotationMenuContainer(props: Props): JSX.Element {
const {
jobInstance,
stopFrame,
user,
annotationFormats: { loaders, dumpers },
history,
......@@ -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) {
......@@ -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}
/>
);
}
......
......@@ -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: [],
},
};
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册