Skip to content

Commit

Permalink
Label color (cvat-ai#2014)
Browse files Browse the repository at this point in the history
* added color to django app and cvat-core

* temp

* temp

* Added label color to mask dump

* Fixed UI for label color picker

* npm packages and CHANGELOG

* fixed models and migrations

* Fixed default background color and using normalization

* Added setting label color with hash

* fixed error

* Added close icon to color picker

* Fixed CHANGELOG

* requested changes

* fixed menu visibility

* Fixed label hashing and algorithm

* Added wheel package to CI

* Fixed dockerfile

* moved wheel package from dockerfile to requirements

* fixed requirements

* Fixed requirements

Co-authored-by: Nikita Manovich <nikita.manovich@intel.com>
  • Loading branch information
ActiveChooN and Nikita Manovich committed Aug 21, 2020
1 parent 822a3b5 commit bee4c37
Show file tree
Hide file tree
Showing 38 changed files with 453 additions and 328 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Siammask tracker as DL serverless function (<https://github.com/opencv/cvat/pull/1988>)
- [Datumaro] Added model info and source info commands (<https://github.com/opencv/cvat/pull/1973>)
- [Datumaro] Dataset statistics (<https://github.com/opencv/cvat/pull/1668>)
- Ability to change label color in tasks and predefined labels (<https://github.com/opencv/cvat/pull/2014>)
- [Datumaro] Multi-dataset merge (https://github.com/opencv/cvat/pull/1695)

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ RUN apt-get update && \
curl && \
curl https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
apt-get --no-install-recommends install -y git-lfs && git lfs install && \
python3 -m pip install --no-cache-dir -U pip==20.0.1 setuptools>=49.1.0 && \
python3 -m pip install --no-cache-dir -U pip==20.0.1 setuptools>=49.1.0 wheel==0.35.1 && \
ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata && \
add-apt-repository --remove ppa:mc3man/gstffmpeg-keep -y && \
Expand Down
2 changes: 1 addition & 1 deletion 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.4.0",
"version": "3.5.0",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "babel.config.js",
"scripts": {
Expand Down
9 changes: 3 additions & 6 deletions cvat-core/src/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
(() => {
const {
AttributeType,
colors,
} = require('./enums');
const { ArgumentError } = require('./exceptions');

Expand Down Expand Up @@ -150,9 +149,6 @@
}
}

if (typeof (data.id) !== 'undefined') {
data.color = colors[data.id % colors.length];
}
data.attributes = [];

if (Object.prototype.hasOwnProperty.call(initialData, 'attributes')
Expand Down Expand Up @@ -193,10 +189,10 @@
color: {
get: () => data.color,
set: (color) => {
if (colors.includes(color)) {
if (typeof color === 'string' && color.match(/^#[0-9a-f]{6}$|^$/)) {
data.color = color;
} else {
throw new ArgumentError('Trying to set unknown color');
throw new ArgumentError('Trying to set wrong color format');
}
},
},
Expand All @@ -217,6 +213,7 @@
const object = {
name: this.name,
attributes: [...this.attributes.map((el) => el.toJSON())],
color: this.color,
};

if (typeof (this.id) !== 'undefined') {
Expand Down
2 changes: 1 addition & 1 deletion 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.7.2",
"version": "1.8.0",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
40 changes: 0 additions & 40 deletions cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ export enum AnnotationActionTypes {
GROUP_ANNOTATIONS_FAILED = 'GROUP_ANNOTATIONS_FAILED',
SPLIT_ANNOTATIONS_SUCCESS = 'SPLIT_ANNOTATIONS_SUCCESS',
SPLIT_ANNOTATIONS_FAILED = 'SPLIT_ANNOTATIONS_FAILED',
CHANGE_LABEL_COLOR_SUCCESS = 'CHANGE_LABEL_COLOR_SUCCESS',
CHANGE_LABEL_COLOR_FAILED = 'CHANGE_LABEL_COLOR_FAILED',
UPDATE_TAB_CONTENT_HEIGHT = 'UPDATE_TAB_CONTENT_HEIGHT',
COLLAPSE_SIDEBAR = 'COLLAPSE_SIDEBAR',
COLLAPSE_APPEARANCE = 'COLLAPSE_APPEARANCE',
Expand Down Expand Up @@ -1288,44 +1286,6 @@ ThunkAction {
};
}

export function changeLabelColorAsync(
label: any,
color: string,
): ThunkAction {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
try {
const {
filters,
showAllInterpolationTracks,
jobInstance,
frame,
} = receiveAnnotationsParameters();

const updatedLabel = label;
updatedLabel.color = color;
const states = await jobInstance.annotations
.get(frame, showAllInterpolationTracks, filters);
const history = await jobInstance.actions.get();

dispatch({
type: AnnotationActionTypes.CHANGE_LABEL_COLOR_SUCCESS,
payload: {
label: updatedLabel,
history,
states,
},
});
} catch (error) {
dispatch({
type: AnnotationActionTypes.CHANGE_LABEL_COLOR_FAILED,
payload: {
error,
},
});
}
};
}

export function changeGroupColorAsync(
group: number,
color: string,
Expand Down
3 changes: 3 additions & 0 deletions cvat-ui/src/assets/colorize-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ function AppearanceBlock(props: Props): JSX.Element {
<div className='cvat-objects-appearance-content'>
<Text type='secondary'>Color by</Text>
<Radio.Group value={colorBy} onChange={changeShapesColorBy}>
<Radio.Button value={ColorBy.LABEL}>{ColorBy.LABEL}</Radio.Button>
<Radio.Button value={ColorBy.INSTANCE}>{ColorBy.INSTANCE}</Radio.Button>
<Radio.Button value={ColorBy.GROUP}>{ColorBy.GROUP}</Radio.Button>
<Radio.Button value={ColorBy.LABEL}>{ColorBy.LABEL}</Radio.Button>
</Radio.Group>
<Text type='secondary'>Opacity</Text>
<Slider
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import React, { useState } from 'react';
import { Row, Col } from 'antd/lib/grid';
import Icon from 'antd/lib/icon';
import Button from 'antd/lib/button';
import Popover from 'antd/lib/popover';
import Text from 'antd/lib/typography/Text';
import { SketchPicker } from 'react-color';
import Tooltip from 'antd/lib/tooltip';

import getCore from 'cvat-core-wrapper';

const core = getCore();

interface Props {
children: React.ReactNode;
value?: string;
visible?: boolean;
resetVisible?: boolean;
onChange?: (value: string) => void;
onVisibleChange?: (visible: boolean) => void;
placement?: 'left' | 'top' | 'right' | 'bottom' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom' | undefined;
}

function ColorPicker(props: Props, ref: React.Ref<any>): JSX.Element {
const {
children,
value,
visible,
resetVisible,
onChange,
onVisibleChange,
placement,
} = props;

const [colorState, setColorState] = useState(value);
const [pickerVisible, setPickerVisible] = useState(false);

const colors = [...core.enums.colors];

const changeVisible = (_visible: boolean): void => {
if (typeof onVisibleChange === 'function') {
onVisibleChange(_visible);
} else {
setPickerVisible(_visible);
}
};

return (
<Popover
content={(
<>
<SketchPicker
color={colorState}
onChange={(color) => setColorState(color.hex)}
presetColors={colors}
ref={ref}
disableAlpha
/>
<Row>
<Col span={9}>
{resetVisible !== false && (
<Button
onClick={() => {
if (typeof onChange === 'function') onChange('');
changeVisible(false);
}}
>
Reset
</Button>
)}
</Col>
<Col span={9}>
<Button
onClick={() => {
changeVisible(false);
}}
>
Cancel
</Button>
</Col>
<Col span={6}>
<Button
type='primary'
onClick={() => {
if (typeof onChange === 'function') onChange(colorState || '');
changeVisible(false);
}}
>
Ok
</Button>
</Col>
</Row>
</>
)}
title={(
<Row type='flex' justify='space-between' align='middle'>
<Col span={12}>
<Text strong>
Select color
</Text>
</Col>
<Col span={4}>
<Tooltip title='Cancel'>
<Button
type='link'
onClick={() => {
changeVisible(false);
}}
>
<Icon type='close' />
</Button>
</Tooltip>
</Col>
</Row>

)}
placement={placement || 'left'}
overlayClassName='cvat-label-color-picker'
trigger='click'
visible={typeof visible === 'boolean' ? visible : pickerVisible}
onVisibleChange={changeVisible}
>
{children}
</Popover>
);
}

export default React.forwardRef(ColorPicker);
Loading

0 comments on commit bee4c37

Please sign in to comment.