Merge branch 'develop' into bs/undefined_keyword

main
Boris Sekachev 6 years ago committed by GitHub
commit f714510078
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,9 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0-alpha] - Unreleased ## [1.0.0-beta] - Unreleased
### Added ### Added
- Special behaviour for attribute value ``__undefined__`` (invisibility, no shortcuts to be set in AAM) - Special behaviour for attribute value ``__undefined__`` (invisibility, no shortcuts to be set in AAM)
- Dialog window with some helpful information about using filters
### Changed ### Changed
- -
@ -18,11 +19,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- -
### Fixed ### Fixed
- - New shape is added when press ``esc`` when drawing instead of cancellation
### Security ### Security
- -
## [1.0.0-alpha] - 2020-03-31
### Added
- Data streaming using chunks (https://github.com/opencv/cvat/pull/1007)
- New UI: showing file names in UI (https://github.com/opencv/cvat/pull/1311)
- New UI: delete a point from context menu (https://github.com/opencv/cvat/pull/1292)
### Fixed
- Git app cannot clone a repository (https://github.com/opencv/cvat/pull/1330)
- New UI: preview position in task details (https://github.com/opencv/cvat/pull/1312)
- AWS deployment (https://github.com/opencv/cvat/pull/1316)
## [0.6.1] - 2020-03-21 ## [0.6.1] - 2020-03-21
### Changed ### Changed
- VOC task export now does not use official label map by default, but takes one - VOC task export now does not use official label map by default, but takes one

@ -50,6 +50,7 @@ export class DrawHandlerImpl implements DrawHandler {
// so, methods like draw() just undefined for SVG.Shape, but nevertheless they exist // so, methods like draw() just undefined for SVG.Shape, but nevertheless they exist
private drawInstance: any; private drawInstance: any;
private initialized: boolean; private initialized: boolean;
private canceled: boolean;
private pointsGroup: SVG.G | null; private pointsGroup: SVG.G | null;
private shapeSizeElement: ShapeSizeElement; private shapeSizeElement: ShapeSizeElement;
@ -149,6 +150,7 @@ export class DrawHandlerImpl implements DrawHandler {
// Clear drawing // Clear drawing
this.drawInstance.draw('stop'); this.drawInstance.draw('stop');
} }
this.drawInstance.off(); this.drawInstance.off();
this.drawInstance.remove(); this.drawInstance.remove();
this.drawInstance = null; this.drawInstance = null;
@ -161,6 +163,10 @@ export class DrawHandlerImpl implements DrawHandler {
if (this.crosshair) { if (this.crosshair) {
this.removeCrosshair(); this.removeCrosshair();
} }
if (!this.drawData.initialState) {
this.onDrawDone(null);
}
} }
private initDrawing(): void { private initDrawing(): void {
@ -175,8 +181,9 @@ export class DrawHandlerImpl implements DrawHandler {
const bbox = (e.target as SVGRectElement).getBBox(); const bbox = (e.target as SVGRectElement).getBBox();
const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox); const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox);
const { shapeType } = this.drawData; const { shapeType } = this.drawData;
this.cancel(); this.release();
if (this.canceled) return;
if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) { if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) {
this.onDrawDone({ this.onDrawDone({
shapeType, shapeType,
@ -290,11 +297,11 @@ export class DrawHandlerImpl implements DrawHandler {
this.drawInstance.on('drawdone', (e: CustomEvent): void => { this.drawInstance.on('drawdone', (e: CustomEvent): void => {
const targetPoints = pointsToArray((e.target as SVGElement).getAttribute('points')); const targetPoints = pointsToArray((e.target as SVGElement).getAttribute('points'));
const { points, box } = this.getFinalPolyshapeCoordinates(targetPoints); const { points, box } = this.getFinalPolyshapeCoordinates(targetPoints);
const { shapeType } = this.drawData; const { shapeType } = this.drawData;
this.cancel(); this.release();
if (this.canceled) return;
if (shapeType === 'polygon' if (shapeType === 'polygon'
&& ((box.xbr - box.xtl) * (box.ybr - box.ytl) >= consts.AREA_THRESHOLD) && ((box.xbr - box.xtl) * (box.ybr - box.ytl) >= consts.AREA_THRESHOLD)
&& points.length >= 3 * 2) { && points.length >= 3 * 2) {
@ -598,6 +605,7 @@ export class DrawHandlerImpl implements DrawHandler {
this.canvas = canvas; this.canvas = canvas;
this.text = text; this.text = text;
this.initialized = false; this.initialized = false;
this.canceled = false;
this.drawData = null; this.drawData = null;
this.geometry = null; this.geometry = null;
this.crosshair = null; this.crosshair = null;
@ -671,17 +679,18 @@ export class DrawHandlerImpl implements DrawHandler {
this.geometry = geometry; this.geometry = geometry;
if (drawData.enabled) { if (drawData.enabled) {
this.canceled = false;
this.drawData = drawData; this.drawData = drawData;
this.initDrawing(); this.initDrawing();
this.startDraw(); this.startDraw();
} else { } else {
this.cancel(); this.release();
this.drawData = drawData; this.drawData = drawData;
} }
} }
public cancel(): void { public cancel(): void {
this.canceled = true;
this.release(); this.release();
this.onDrawDone(null);
} }
} }

@ -441,7 +441,7 @@
* Returns the ranges of cached frames * Returns the ranges of cached frames
* @method ranges * @method ranges
* @memberof Session.frames * @memberof Session.frames
* @returns {Array{string}} * @returns {Array.<string>}
* @instance * @instance
* @async * @async
*/ */
@ -520,7 +520,8 @@
* @returns {HistoryActions} * @returns {HistoryActions}
* @throws {module:API.cvat.exceptions.PluginError} * @throws {module:API.cvat.exceptions.PluginError}
* @throws {module:API.cvat.exceptions.ArgumentError} * @throws {module:API.cvat.exceptions.ArgumentError}
* @returns {[string, number][]} array of pairs [action name, frame number] * @returns {Array.<Array.<string|number>>}
* array of pairs [action name, frame number]
* @instance * @instance
* @async * @async
*/ */

@ -2,9 +2,14 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import React from 'react'; import React, { useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Select, { SelectValue, LabeledValue } from 'antd/lib/select'; 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 Icon from 'antd/lib/icon';
import { import {
@ -16,6 +21,8 @@ import { CombinedState } from 'reducers/interfaces';
interface StateToProps { interface StateToProps {
annotationsFilters: string[]; annotationsFilters: string[];
annotationsFiltersHistory: string[]; annotationsFiltersHistory: string[];
searchForwardShortcut: string;
searchBackwardShortcut: string;
} }
interface DispatchToProps { interface DispatchToProps {
@ -30,11 +37,16 @@ function mapStateToProps(state: CombinedState): StateToProps {
filtersHistory: annotationsFiltersHistory, filtersHistory: annotationsFiltersHistory,
}, },
}, },
shortcuts: {
normalizedKeyMap,
},
} = state; } = state;
return { return {
annotationsFilters, annotationsFilters,
annotationsFiltersHistory, 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 (
<>
<Paragraph>
<Title level={3}>General</Title>
</Paragraph>
<Paragraph>
You can use filters to display only subset of objects on a frame
or to search objects that satisfy the filters using hotkeys
<Text strong>
{` ${searchForwardShortcut} `}
</Text>
and
<Text strong>
{` ${searchBackwardShortcut} `}
</Text>
</Paragraph>
<Paragraph>
<Text strong>Supported properties: </Text>
width, height, label, serverID, clientID, type, shape, occluded
<br />
<Text strong>Supported operators: </Text>
==, !=, &gt;, &gt;=, &lt;, &lt;=, ~=, (), &amp; and |
<br />
<Text strong>
If you have double quotes in your query string,
please escape them using back slash: \&quot; (see the latest example)
</Text>
<br />
All properties and values are case-sensitive.
CVAT uses json queries to perform search.
</Paragraph>
<Paragraph>
<Title level={3}>Examples</Title>
<ul>
<li>label==&quot;car&quot; | label==[&quot;road sign&quot;]</li>
<li>width &gt;= height</li>
<li>attr[&quot;Attribute 1&quot;] == attr[&quot;Attribute 2&quot;]</li>
<li>clientID == 50</li>
<li>
(label==&quot;car&quot; &amp; attr[&quot;parked&quot;]==true)
| (label==&quot;pedestrian&quot; &amp; width &gt; 150)
</li>
<li>
(( label==[&quot;car \&quot;mazda\&quot;&quot;])
&amp; (attr[&quot;sunglasses&quot;]==true
| (width &gt; 150 | height &gt; 150 &amp; (clientID == serverID)))))
</li>
</ul>
</Paragraph>
</>
);
}
function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Element { function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Element {
const { const {
annotationsFilters, annotationsFilters,
annotationsFiltersHistory, annotationsFiltersHistory,
searchForwardShortcut,
searchBackwardShortcut,
changeAnnotationsFilters, changeAnnotationsFilters,
} = props; } = props;
const [underCursor, setUnderCursor] = useState(false);
return ( return (
<Select <Select
className='cvat-annotations-filters-input' className='cvat-annotations-filters-input'
@ -70,13 +143,36 @@ function AnnotationsFiltersInput(props: StateToProps & DispatchToProps): JSX.Ele
value={annotationsFilters} value={annotationsFilters}
mode='tags' mode='tags'
style={{ width: '100%' }} style={{ width: '100%' }}
placeholder={( placeholder={
<> underCursor ? (
<Icon type='filter' /> <>
<span style={{ marginLeft: 5 }}>Annotations filter</span> <Tooltip title='Click to open help'>
</> <Icon
)} type='filter'
onClick={(e: React.MouseEvent) => {
e.stopPropagation();
Modal.info({
width: 700,
title: 'How to use filters?',
content: filtersHelpModalContent(
searchForwardShortcut,
searchBackwardShortcut,
),
});
}}
/>
</Tooltip>
</>
) : (
<>
<Icon style={{ transform: 'scale(0.9)' }} type='filter' />
<span style={{ marginLeft: 5 }}>Annotations filters</span>
</>
)
}
onChange={changeAnnotationsFilters} onChange={changeAnnotationsFilters}
onMouseEnter={() => setUnderCursor(true)}
onMouseLeave={() => setUnderCursor(false)}
> >
{annotationsFiltersHistory.map((element: string): JSX.Element => ( {annotationsFiltersHistory.map((element: string): JSX.Element => (
<Select.Option key={element} value={element}>{element}</Select.Option> <Select.Option key={element} value={element}>{element}</Select.Option>

@ -4,6 +4,6 @@
from cvat.utils.version import get_version from cvat.utils.version import get_version
VERSION = (1, 0, 0, 'alpha', 0) VERSION = (1, 0, 0, 'beta', 0)
__version__ = get_version(VERSION) __version__ = get_version(VERSION)

@ -293,7 +293,10 @@ class TrackManager(ObjectManager):
@staticmethod @staticmethod
def normalize_shape(shape): 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) broken_line = geometry.LineString(points)
points = [] points = []
for off in range(0, 100, 1): for off in range(0, 100, 1):

@ -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)
Loading…
Cancel
Save