From cebd1db5f4c730c9f35a0e18c41b4623cf38b0cc Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 14 Apr 2020 23:43:39 +0300 Subject: [PATCH 1/9] Initial commit --- cvat-ui/src/actions/plugins-actions.ts | 3 + .../top-bar/annotation-menu.tsx | 4 + .../annotation-page/top-bar/reid-plugin.tsx | 176 ++++++++++++++++++ .../top-bar/annotation-menu.tsx | 7 + cvat-ui/src/reducers/interfaces.ts | 1 + cvat-ui/src/reducers/plugins-reducer.ts | 1 + cvat-ui/src/utils/plugin-checker.ts | 3 + cvat-ui/src/utils/reid-utils.ts | 16 ++ cvat/apps/reid/urls.py | 1 + cvat/apps/reid/views.py | 3 + 10 files changed, 215 insertions(+) create mode 100644 cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx create mode 100644 cvat-ui/src/utils/reid-utils.ts diff --git a/cvat-ui/src/actions/plugins-actions.ts b/cvat-ui/src/actions/plugins-actions.ts index 9e88b055969..6ece19294b8 100644 --- a/cvat-ui/src/actions/plugins-actions.ts +++ b/cvat-ui/src/actions/plugins-actions.ts @@ -33,6 +33,7 @@ export function checkPluginsAsync(): ThunkAction { GIT_INTEGRATION: false, TF_ANNOTATION: false, TF_SEGMENTATION: false, + REID: false, }; const promises: Promise[] = [ @@ -41,6 +42,7 @@ export function checkPluginsAsync(): ThunkAction { PluginChecker.check(SupportedPlugins.GIT_INTEGRATION), PluginChecker.check(SupportedPlugins.TF_ANNOTATION), PluginChecker.check(SupportedPlugins.TF_SEGMENTATION), + PluginChecker.check(SupportedPlugins.REID), ]; const values = await Promise.all(promises); @@ -49,6 +51,7 @@ export function checkPluginsAsync(): ThunkAction { [,, plugins.GIT_INTEGRATION] = values; [,,, plugins.TF_ANNOTATION] = values; [,,,, plugins.TF_SEGMENTATION] = values; + [,,,,, plugins.REID] = values; dispatch(pluginActions.checkedAllPlugins(plugins)); }; diff --git a/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx b/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx index 85d057a6f12..76a0cf98e88 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/annotation-menu.tsx @@ -9,6 +9,7 @@ import Modal from 'antd/lib/modal'; import DumpSubmenu from 'components/actions-menu/dump-submenu'; import LoadSubmenu from 'components/actions-menu/load-submenu'; import ExportSubmenu from 'components/actions-menu/export-submenu'; +import ReIDPlugin from './reid-plugin'; interface Props { taskMode: string; @@ -18,6 +19,7 @@ interface Props { loadActivity: string | null; dumpActivities: string[] | null; exportActivities: string[] | null; + installedReID: boolean; onClickMenu(params: ClickParam, file?: File): void; } @@ -39,6 +41,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element { loadActivity, dumpActivities, exportActivities, + installedReID, } = props; let latestParams: ClickParam | null = null; @@ -120,6 +123,7 @@ export default function AnnotationMenuComponent(props: Props): JSX.Element { Open the task + { installedReID && } ); } diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx new file mode 100644 index 00000000000..b224a98cca0 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -0,0 +1,176 @@ +import ReactDOM from 'react-dom'; +import React, { useState, useEffect } from 'react'; +import { Row, Col } from 'antd/lib/grid'; +import Modal from 'antd/lib/modal'; +import Menu from 'antd/lib/menu'; +import Text from 'antd/lib/typography/Text'; +import InputNumber from 'antd/lib/input-number'; +import Tooltip from 'antd/lib/tooltip'; + +import { clamp } from 'utils/math'; +import { run, cancel } from 'utils/reid-utils'; + +interface InputModalProps { + visible: boolean; + onCancel(): void; + onSubmit(threshold: number, distance: number): void; +} + +function InputModal(props: InputModalProps): JSX.Element { + const { visible, onCancel, onSubmit } = props; + const [threshold, setThreshold] = useState(0.5); + const [distance, setDistance] = useState(50); + + const [thresholdMin, thresholdMax] = [0.05, 0.95]; + const [distanceMin, distanceMax] = [1, 1000]; + return ( + onSubmit(threshold, distance)} + okText='Merge' + > + + + + Similarity threshold: + + + + { + if (typeof (value) === 'number') { + setThreshold(clamp(value, thresholdMin, thresholdMax)); + } + }} + /> + + + + + + Max pixel distance: + + + + { + if (typeof (value) === 'number') { + setDistance(clamp(value, distanceMin, distanceMax)); + } + }} + /> + + + + ); +} + +interface InProgressDialogProps { + visible: boolean; + progress: number; + onCancel(): void; +} + +function InProgressDialog(props: InProgressDialogProps): JSX.Element { + const { visible, onCancel, progress } = props; + return ( + + {`Merging is in progress ${progress}%`} + + ); +} + +const reidContainer = window.document.createElement('div'); +reidContainer.setAttribute('id', 'cvat-reid-wrapper'); +window.document.body.appendChild(reidContainer); + +export default function ReIDPlugin(props: {}): JSX.Element { + const { ...rest } = props; + const [showInputDialog, setShowInputDialog] = useState(false); + const [showInProgressDialog, setShowInProgressDialog] = useState(false); + const [progress, setProgress] = useState(0); + + useEffect(() => { + ReactDOM.render(( + <> + { + // get task id + cancel(); + }} + /> + setShowInputDialog(false)} + onSubmit={(threshold: number, distance: number) => { + setProgress(0); + setShowInputDialog(false); + setShowInProgressDialog(true); + + // get annotations + // get job id + // push everything to run + // implement run + const onUpdatePercentage = (percent: number): void => { + setProgress(percent); + }; + + run({ + threshold, + distance, + onUpdatePercentage, + jobID: 0, + annotations: [], + }).then(() => { + // save annotations (just import it to collection) + }).catch((error: Error) => { + Modal.error({ + title: 'Could not merge annotations', + content: error.toString(), + }); + }).finally(() => { + setShowInProgressDialog(false); + }); + }} + /> + + ), reidContainer); + }); + + return ( + { + setShowInputDialog(true); + }} + > + Run ReID merge + + ); +} diff --git a/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx b/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx index c4d0a35bc8f..8c73137d46f 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/annotation-menu.tsx @@ -27,6 +27,7 @@ interface StateToProps { loadActivity: string | null; dumpActivities: string[] | null; exportActivities: string[] | null; + installedReID: boolean; } interface DispatchToProps { @@ -57,6 +58,9 @@ function mapStateToProps(state: CombinedState): StateToProps { exports: activeExports, }, }, + plugins: { + list, + }, } = state; const taskID = jobInstance.task.id; @@ -70,6 +74,7 @@ function mapStateToProps(state: CombinedState): StateToProps { jobInstance, annotationFormats, exporters, + installedReID: list.REID, }; } @@ -105,6 +110,7 @@ function AnnotationMenuContainer(props: Props): JSX.Element { loadActivity, dumpActivities, exportActivities, + installedReID, } = props; const loaders = annotationFormats @@ -157,6 +163,7 @@ function AnnotationMenuContainer(props: Props): JSX.Element { loadActivity={loadActivity} dumpActivities={dumpActivities} exportActivities={exportActivities} + installedReID={installedReID} onClickMenu={onClickMenu} /> ); diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index d794ffd7238..e6e500d4353 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -75,6 +75,7 @@ export enum SupportedPlugins { TF_ANNOTATION = 'TF_ANNOTATION', TF_SEGMENTATION = 'TF_SEGMENTATION', ANALYTICS = 'ANALYTICS', + REID = 'REID', } export interface PluginsState { diff --git a/cvat-ui/src/reducers/plugins-reducer.ts b/cvat-ui/src/reducers/plugins-reducer.ts index ceae9dbca03..176f4b56c2e 100644 --- a/cvat-ui/src/reducers/plugins-reducer.ts +++ b/cvat-ui/src/reducers/plugins-reducer.ts @@ -17,6 +17,7 @@ const defaultState: PluginsState = { TF_ANNOTATION: false, TF_SEGMENTATION: false, ANALYTICS: false, + REID: false, }, }; diff --git a/cvat-ui/src/utils/plugin-checker.ts b/cvat-ui/src/utils/plugin-checker.ts index 38762b06bf1..2d6dc9b0789 100644 --- a/cvat-ui/src/utils/plugin-checker.ts +++ b/cvat-ui/src/utils/plugin-checker.ts @@ -38,6 +38,9 @@ class PluginChecker { case SupportedPlugins.ANALYTICS: { return isReachable(`${serverHost}/analytics/app/kibana`, 'GET'); } + case SupportedPlugins.REID: { + return isReachable(`${serverHost}/reid/enabled`, 'GET'); + } default: return false; } diff --git a/cvat-ui/src/utils/reid-utils.ts b/cvat-ui/src/utils/reid-utils.ts new file mode 100644 index 00000000000..1c9c0daf268 --- /dev/null +++ b/cvat-ui/src/utils/reid-utils.ts @@ -0,0 +1,16 @@ +// TODO: +// add dialog window +// add button to menu +// add run and check callbacks + +export function run(): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, 1000); + }); +} + +export function cancel(): void { + +} diff --git a/cvat/apps/reid/urls.py b/cvat/apps/reid/urls.py index 4decc5cf746..ddb177c04d7 100644 --- a/cvat/apps/reid/urls.py +++ b/cvat/apps/reid/urls.py @@ -9,4 +9,5 @@ path('start/job/', views.start), path('cancel/', views.cancel), path('check/', views.check), + path('enabled', views.enabled), ] diff --git a/cvat/apps/reid/views.py b/cvat/apps/reid/views.py index d0753e46d66..100151ee9d1 100644 --- a/cvat/apps/reid/views.py +++ b/cvat/apps/reid/views.py @@ -94,3 +94,6 @@ def cancel(request, jid): return HttpResponseBadRequest(str(e)) return HttpResponse() + +def enabled(request): + return HttpResponse() From fe89eba0d9079103ad52342fdbf52def99da2137 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 00:41:08 +0300 Subject: [PATCH 2/9] Connected storage --- .../annotation-page/top-bar/reid-plugin.tsx | 53 ++++++++++++++++--- cvat-ui/src/utils/reid-utils.ts | 10 +++- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx index b224a98cca0..c92d1ffe395 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -9,6 +9,8 @@ import Tooltip from 'antd/lib/tooltip'; import { clamp } from 'utils/math'; import { run, cancel } from 'utils/reid-utils'; +import { connect } from 'react-redux'; +import { CombinedState } from 'reducers/interfaces'; interface InputModalProps { visible: boolean; @@ -106,8 +108,36 @@ const reidContainer = window.document.createElement('div'); reidContainer.setAttribute('id', 'cvat-reid-wrapper'); window.document.body.appendChild(reidContainer); -export default function ReIDPlugin(props: {}): JSX.Element { - const { ...rest } = props; + +interface StateToProps { + jobInstance: any | null; +} + +interface DispatchToProps { + +} + +function mapStateToProps(state: CombinedState): StateToProps { + const { + annotation: { + job: { + instance: jobInstance, + }, + }, + } = state; + + return { + jobInstance, + }; +} + +function mapDispatchToProps(dispatch: any): DispatchToProps { + +} + + +function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element { + const { jobInstance, ...rest } = props; const [showInputDialog, setShowInputDialog] = useState(false); const [showInProgressDialog, setShowInProgressDialog] = useState(false); const [progress, setProgress] = useState(0); @@ -131,16 +161,18 @@ export default function ReIDPlugin(props: {}): JSX.Element { setShowInputDialog(false); setShowInProgressDialog(true); - // get annotations + // как экспортировать и импортировать аннотацию, без сохранения на сервере + // на клиенте мы можем только получить аннотацию для текущего фрейма + // скорее всего нужен import row, export raw + // get job id - // push everything to run - // implement run + // get annotations const onUpdatePercentage = (percent: number): void => { setProgress(percent); }; run({ - threshold, + threshold, distance, onUpdatePercentage, jobID: 0, @@ -167,10 +199,17 @@ export default function ReIDPlugin(props: {}): JSX.Element { key='run_reid' title='Run algorithm that merges separated bounding boxes automatically' onClick={() => { - setShowInputDialog(true); + if (jobInstance) { + setShowInputDialog(true); + } }} > Run ReID merge ); } + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(ReIDPlugin); diff --git a/cvat-ui/src/utils/reid-utils.ts b/cvat-ui/src/utils/reid-utils.ts index 1c9c0daf268..053beb7f995 100644 --- a/cvat-ui/src/utils/reid-utils.ts +++ b/cvat-ui/src/utils/reid-utils.ts @@ -3,7 +3,15 @@ // add button to menu // add run and check callbacks -export function run(): Promise { +type Params = { + threshold: number; + distance: number; + onUpdatePercentage(percentage: number): void; + jobID: number; + annotations: any[]; +}; + +export function run(params: Params): Promise { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); From 8d75103bebea0cb62c6f435d45b4101fa9ef25de Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 12:01:25 +0300 Subject: [PATCH 3/9] Added core API method --- cvat-core/src/annotations.js | 28 +++++++++ cvat-core/src/session.js | 60 +++++++++++++++++++ .../annotation-page/top-bar/reid-plugin.tsx | 32 +++++----- cvat-ui/src/utils/reid-utils.ts | 8 +-- 4 files changed, 106 insertions(+), 22 deletions(-) diff --git a/cvat-core/src/annotations.js b/cvat-core/src/annotations.js index 3ee70d3cb48..608faf1eee9 100644 --- a/cvat-core/src/annotations.js +++ b/cvat-core/src/annotations.js @@ -247,6 +247,32 @@ return result; } + function importAnnotations(session, data) { + const sessionType = session instanceof Task ? 'task' : 'job'; + const cache = getCache(sessionType); + + if (cache.has(session)) { + return cache.get(session).collection.import(data); + } + + throw new DataError( + 'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before', + ); + } + + function exportAnnotations(session) { + const sessionType = session instanceof Task ? 'task' : 'job'; + const cache = getCache(sessionType); + + if (cache.has(session)) { + return cache.get(session).collection.export(); + } + + throw new DataError( + 'Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before', + ); + } + async function exportDataset(session, format) { if (!(format instanceof String || typeof format === 'string')) { throw new ArgumentError( @@ -332,6 +358,8 @@ selectObject, uploadAnnotations, dumpAnnotations, + importAnnotations, + exportAnnotations, exportDataset, undoActions, redoActions, diff --git a/cvat-core/src/session.js b/cvat-core/src/session.js index 0ae7fb1ab46..9643cb1bf17 100644 --- a/cvat-core/src/session.js +++ b/cvat-core/src/session.js @@ -97,6 +97,18 @@ return result; }, + async import(data) { + const result = await PluginRegistry + .apiWrapper.call(this, prototype.annotations.import, data); + return result; + }, + + async export() { + const result = await PluginRegistry + .apiWrapper.call(this, prototype.annotations.export); + return result; + }, + async exportDataset(format) { const result = await PluginRegistry .apiWrapper.call(this, prototype.annotations.exportDataset, format); @@ -391,6 +403,28 @@ * @throws {module:API.cvat.exceptions.PluginError} * @instance */ + /** + * + * Import raw data in a collection + * @method import + * @memberof Session.annotations + * @param {Object} data + * @throws {module:API.cvat.exceptions.PluginError} + * @throws {module:API.cvat.exceptions.ArgumentError} + * @instance + * @async + */ + /** + * + * Export a collection as a row data + * @method export + * @memberof Session.annotations + * @returns {Object} data + * @throws {module:API.cvat.exceptions.PluginError} + * @throws {module:API.cvat.exceptions.ArgumentError} + * @instance + * @async + */ /** * Export as a dataset. * Method builds a dataset in the specified format. @@ -695,6 +729,8 @@ search: Object.getPrototypeOf(this).annotations.search.bind(this), upload: Object.getPrototypeOf(this).annotations.upload.bind(this), select: Object.getPrototypeOf(this).annotations.select.bind(this), + import: Object.getPrototypeOf(this).annotations.import.bind(this), + export: Object.getPrototypeOf(this).annotations.export.bind(this), statistics: Object.getPrototypeOf(this).annotations.statistics.bind(this), hasUnsavedChanges: Object.getPrototypeOf(this) .annotations.hasUnsavedChanges.bind(this), @@ -1245,6 +1281,8 @@ search: Object.getPrototypeOf(this).annotations.search.bind(this), upload: Object.getPrototypeOf(this).annotations.upload.bind(this), select: Object.getPrototypeOf(this).annotations.select.bind(this), + import: Object.getPrototypeOf(this).annotations.import.bind(this), + export: Object.getPrototypeOf(this).annotations.export.bind(this), statistics: Object.getPrototypeOf(this).annotations.statistics.bind(this), hasUnsavedChanges: Object.getPrototypeOf(this) .annotations.hasUnsavedChanges.bind(this), @@ -1326,6 +1364,8 @@ annotationsStatistics, uploadAnnotations, dumpAnnotations, + importAnnotations, + exportAnnotations, exportDataset, undoActions, redoActions, @@ -1490,6 +1530,16 @@ return result; }; + Job.prototype.annotations.import.implementation = function (data) { + const result = importAnnotations(this, data); + return result; + }; + + Job.prototype.annotations.export.implementation = function () { + const result = exportAnnotations(this); + return result; + }; + Job.prototype.annotations.dump.implementation = async function (name, dumper) { const result = await dumpAnnotations(this, name, dumper); return result; @@ -1739,6 +1789,16 @@ return result; }; + Task.prototype.annotations.import.implementation = function (data) { + const result = importAnnotations(this, data); + return result; + }; + + Task.prototype.annotations.export.implementation = function () { + const result = exportAnnotations(this); + return result; + }; + Task.prototype.annotations.exportDataset.implementation = async function (format) { const result = await exportDataset(this, format); return result; diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx index c92d1ffe395..a9bb8586c31 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -149,8 +149,7 @@ function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element { visible={showInProgressDialog} progress={progress} onCancel={() => { - // get task id - cancel(); + cancel(jobInstance.id); }} /> { setProgress(percent); }; - run({ - threshold, - distance, - onUpdatePercentage, - jobID: 0, - annotations: [], - }).then(() => { + jobInstance.annotations.export().then((annotations: any) => ( + run({ + threshold, + distance, + onUpdatePercentage, + jobID: jobInstance.id, + annotations, + }) + )).then(() => { // save annotations (just import it to collection) }).catch((error: Error) => { Modal.error({ title: 'Could not merge annotations', content: error.toString(), }); - }).finally(() => { - setShowInProgressDialog(false); - }); + }) + .finally(() => { + setShowInProgressDialog(false); + }); }} /> diff --git a/cvat-ui/src/utils/reid-utils.ts b/cvat-ui/src/utils/reid-utils.ts index 053beb7f995..92dede12947 100644 --- a/cvat-ui/src/utils/reid-utils.ts +++ b/cvat-ui/src/utils/reid-utils.ts @@ -1,14 +1,14 @@ // TODO: -// add dialog window -// add button to menu // add run and check callbacks +// когда запускаем + type Params = { threshold: number; distance: number; onUpdatePercentage(percentage: number): void; jobID: number; - annotations: any[]; + annotations: any; }; export function run(params: Params): Promise { @@ -19,6 +19,6 @@ export function run(params: Params): Promise { }); } -export function cancel(): void { +export function cancel(jobID: number): void { } From 0a0acd7bdfe9a3b54504c7364866942ed61b85ac Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 12:57:26 +0300 Subject: [PATCH 4/9] Done implementation --- .../annotation-page/top-bar/reid-plugin.tsx | 41 +++++---- cvat-ui/src/utils/dextr-utils.ts | 2 - cvat-ui/src/utils/reid-utils.ts | 83 +++++++++++++++++-- cvat/apps/dextr_segmentation/dextr.py | 2 +- cvat/apps/dextr_segmentation/urls.py | 2 +- cvat/apps/reid/urls.py | 2 +- 6 files changed, 106 insertions(+), 26 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx index a9bb8586c31..c1785de0a8d 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -1,3 +1,7 @@ +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT + import ReactDOM from 'react-dom'; import React, { useState, useEffect } from 'react'; import { Row, Col } from 'antd/lib/grid'; @@ -11,6 +15,9 @@ import { clamp } from 'utils/math'; import { run, cancel } from 'utils/reid-utils'; import { connect } from 'react-redux'; import { CombinedState } from 'reducers/interfaces'; +import { fetchAnnotationsAsync } from 'actions/annotation-actions'; + +/* eslint newline-per-chained-call: 0 */ interface InputModalProps { visible: boolean; @@ -114,7 +121,7 @@ interface StateToProps { } interface DispatchToProps { - + updateAnnotations(): void; } function mapStateToProps(state: CombinedState): StateToProps { @@ -132,12 +139,16 @@ function mapStateToProps(state: CombinedState): StateToProps { } function mapDispatchToProps(dispatch: any): DispatchToProps { - + return { + updateAnnotations(): void { + dispatch(fetchAnnotationsAsync()); + }, + }; } function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element { - const { jobInstance, ...rest } = props; + const { jobInstance, updateAnnotations, ...rest } = props; const [showInputDialog, setShowInputDialog] = useState(false); const [showInProgressDialog, setShowInProgressDialog] = useState(false); const [progress, setProgress] = useState(0); @@ -155,7 +166,7 @@ function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element { setShowInputDialog(false)} - onSubmit={(threshold: number, distance: number) => { + onSubmit={async (threshold: number, distance: number) => { setProgress(0); setShowInputDialog(false); setShowInProgressDialog(true); @@ -164,25 +175,27 @@ function ReIDPlugin(props: StateToProps & DispatchToProps): JSX.Element { setProgress(percent); }; - jobInstance.annotations.export().then((annotations: any) => ( - run({ + try { + const annotations = await jobInstance.annotations.export(); + const merged = await run({ threshold, distance, onUpdatePercentage, jobID: jobInstance.id, annotations, - }) - )).then(() => { - // save annotations (just import it to collection) - }).catch((error: Error) => { + }); + await jobInstance.annotations.clear(); + updateAnnotations(); // one more call to do not confuse canvas + await jobInstance.annotations.import(merged); + updateAnnotations(); + } catch (error) { Modal.error({ title: 'Could not merge annotations', content: error.toString(), }); - }) - .finally(() => { - setShowInProgressDialog(false); - }); + } finally { + setShowInProgressDialog(false); + } }} /> diff --git a/cvat-ui/src/utils/dextr-utils.ts b/cvat-ui/src/utils/dextr-utils.ts index 2a0b1e03ec8..54189519158 100644 --- a/cvat-ui/src/utils/dextr-utils.ts +++ b/cvat-ui/src/utils/dextr-utils.ts @@ -143,8 +143,6 @@ function serverRequest( reject(error); }); }); - - // start checking } const plugin: DEXTRPlugin = { diff --git a/cvat-ui/src/utils/reid-utils.ts b/cvat-ui/src/utils/reid-utils.ts index 92dede12947..07c95ee4173 100644 --- a/cvat-ui/src/utils/reid-utils.ts +++ b/cvat-ui/src/utils/reid-utils.ts @@ -1,7 +1,13 @@ -// TODO: -// add run and check callbacks +// Copyright (C) 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT -// когда запускаем +import getCore from 'cvat-core'; +import { ShapeType, RQStatus } from 'reducers/interfaces'; + + +const core = getCore(); +const baseURL = core.config.backendAPI.slice(0, -7); type Params = { threshold: number; @@ -13,12 +19,75 @@ type Params = { export function run(params: Params): Promise { return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(); - }, 1000); + const { + threshold, + distance, + onUpdatePercentage, + jobID, + annotations, + } = params; + const { shapes, ...rest } = annotations; + + const boxes = shapes.filter((shape: any): boolean => shape.type === ShapeType.RECTANGLE); + const others = shapes.filter((shape: any): boolean => shape.type !== ShapeType.RECTANGLE); + + core.server.request( + `${baseURL}/reid/start/job/${params.jobID}`, { + method: 'POST', + data: JSON.stringify({ + threshold, + maxDistance: distance, + boxes, + }), + headers: { + 'Content-Type': 'application/json', + }, + }, + ).then(() => { + const timeoutCallback = (): void => { + core.server.request( + `${baseURL}/reid/check/${jobID}`, { + method: 'GET', + }, + ).then((response: any) => { + const { status } = response; + if (status === RQStatus.finished) { + if (!response.result) { + resolve(annotations); + } + + const result = JSON.parse(response.result); + const collection = rest; + Array.prototype.push.apply(collection.tracks, result); + collection.shapes = others; + resolve(collection); + } else if (status === RQStatus.started) { + const { progress } = response; + onUpdatePercentage(+progress.toFixed(2)); + setTimeout(timeoutCallback, 1000); + } else if (status === RQStatus.failed) { + reject(new Error(response.stderr)); + } else if (status === RQStatus.unknown) { + reject(new Error('Unknown REID status has been received')); + } else { + setTimeout(timeoutCallback, 1000); + } + }).catch((error: Error) => { + reject(error); + }); + }; + + setTimeout(timeoutCallback, 1000); + }).catch((error: Error) => { + reject(error); + }); }); } export function cancel(jobID: number): void { - + core.server.request( + `${baseURL}/reid/cancel/${jobID}`, { + method: 'GET', + }, + ); } diff --git a/cvat/apps/dextr_segmentation/dextr.py b/cvat/apps/dextr_segmentation/dextr.py index 9bb3f3ba311..d6eb2002224 100644 --- a/cvat/apps/dextr_segmentation/dextr.py +++ b/cvat/apps/dextr_segmentation/dextr.py @@ -1,5 +1,5 @@ -# Copyright (C) 2018 Intel Corporation +# Copyright (C) 2018-2020 Intel Corporation # # SPDX-License-Identifier: MIT diff --git a/cvat/apps/dextr_segmentation/urls.py b/cvat/apps/dextr_segmentation/urls.py index 11a92983ef3..6b3120b6793 100644 --- a/cvat/apps/dextr_segmentation/urls.py +++ b/cvat/apps/dextr_segmentation/urls.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Intel Corporation +# Copyright (C) 2018-2020 Intel Corporation # # SPDX-License-Identifier: MIT diff --git a/cvat/apps/reid/urls.py b/cvat/apps/reid/urls.py index ddb177c04d7..431b11192ec 100644 --- a/cvat/apps/reid/urls.py +++ b/cvat/apps/reid/urls.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Intel Corporation +# Copyright (C) 2018-2020 Intel Corporation # # SPDX-License-Identifier: MIT From 6a301152595a4b1b75e8b829cf987a00067654d9 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 12:58:45 +0300 Subject: [PATCH 5/9] Removed rule --- cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx index c1785de0a8d..d182eb3a426 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -17,8 +17,6 @@ import { connect } from 'react-redux'; import { CombinedState } from 'reducers/interfaces'; import { fetchAnnotationsAsync } from 'actions/annotation-actions'; -/* eslint newline-per-chained-call: 0 */ - interface InputModalProps { visible: boolean; onCancel(): void; From 2a9cbe34c815ce7bc8873e7a0d7f9a9e4c60c5ac Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 13:08:29 +0300 Subject: [PATCH 6/9] Removed double cancel --- .../src/components/annotation-page/top-bar/reid-plugin.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx index d182eb3a426..d413df158f2 100644 --- a/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx +++ b/cvat-ui/src/components/annotation-page/top-bar/reid-plugin.tsx @@ -103,6 +103,11 @@ function InProgressDialog(props: InProgressDialogProps): JSX.Element { type: 'danger', }} onOk={onCancel} + cancelButtonProps={{ + style: { + display: 'none', + }, + }} > {`Merging is in progress ${progress}%`} From a08625a85d49ef5de2679b5fd0dfa35a1f21c914 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 13:11:48 +0300 Subject: [PATCH 7/9] Updated changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e620d960da6..85943c3bf2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ability to create one tracked point (https://github.com/opencv/cvat/pull/1383) - Ability to draw/edit polygons and polylines with automatic bordering feature (https://github.com/opencv/cvat/pull/1394) - Tutorial: instructions for CVAT over HTTPS -- Added deep extreme cut (semi-automatic segmentation) to the new UI (https://github.com/opencv/cvat/pull/1398) - +- Deep extreme cut (semi-automatic segmentation) to the new UI (https://github.com/opencv/cvat/pull/1398) +- Re-Identification algorithm to merging bounding boxes automatically to the new UI (https://github.com/opencv/cvat/pull/1406) +- Methods ``import`` and ``export`` to import/export raw annotations for Job and Task in ``cvat-core`` (https://github.com/opencv/cvat/pull/1406) ### Changed - Increase preview size of a task till 256, 256 on the server From 5347ea0ea64541c02aafb34993b958fd99f182d9 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Wed, 15 Apr 2020 15:39:56 +0300 Subject: [PATCH 8/9] Fixed: Cannot read property toFixed of undefined --- cvat-ui/src/utils/reid-utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cvat-ui/src/utils/reid-utils.ts b/cvat-ui/src/utils/reid-utils.ts index 07c95ee4173..181d566c92d 100644 --- a/cvat-ui/src/utils/reid-utils.ts +++ b/cvat-ui/src/utils/reid-utils.ts @@ -53,6 +53,7 @@ export function run(params: Params): Promise { const { status } = response; if (status === RQStatus.finished) { if (!response.result) { + // cancelled resolve(annotations); } @@ -63,7 +64,9 @@ export function run(params: Params): Promise { resolve(collection); } else if (status === RQStatus.started) { const { progress } = response; - onUpdatePercentage(+progress.toFixed(2)); + if (typeof (progress) === 'number') { + onUpdatePercentage(+progress.toFixed(2)); + } setTimeout(timeoutCallback, 1000); } else if (status === RQStatus.failed) { reject(new Error(response.stderr)); From d9c91e076b78d8ca33df35bbef1bb84e30fd5dc1 Mon Sep 17 00:00:00 2001 From: Boris Sekachev <40690378+bsekachev@users.noreply.github.com> Date: Fri, 17 Apr 2020 12:32:57 +0300 Subject: [PATCH 9/9] Update CHANGELOG.md --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7dd52412b9..56206927ceb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.0.0-beta.2] - Unreleased ### Added -- +- Re-Identification algorithm to merging bounding boxes automatically to the new UI (https://github.com/opencv/cvat/pull/1406) +- Methods ``import`` and ``export`` to import/export raw annotations for Job and Task in ``cvat-core`` (https://github.com/opencv/cvat/pull/1406) ### Changed - @@ -35,8 +36,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ability to draw/edit polygons and polylines with automatic bordering feature (https://github.com/opencv/cvat/pull/1394) - Tutorial: instructions for CVAT over HTTPS - Deep extreme cut (semi-automatic segmentation) to the new UI (https://github.com/opencv/cvat/pull/1398) -- Re-Identification algorithm to merging bounding boxes automatically to the new UI (https://github.com/opencv/cvat/pull/1406) -- Methods ``import`` and ``export`` to import/export raw annotations for Job and Task in ``cvat-core`` (https://github.com/opencv/cvat/pull/1406) ### Changed - Increase preview size of a task till 256, 256 on the server