From 0cf3978ead40b97799f7cb637aac0e6daee27c56 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 31 Mar 2020 14:04:18 +0300 Subject: [PATCH 01/14] Fixed escape in draw --- cvat-canvas/src/typescript/drawHandler.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 4afe75ec..f6c1d947 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -50,6 +50,7 @@ export class DrawHandlerImpl implements DrawHandler { // so, methods like draw() just undefined for SVG.Shape, but nevertheless they exist private drawInstance: any; private initialized: boolean; + private canceled: boolean; private pointsGroup: SVG.G | null; private shapeSizeElement: ShapeSizeElement; @@ -149,6 +150,7 @@ export class DrawHandlerImpl implements DrawHandler { // Clear drawing this.drawInstance.draw('stop'); } + this.drawInstance.off(); this.drawInstance.remove(); this.drawInstance = null; @@ -161,6 +163,7 @@ export class DrawHandlerImpl implements DrawHandler { if (this.crosshair) { this.removeCrosshair(); } + this.onDrawDone(null); } private initDrawing(): void { @@ -175,8 +178,9 @@ export class DrawHandlerImpl implements DrawHandler { const bbox = (e.target as SVGRectElement).getBBox(); const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox); const { shapeType } = this.drawData; - this.cancel(); + this.release(); + if (this.canceled) return; if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) { this.onDrawDone({ shapeType, @@ -290,11 +294,11 @@ export class DrawHandlerImpl implements DrawHandler { this.drawInstance.on('drawdone', (e: CustomEvent): void => { const targetPoints = pointsToArray((e.target as SVGElement).getAttribute('points')); - const { points, box } = this.getFinalPolyshapeCoordinates(targetPoints); const { shapeType } = this.drawData; - this.cancel(); + this.release(); + if (this.canceled) return; if (shapeType === 'polygon' && ((box.xbr - box.xtl) * (box.ybr - box.ytl) >= consts.AREA_THRESHOLD) && points.length >= 3 * 2) { @@ -598,6 +602,7 @@ export class DrawHandlerImpl implements DrawHandler { this.canvas = canvas; this.text = text; this.initialized = false; + this.canceled = false; this.drawData = null; this.geometry = null; this.crosshair = null; @@ -671,17 +676,18 @@ export class DrawHandlerImpl implements DrawHandler { this.geometry = geometry; if (drawData.enabled) { + this.canceled = false; this.drawData = drawData; this.initDrawing(); this.startDraw(); } else { - this.cancel(); + this.release(); this.drawData = drawData; } } public cancel(): void { + this.canceled = true; this.release(); - this.onDrawDone(null); } } From 2e6a92afa4fd52c531678bcb2f4cb9f40d1c244f Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 31 Mar 2020 14:09:47 +0300 Subject: [PATCH 02/14] Insert multiple shapes --- cvat-canvas/src/typescript/drawHandler.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index f6c1d947..a2c401c5 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -163,7 +163,10 @@ export class DrawHandlerImpl implements DrawHandler { if (this.crosshair) { this.removeCrosshair(); } - this.onDrawDone(null); + + if (!this.drawData.initialState) { + this.onDrawDone(null); + } } private initDrawing(): void { From a7f02df7d07842f1cd4f00fa41ac5daa0437f28c Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 31 Mar 2020 16:11:35 +0300 Subject: [PATCH 03/14] Added dialog window with some help info about filters --- cvat-core/src/session.js | 5 +- .../annotations-filters-input.tsx | 110 ++++++++++++++++-- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/cvat-core/src/session.js b/cvat-core/src/session.js index 987b3fae..548dd191 100644 --- a/cvat-core/src/session.js +++ b/cvat-core/src/session.js @@ -441,7 +441,7 @@ * Returns the ranges of cached frames * @method ranges * @memberof Session.frames - * @returns {Array{string}} + * @returns {Array.} * @instance * @async */ @@ -520,7 +520,8 @@ * @returns {HistoryActions} * @throws {module:API.cvat.exceptions.PluginError} * @throws {module:API.cvat.exceptions.ArgumentError} - * @returns {[string, number][]} array of pairs [action name, frame number] + * @returns {Array.>} + * array of pairs [action name, frame number] * @instance * @async */ diff --git a/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx b/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx index 39ff37b6..b6e98198 100644 --- a/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx +++ b/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx @@ -2,9 +2,14 @@ // // SPDX-License-Identifier: MIT -import React from 'react'; +import React, { useState } from 'react'; import { connect } from 'react-redux'; import Select, { SelectValue, LabeledValue } from 'antd/lib/select'; +import Title from 'antd/lib/typography/Title'; +import Text from 'antd/lib/typography/Text'; +import Paragraph from 'antd/lib/typography/Paragraph'; +import Tooltip from 'antd/lib/tooltip'; +import Modal from 'antd/lib/modal'; import Icon from 'antd/lib/icon'; import { @@ -16,6 +21,8 @@ import { CombinedState } from 'reducers/interfaces'; interface StateToProps { annotationsFilters: string[]; annotationsFiltersHistory: string[]; + searchForwardShortcut: string; + searchBackwardShortcut: string; } interface DispatchToProps { @@ -30,11 +37,16 @@ function mapStateToProps(state: CombinedState): StateToProps { filtersHistory: annotationsFiltersHistory, }, }, + shortcuts: { + normalizedKeyMap, + }, } = state; return { annotationsFilters, annotationsFiltersHistory, + searchForwardShortcut: normalizedKeyMap.SEARCH_FORWARD, + searchBackwardShortcut: normalizedKeyMap.SEARCH_BACKWARD, }; } @@ -56,13 +68,74 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { }; } +function filtersHelpModalContent( + searchForwardShortcut: string, + searchBackwardShortcut: string, +): JSX.Element { + return ( + <> + + General + + + You can use filters to display only subset of objects on a frame + or to search objects that satisfy the filters using hotkeys + + {` ${searchForwardShortcut} `} + + and + + {` ${searchBackwardShortcut} `} + + + + Supported properties: + width, height, label, serverID, clientID, type, shape, occluded +
+ Supported operators: + ==, !=, >, >=, <, <=, ~=, (), & and | +
+ + If you have double quotes in your query string, + please escape them using back slash: \" (see the latest example) + +
+ All properties and values are case-sensitive. + CVAT uses json queries to perform search. +
+ + Examples +
    +
  • label=="car" | label==["road sign"]
  • +
  • width >= height
  • +
  • attr["Attribute 1"] == attr["Attribute 2"]
  • +
  • clientID == 50
  • +
  • + (label=="car" & attr["parked"]==true) + | (label=="pedestrian" & width > 150) +
  • +
  • + (( label==["car \"mazda\""]) + & (attr["sunglasses"]==true + | (width > 150 | height > 150 & (clientID == serverID))))) +
  • +
+
+ + ); +} + function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Element { const { annotationsFilters, annotationsFiltersHistory, + searchForwardShortcut, + searchBackwardShortcut, changeAnnotationsFilters, } = props; + const [underCursor, setUnderCursor] = useState(false); + return ( @@ -71,7 +75,9 @@ function renderInputElement(parameters: InputElementParameters): JSX.Element { )} > {values.map((value: string): JSX.Element => ( - {value} + + {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + ))} @@ -193,7 +199,9 @@ function renderList(parameters: ListParameters): JSX.Element | null { [key: string]: (keyEvent?: KeyboardEvent) => void; } = {}; - values.slice(0, 10).forEach((value: string, index: number): void => { + const filteredValues = values + .filter((value: string): boolean => value !== consts.UNDEFINED_ATTRIBUTE_VALUE); + filteredValues.slice(0, 10).forEach((value: string, index: number): void => { const key = `SET_${index}_VALUE`; keyMap[key] = { name: `Set value "${value}"`, @@ -214,7 +222,7 @@ function renderList(parameters: ListParameters): JSX.Element | null { return (
- {values.map((value: string, index: number): JSX.Element => ( + {filteredValues.map((value: string, index: number): JSX.Element => (
{`${index}:`} {` ${value}`} diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/styles.scss b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/styles.scss index 1f8de841..231cc13b 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/styles.scss +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/styles.scss @@ -48,9 +48,7 @@ margin: 10px 0px 10px 10px; } - .attribute-annotation-sidebar-attr-elem-wrapper { - display: inline-block; width: 60%; } diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index fcf0fe38..efd81d67 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -20,7 +20,7 @@ import Text from 'antd/lib/typography/Text'; import Tooltip from 'antd/lib/tooltip'; import ColorChanger from 'components/annotation-page/standard-workspace/objects-side-bar/color-changer'; - +import consts from 'consts'; import { ObjectOutsideIcon, FirstIcon, @@ -30,10 +30,10 @@ import { BackgroundIcon, ForegroundIcon, } from 'icons'; - import { ObjectType, ShapeType } from 'reducers/interfaces'; import { clamp } from 'utils/math'; + function ItemMenu( serverID: number | undefined, locked: boolean, @@ -508,7 +508,9 @@ function ItemAttributeComponent(props: ItemAttributeComponentProps): JSX.Element }} > { attrValues.map((value: string): JSX.Element => ( - {value} + + {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + )) } @@ -534,7 +536,9 @@ function ItemAttributeComponent(props: ItemAttributeComponentProps): JSX.Element className='cvat-object-item-select-attribute' > { attrValues.map((value: string): JSX.Element => ( - {value} + + {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + )) } diff --git a/cvat-ui/src/consts.ts b/cvat-ui/src/consts.ts new file mode 100644 index 00000000..666dc98d --- /dev/null +++ b/cvat-ui/src/consts.ts @@ -0,0 +1,9 @@ +// Copyright (C) 2019-2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + +const UNDEFINED_ATTRIBUTE_VALUE = '__undefined__'; + +export default { + UNDEFINED_ATTRIBUTE_VALUE, +}; diff --git a/cvat-ui/src/utils/enviroment.ts b/cvat-ui/src/utils/enviroment.ts index e1f01755..137e9dd1 100644 --- a/cvat-ui/src/utils/enviroment.ts +++ b/cvat-ui/src/utils/enviroment.ts @@ -2,6 +2,6 @@ // // SPDX-License-Identifier: MIT -export default function isDev() { +export default function isDev(): boolean { return process.env.NODE_ENV === 'development'; } From 5b8ee72d4f32b318c540b6a5d7483d9af5089d31 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 1 Apr 2020 00:27:55 +0300 Subject: [PATCH 10/14] Fixed license year --- cvat-canvas/src/typescript/consts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-canvas/src/typescript/consts.ts b/cvat-canvas/src/typescript/consts.ts index 23a36f11..84b89940 100644 --- a/cvat-canvas/src/typescript/consts.ts +++ b/cvat-canvas/src/typescript/consts.ts @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2020 Intel Corporation +// Copyright (C) 2020 Intel Corporation // // SPDX-License-Identifier: MIT From 10c300605f6ef8fc3c786a4bb4bd5423aebbc479 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 1 Apr 2020 00:30:29 +0300 Subject: [PATCH 11/14] No break space const --- .../attribute-annotation-sidebar/attribute-editor.tsx | 6 ++++-- .../standard-workspace/objects-side-bar/object-item.tsx | 6 ++++-- cvat-ui/src/consts.ts | 2 ++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx index 50cec85a..6917e42f 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-editor.tsx @@ -56,7 +56,8 @@ function renderInputElement(parameters: InputElementParameters): JSX.Element { > {values.map((value: string): JSX.Element => ( - {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + {value === consts.UNDEFINED_ATTRIBUTE_VALUE + ? consts.NO_BREAK_SPACE : value} ))} @@ -76,7 +77,8 @@ function renderInputElement(parameters: InputElementParameters): JSX.Element { > {values.map((value: string): JSX.Element => ( - {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + {value === consts.UNDEFINED_ATTRIBUTE_VALUE + ? consts.NO_BREAK_SPACE : value} ))} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index efd81d67..2a43e042 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -509,7 +509,8 @@ function ItemAttributeComponent(props: ItemAttributeComponentProps): JSX.Element > { attrValues.map((value: string): JSX.Element => ( - {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + {value === consts.UNDEFINED_ATTRIBUTE_VALUE + ? consts.NO_BREAK_SPACE : value} )) } @@ -537,7 +538,8 @@ function ItemAttributeComponent(props: ItemAttributeComponentProps): JSX.Element > { attrValues.map((value: string): JSX.Element => ( - {value === consts.UNDEFINED_ATTRIBUTE_VALUE ? '\u00a0' : value} + {value === consts.UNDEFINED_ATTRIBUTE_VALUE + ? consts.NO_BREAK_SPACE : value} )) } diff --git a/cvat-ui/src/consts.ts b/cvat-ui/src/consts.ts index 666dc98d..aceacc0f 100644 --- a/cvat-ui/src/consts.ts +++ b/cvat-ui/src/consts.ts @@ -3,7 +3,9 @@ // SPDX-License-Identifier: MIT const UNDEFINED_ATTRIBUTE_VALUE = '__undefined__'; +const NO_BREAK_SPACE = '\u00a0'; export default { UNDEFINED_ATTRIBUTE_VALUE, + NO_BREAK_SPACE, }; From c91fa277ce2c33e6cb3b59241c1e65e5902aa299 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 1 Apr 2020 00:34:59 +0300 Subject: [PATCH 12/14] Updated changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f15c960..726e5775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0-alpha] - Unreleased ### Added -- +- Special behaviour for attribute value ``__undefined__`` (invisibility, no shortcuts to be set in AAM) ### Changed - From 5e092cd932be32bf49ad408e65dc8f8f0f02f85f Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 1 Apr 2020 00:36:21 +0300 Subject: [PATCH 13/14] Fixed year in license headers --- cvat-canvas/src/typescript/consts.ts | 2 +- cvat-ui/src/consts.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cvat-canvas/src/typescript/consts.ts b/cvat-canvas/src/typescript/consts.ts index 84b89940..23a36f11 100644 --- a/cvat-canvas/src/typescript/consts.ts +++ b/cvat-canvas/src/typescript/consts.ts @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Intel Corporation +// Copyright (C) 2019-2020 Intel Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/consts.ts b/cvat-ui/src/consts.ts index aceacc0f..b5942c32 100644 --- a/cvat-ui/src/consts.ts +++ b/cvat-ui/src/consts.ts @@ -1,4 +1,4 @@ -// Copyright (C) 2019-2020 Intel Corporation +// Copyright (C) 2020 Intel Corporation // // SPDX-License-Identifier: MIT From 66c6e7e9195507627e697eaa86ef5020784cc754 Mon Sep 17 00:00:00 2001 From: zhiltsov-max Date: Thu, 2 Apr 2020 14:08:22 +0300 Subject: [PATCH 14/14] Fix point interpolation (#1344) * Extend formats tests with different track types * Add unordered list comparison * Skip empty list comparison * fix * fix * Reproduce problem * Fix point interpolation for single point * undo rest api refactor --- cvat/apps/engine/data_manager.py | 5 ++- cvat/apps/engine/tests/test_data_manager.py | 39 +++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 cvat/apps/engine/tests/test_data_manager.py diff --git a/cvat/apps/engine/data_manager.py b/cvat/apps/engine/data_manager.py index d7adc8b8..b39c6783 100644 --- a/cvat/apps/engine/data_manager.py +++ b/cvat/apps/engine/data_manager.py @@ -293,7 +293,10 @@ class TrackManager(ObjectManager): @staticmethod def normalize_shape(shape): - points = np.asarray(shape["points"]).reshape(-1, 2) + points = list(shape["points"]) + if len(points) == 2: + points.extend(points) # duplicate points for single point case + points = np.asarray(points).reshape(-1, 2) broken_line = geometry.LineString(points) points = [] for off in range(0, 100, 1): diff --git a/cvat/apps/engine/tests/test_data_manager.py b/cvat/apps/engine/tests/test_data_manager.py new file mode 100644 index 00000000..968b5752 --- /dev/null +++ b/cvat/apps/engine/tests/test_data_manager.py @@ -0,0 +1,39 @@ +# Copyright (C) 2020 Intel Corporation +# +# SPDX-License-Identifier: MIT + +from cvat.apps.engine.data_manager import TrackManager + +from unittest import TestCase + + +class TrackManagerTest(TestCase): + def test_single_point_interpolation(self): + track = { + "frame": 0, + "label_id": 0, + "group": None, + "attributes": [], + "shapes": [ + { + "frame": 0, + "points": [1.0, 2.0], + "type": "points", + "occluded": False, + "outside": False, + "attributes": [] + }, + { + "frame": 2, + "attributes": [], + "points": [3.0, 4.0, 5.0, 6.0], + "type": "points", + "occluded": False, + "outside": True + }, + ] + } + + interpolated = TrackManager.get_interpolated_shapes(track, 0, 2) + + self.assertEqual(len(interpolated), 3) \ No newline at end of file