From e9547e4bd5ad567a4db2c852e3597af10c4b5a23 Mon Sep 17 00:00:00 2001 From: klakhov Date: Fri, 25 Aug 2023 11:57:29 +0300 Subject: [PATCH 01/37] initial commit --- .../controls-side-bar/opencv-control.tsx | 24 ++++++++++ .../utils/opencv-wrapper/gamma-correciton.ts | 47 +++++++++++++++++++ .../utils/opencv-wrapper/opencv-wrapper.ts | 5 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index ef1ce7e6a4fd..224776a1a976 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -702,6 +702,30 @@ class OpenCVControlComponent extends React.PureComponent + + + ); diff --git a/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts b/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts new file mode 100644 index 000000000000..c677c196429d --- /dev/null +++ b/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts @@ -0,0 +1,47 @@ +// Copyright (C) 2023 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + +import { ImageProcessing } from './opencv-interfaces'; + +export interface GammaCorrection extends ImageProcessing { + processImage: (src: ImageData, frameNumber: number) => ImageData; +} + +export default class GammaCorrectionImplementation implements GammaCorrection { + private cv: any; + public currentProcessedImage: number | undefined; + + constructor(cv: any) { + this.cv = cv; + } + + public processImage(src: ImageData, frameNumber: number): ImageData { + console.log('Gamma called'); + const gammaParam = 3.0; + const inverseGamma = 1.0 / gammaParam; + const lut = []; + for (let i = 0; i < 256; i++) { + lut[i] = Math.floor(255 * ((i / 255) ** inverseGamma)); + } + // const { cv } = this; + // console.log(cv.getBuildInformation()); + // let matImage = null; + // matImage = cv.matFromImageData(src); + for (let i = 0; i < src.data.length; i += 4) { + src.data[i + 0] = lut[src.data[i + 0]]; + src.data[i + 1] = lut[src.data[i + 1]]; + src.data[i + 2] = lut[src.data[i + 2]]; + } + // matImage = new cv.Mat(); + // const lut = new cv.Mat.zeros(256, 4, cv.CV_8S); + // const out = new cv.Mat(); + // console.log(matImage, lut, out); + // cv.LUT(matImage, lut, out); + // const arr = new Uint8ClampedArray(matImage.data, matImage.cols, matImage.rows); + // const imgData = new ImageData(arr, src.width, src.height); + // matImage.delete(); + this.currentProcessedImage = frameNumber; + return src; + } +} diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts index 36e0568aca74..fbf04d155938 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts @@ -8,6 +8,7 @@ import HistogramEqualizationImplementation, { HistogramEqualization } from './hi import TrackerMImplementation from './tracker-mil'; import IntelligentScissorsImplementation, { IntelligentScissors } from './intelligent-scissors'; import { OpenCVTracker } from './opencv-interfaces'; +import GammaCorrectionImplementation, { GammaCorrection } from './gamma-correciton'; const core = getCore(); const baseURL = core.config.backendAPI.slice(0, -7); @@ -32,6 +33,7 @@ export interface Contours { export interface ImgProc { hist: () => HistogramEqualization; + gamma: () => GammaCorrection; } export interface Tracking { @@ -105,7 +107,7 @@ export class OpenCVWrapper { const global = window as any; - this.cv = await global.cv; + this.cv = global.cv; } public async initialize(onProgress: (percent: number) => void): Promise { @@ -220,6 +222,7 @@ export class OpenCVWrapper { this.checkInitialization(); return { hist: () => new HistogramEqualizationImplementation(this.cv), + gamma: () => new GammaCorrectionImplementation(this.cv), }; } From f2faf9fc0ca7dc88d954a809c0512730fcd2b462 Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 30 Aug 2023 09:50:36 +0300 Subject: [PATCH 02/37] added image filter actions --- cvat-ui/package.json | 2 + cvat-ui/src/actions/settings-actions.ts | 22 ++++++- .../controls-side-bar/opencv-control.tsx | 16 +++-- cvat-ui/src/reducers/index.ts | 10 ++- cvat-ui/src/reducers/settings-reducer.ts | 30 +++++++++ .../utils/opencv-wrapper/gamma-correciton.ts | 19 ++++-- .../utils/opencv-wrapper/opencv-wrapper.ts | 2 +- yarn.lock | 64 +++++++++++-------- 8 files changed, 127 insertions(+), 38 deletions(-) diff --git a/cvat-ui/package.json b/cvat-ui/package.json index ae0bf54801f5..5cc8829549d4 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -36,6 +36,8 @@ "@types/redux-logger": "^3.0.9", "@types/resize-observer-browser": "^0.1.6", "@uiw/react-md-editor": "^3.22.0", + "@types/fabric": "^4.5.7", + "fabric": "^5.2.1", "antd": "~4.18.9", "chart.js": "^4.3.0", "copy-to-clipboard": "^3.3.1", diff --git a/cvat-ui/src/actions/settings-actions.ts b/cvat-ui/src/actions/settings-actions.ts index 0e37fe7d3da5..6c46f3d8cd5c 100644 --- a/cvat-ui/src/actions/settings-actions.ts +++ b/cvat-ui/src/actions/settings-actions.ts @@ -4,7 +4,7 @@ import { AnyAction } from 'redux'; import { - GridColor, ColorBy, SettingsState, ToolsBlockerState, + GridColor, ColorBy, SettingsState, ToolsBlockerState, ImageFilter, } from 'reducers'; export enum SettingsActionTypes { @@ -45,6 +45,8 @@ export enum SettingsActionTypes { SWITCH_TOOLS_BLOCKER_STATE = 'SWITCH_TOOLS_BLOCKER_STATE', SWITCH_SHOWING_DELETED_FRAMES = 'SWITCH_SHOWING_DELETED_FRAMES', SWITCH_SHOWING_TAGS_ON_FRAME = 'SWITCH_SHOWING_TAGS_ON_FRAME', + ADD_IMAGE_FILTER = 'ADD_IMAGE_FILTER', + REMOVE_IMAGE_FILTER = 'REMOVE_IMAGE_FILTER', } export function changeShapesOpacity(opacity: number): AnyAction { @@ -380,3 +382,21 @@ export function switchShowingTagsOnFrame(showTagsOnFrame: boolean): AnyAction { }, }; } + +export function addImageFilter(filter: ImageFilter): AnyAction { + return { + type: SettingsActionTypes.ADD_IMAGE_FILTER, + payload: { + filter, + }, + }; +} + +export function removeImageFilter(filterAlias: string): AnyAction { + return { + type: SettingsActionTypes.REMOVE_IMAGE_FILTER, + payload: { + filterAlias, + }, + }; +} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 224776a1a976..6696863df78a 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -21,7 +21,7 @@ import { getCore } from 'cvat-core-wrapper'; import openCVWrapper from 'utils/opencv-wrapper/opencv-wrapper'; import { IntelligentScissors } from 'utils/opencv-wrapper/intelligent-scissors'; import { - CombinedState, ActiveControl, OpenCVTool, ObjectType, ShapeType, ToolsBlockerState, + CombinedState, ActiveControl, OpenCVTool, ObjectType, ShapeType, ToolsBlockerState, ImageFilter, } from 'reducers'; import { interactWithCanvas, @@ -37,7 +37,7 @@ import ApproximationAccuracy, { thresholdFromAccuracy, } from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy'; import { ImageProcessing, OpenCVTracker, TrackerModel } from 'utils/opencv-wrapper/opencv-interfaces'; -import { switchToolsBlockerState } from 'actions/settings-actions'; +import { addImageFilter as addImageFilterAction, removeImageFilter as removeImageFilterAction, switchToolsBlockerState } from 'actions/settings-actions'; import withVisibilityHandling from './handle-popover-visibility'; interface Props { @@ -62,6 +62,8 @@ interface DispatchToProps { changeFrame(toFrame: number, fillBuffer?: boolean, frameStep?: number, forceUpdate?: boolean):void; onSwitchToolsBlockerState(toolsBlockerState: ToolsBlockerState):void; switchNavigationBlocked(navigationBlocked: boolean): void; + addImageFilter(filter: ImageFilter): void; + removeImageFilter(filterAlias: string): void; } interface TrackedShape { @@ -132,6 +134,8 @@ const mapDispatchToProps = { changeFrame: changeFrameAsync, onSwitchToolsBlockerState: switchToolsBlockerState, switchNavigationBlocked: switchNavigationBlockedAction, + addImageFilter: addImageFilterAction, + removeImageFilter: removeImageFilterAction, }; class OpenCVControlComponent extends React.PureComponent { @@ -572,6 +576,7 @@ class OpenCVControlComponent extends React.PureComponent imageModifier.alias === alias); if (index !== -1) { @@ -580,15 +585,18 @@ class OpenCVControlComponent extends React.PureComponent ({ ...prev, activeImageModifiers: [...prev.activeImageModifiers, { modifier, alias }], }), () => { this.runImageModifier(); }); + addImageFilter({ modifier, alias }); } private enableCanvasForceUpdate():void { @@ -702,7 +710,7 @@ class OpenCVControlComponent extends React.PureComponent - + {/* - + */} ); diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index 0271e14b0209..15f9f5b6ef6b 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -11,7 +11,7 @@ import { } from 'cvat-core-wrapper'; import { IntelligentScissors } from 'utils/opencv-wrapper/intelligent-scissors'; import { KeyMap } from 'utils/mousetrap-react'; -import { OpenCVTracker } from 'utils/opencv-wrapper/opencv-interfaces'; +import { ImageProcessing, OpenCVTracker } from 'utils/opencv-wrapper/opencv-interfaces'; export type StringObject = { [index: string]: string; @@ -121,6 +121,11 @@ export interface TasksState { }; } +export interface ImageFilter { + modifier: ImageProcessing, + alias: string +} + export interface ExportState { projects: { dataset: { @@ -826,6 +831,9 @@ export interface SettingsState { shapes: ShapesSettingsState; workspace: WorkspaceSettingsState; player: PlayerSettingsState; + imageProcessing: { + filters: ImageFilter[] + }; showDialog: boolean; } diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index e732f26a7e7d..f67f86713e71 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -60,6 +60,9 @@ const defaultState: SettingsState = { contrastLevel: 100, saturationLevel: 100, }, + imageProcessing: { + filters: [], + }, showDialog: false, }; @@ -394,6 +397,33 @@ export default (state = defaultState, action: AnyAction): SettingsState => { }, }; } + case SettingsActionTypes.ADD_IMAGE_FILTER: { + return { + ...state, + imageProcessing: { + ...state.imageProcessing, + filters: [ + ...state.imageProcessing.filters, + action.payload.filter, + ], + }, + }; + } + case SettingsActionTypes.REMOVE_IMAGE_FILTER: { + const { filterAlias } = action.payload; + const filters = [...state.imageProcessing.filters]; + const index = filters.findIndex((imageModifier) => imageModifier.alias === filterAlias); + if (index !== -1) { + filters.splice(index, 1); + } + return { + ...state, + imageProcessing: { + ...state.imageProcessing, + filters, + }, + }; + } case AnnotationActionTypes.UPLOAD_JOB_ANNOTATIONS_SUCCESS: case AnnotationActionTypes.CREATE_ANNOTATIONS_SUCCESS: case AnnotationActionTypes.CHANGE_FRAME_SUCCESS: { diff --git a/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts b/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts index c677c196429d..3d40309a191c 100644 --- a/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts +++ b/cvat-ui/src/utils/opencv-wrapper/gamma-correciton.ts @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT +import { fabric } from 'fabric'; import { ImageProcessing } from './opencv-interfaces'; export interface GammaCorrection extends ImageProcessing { @@ -24,15 +25,23 @@ export default class GammaCorrectionImplementation implements GammaCorrection { for (let i = 0; i < 256; i++) { lut[i] = Math.floor(255 * ((i / 255) ** inverseGamma)); } + const f = new fabric.Image.filters.Gamma({ + gamma: [0.5, 0.5, 0.5], + }); + console.log(f); + const r = f.applyTo2d({ + imageData: src, + }); + console.log(r); // const { cv } = this; // console.log(cv.getBuildInformation()); // let matImage = null; // matImage = cv.matFromImageData(src); - for (let i = 0; i < src.data.length; i += 4) { - src.data[i + 0] = lut[src.data[i + 0]]; - src.data[i + 1] = lut[src.data[i + 1]]; - src.data[i + 2] = lut[src.data[i + 2]]; - } + // for (let i = 0; i < src.data.length; i += 4) { + // src.data[i + 0] = lut[src.data[i + 0]]; + // src.data[i + 1] = lut[src.data[i + 1]]; + // src.data[i + 2] = lut[src.data[i + 2]]; + // } // matImage = new cv.Mat(); // const lut = new cv.Mat.zeros(256, 4, cv.CV_8S); // const out = new cv.Mat(); diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts index fbf04d155938..cba90ee2e2e7 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts @@ -107,7 +107,7 @@ export class OpenCVWrapper { const global = window as any; - this.cv = global.cv; + this.cv = await global.cv; } public async initialize(onProgress: (percent: number) => void): Promise { diff --git a/yarn.lock b/yarn.lock index 7af6ed7b11b5..ebf4f16a7302 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,9 +1666,9 @@ integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== "@mapbox/node-pre-gyp@^1.0.0": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c" - integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== + version "1.0.11" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" + integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== dependencies: detect-libc "^2.0.0" https-proxy-agent "^5.0.0" @@ -3373,9 +3373,9 @@ caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503: integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA== canvas@^2.8.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.0.tgz#7f0c3e9ae94cf469269b5d3a7963a7f3a9936434" - integrity sha512-bdTjFexjKJEwtIo0oRx8eD4G2yWoUOXP9lj279jmQ2zMnTQhT8C3512OKz3s+ZOaQlLbE7TuVvRDYDB3Llyy5g== + version "2.11.2" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" + integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== dependencies: "@mapbox/node-pre-gyp" "^1.0.0" nan "^2.17.0" @@ -4245,9 +4245,9 @@ detect-browser@^5.2.1: integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== detect-libc@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" - integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== + version "2.0.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" + integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== detect-newline@^3.0.0: version "3.1.0" @@ -8215,12 +8215,10 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -minipass@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b" - integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw== - dependencies: - yallist "^4.0.0" +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== minizlib@^2.1.1: version "2.1.2" @@ -8319,9 +8317,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-fetch@^2.6.7: - version "2.6.8" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e" - integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg== + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" @@ -8450,7 +8448,12 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nwsapi@^2.2.0, nwsapi@^2.2.2: +nwsapi@^2.2.0: + version "2.2.7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" + integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + +nwsapi@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== @@ -10186,7 +10189,7 @@ readable-stream@^2.0.1, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.6.0: +readable-stream@^3.0.2, readable-stream@^3.0.6: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -10195,6 +10198,15 @@ readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -12149,13 +12161,13 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== tar@^6.1.11: - version "6.1.13" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" - integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== + version "6.1.15" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" + integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" - minipass "^4.0.0" + minipass "^5.0.0" minizlib "^2.1.1" mkdirp "^1.0.3" yallist "^4.0.0" @@ -13254,12 +13266,12 @@ write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" -ws@^8.11.0: +ws@^8.11.0, ws@^8.2.3: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== -ws@^8.2.3, ws@^8.4.2: +ws@^8.4.2: version "8.12.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8" integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig== From eed9053682c729ecb538c036b045e4a933ed245a Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 30 Aug 2023 13:01:04 +0300 Subject: [PATCH 03/37] run image modifiers from high-level component --- .../controls-side-bar/opencv-control.tsx | 33 ++++--- .../standard-workspace/image-processing.tsx | 95 +++++++++++++++++++ .../standard-workspace/standard-workspace.tsx | 2 + 3 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 6696863df78a..3336d2623620 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -167,7 +167,7 @@ class OpenCVControlComponent extends React.PureComponent) => { - const modifier = this.imageModifier('histogram'); - if (!modifier) { - this.enableImageModifier(openCVWrapper.imgproc.hist(), 'histogram'); - } else { - const button = e.target as HTMLElement; - button.blur(); - this.disableImageModifier('histogram'); - const { changeFrame } = this.props; - const { frame } = this.props; - this.enableCanvasForceUpdate(); - changeFrame(frame, false, 1, true); - } + // const modifier = this.imageModifier('histogram'); + // if (!modifier) { + // this.enableImageModifier(openCVWrapper.imgproc.hist(), 'histogram'); + // } else { + // const button = e.target as HTMLElement; + // button.blur(); + // this.disableImageModifier('histogram'); + // const { changeFrame } = this.props; + // const { frame } = this.props; + // this.enableCanvasForceUpdate(); + // changeFrame(frame, false, 1, true); + // } + const { addImageFilter } = this.props; + addImageFilter({ + modifier: openCVWrapper.imgproc.hist(), + alias: 'opencv.histogram', + }); }} > diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx new file mode 100644 index 000000000000..a41b4beaf642 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -0,0 +1,95 @@ +// Copyright (C) 2022 Intel Corporation +// Copyright (C) CVAT.ai corp +// +// SPDX-License-Identifier: MIT + +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { Canvas } from 'cvat-canvas-wrapper'; +import { useSelector } from 'react-redux'; +import { CombinedState, ImageFilter } from 'reducers'; +import notification from 'antd/lib/notification'; + +export default function ImageProcessingComponent(): JSX.Element | null { + const filtersRef = useRef([]); + const frame = useRef(null); + useSelector((state: CombinedState) => { + filtersRef.current = state.settings.imageProcessing.filters; + frame.current = state.annotation.player.frame.number; + }); + + const canvasInstance = useSelector((state: CombinedState) => state.annotation.canvas.instance) as Canvas; + const states = useSelector((state: CombinedState) => state.annotation.annotations.states); + const curZOrder = useSelector((state: CombinedState) => state.annotation.annotations.zLayer.cur); + const frameData = useSelector((state: CombinedState) => state.annotation.player.frame.data); + const filters = useSelector((state: CombinedState) => state.settings.imageProcessing.filters); + + const getCanvasImageData = ():ImageData => { + const canvas: HTMLCanvasElement | null = window.document.getElementById('cvat_canvas_background') as + | HTMLCanvasElement + | null; + if (!canvas) { + throw new Error('Element #cvat_canvas_background was not found'); + } + const { width, height } = canvas; + const context = canvas.getContext('2d'); + if (!context) { + throw new Error('Canvas context is empty'); + } + return context.getImageData(0, 0, width, height); + }; + + const runImageModifier = useCallback(async (): Promise => { + try { + const currentFilters = filtersRef.current; + const currentFrame = frame.current; + if ( + currentFilters && currentFrame !== null && + currentFilters.length !== 0 && + currentFilters[0].modifier.currentProcessedImage !== currentFrame + ) { + canvasInstance.configure({ forceFrameUpdate: true }); + const imageData = getCanvasImageData(); + const newImageData = currentFilters + .reduce((oldImageData, activeImageModifier) => activeImageModifier + .modifier.processImage(oldImageData, currentFrame), imageData); + const imageBitmap = await createImageBitmap(newImageData); + const proxy = new Proxy(frameData, { + get: (_frameData, prop, receiver) => { + if (prop === 'data') { + return async () => ({ + renderWidth: imageData.width, + renderHeight: imageData.height, + imageData: imageBitmap, + }); + } + + return Reflect.get(_frameData, prop, receiver); + }, + }); + canvasInstance.setup(proxy, states, curZOrder); + } + } catch (error: any) { + notification.error({ + description: error.toString(), + message: 'OpenCV.js processing error occurred', + className: 'cvat-notification-notice-opencv-processing-error', + }); + } finally { + canvasInstance.configure({ forceFrameUpdate: false }); + } + }, [canvasInstance, filters]); + + useEffect(() => { + if (canvasInstance) { + canvasInstance.html().addEventListener('canvas.setup', runImageModifier); + } + return () => { + canvasInstance.html().removeEventListener('canvas.setup', runImageModifier); + }; + }, []); + + useEffect(() => { + runImageModifier(); + }, [filters]); + return null; +} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx index 3c90aa95d011..25605edbe33a 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/standard-workspace.tsx @@ -16,6 +16,7 @@ import CanvasPointContextMenuComponent from 'components/annotation-page/canvas/v import IssueAggregatorComponent from 'components/annotation-page/review/issues-aggregator'; import RemoveConfirmComponent from 'components/annotation-page/standard-workspace/remove-confirm'; import PropagateConfirmComponent from 'components/annotation-page/standard-workspace/propagate-confirm'; +import ImageProcessingComponent from './image-processing'; export default function StandardWorkspaceComponent(): JSX.Element { return ( @@ -28,6 +29,7 @@ export default function StandardWorkspaceComponent(): JSX.Element { + ); } From a9c859f6976d3c81ec9dad9f0c1f07a337b8a1f2 Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 30 Aug 2023 13:55:14 +0300 Subject: [PATCH 04/37] draft of adding/removing filters --- .../controls-side-bar/opencv-control.tsx | 43 ++++++------------- .../standard-workspace/image-processing.tsx | 16 +++++-- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 3336d2623620..ffa6a8504c84 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -52,6 +52,7 @@ interface Props { frameData: any; toolsBlockerState: ToolsBlockerState; activeControl: ActiveControl; + filters: ImageFilter[]; } interface DispatchToProps { @@ -82,7 +83,7 @@ interface State { mode: 'interaction' | 'tracking'; trackedShapes: TrackedShape[]; activeTracker: OpenCVTracker | null; - trackers: OpenCVTracker[] + trackers: OpenCVTracker[]; } interface ImageModifier { @@ -108,6 +109,7 @@ function mapStateToProps(state: CombinedState): Props { }, settings: { workspace: { defaultApproxPolyAccuracy, toolsBlockerState }, + imageProcessing: { filters }, }, } = state; @@ -123,6 +125,7 @@ function mapStateToProps(state: CombinedState): Props { frame, frameData, toolsBlockerState, + filters, }; } @@ -705,40 +708,22 @@ class OpenCVControlComponent extends React.PureComponent - - - - {/* - - */} + ); diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx index a41b4beaf642..4947ab5fb5bf 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -5,9 +5,10 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Canvas } from 'cvat-canvas-wrapper'; -import { useSelector } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; import { CombinedState, ImageFilter } from 'reducers'; import notification from 'antd/lib/notification'; +import { changeFrameAsync } from 'actions/annotation-actions'; export default function ImageProcessingComponent(): JSX.Element | null { const filtersRef = useRef([]); @@ -23,6 +24,8 @@ export default function ImageProcessingComponent(): JSX.Element | null { const frameData = useSelector((state: CombinedState) => state.annotation.player.frame.data); const filters = useSelector((state: CombinedState) => state.settings.imageProcessing.filters); + const dispatch = useDispatch(); + const getCanvasImageData = ():ImageData => { const canvas: HTMLCanvasElement | null = window.document.getElementById('cvat_canvas_background') as | HTMLCanvasElement @@ -42,6 +45,7 @@ export default function ImageProcessingComponent(): JSX.Element | null { try { const currentFilters = filtersRef.current; const currentFrame = frame.current; + console.log('run image modifier', currentFilters); if ( currentFilters && currentFrame !== null && currentFilters.length !== 0 && @@ -77,7 +81,7 @@ export default function ImageProcessingComponent(): JSX.Element | null { } finally { canvasInstance.configure({ forceFrameUpdate: false }); } - }, [canvasInstance, filters]); + }, [canvasInstance]); useEffect(() => { if (canvasInstance) { @@ -89,7 +93,13 @@ export default function ImageProcessingComponent(): JSX.Element | null { }, []); useEffect(() => { - runImageModifier(); + if (filters.length !== 0) { + runImageModifier(); + } else if (frame.current !== null) { + console.log('changeframe'); + canvasInstance.configure({ forceFrameUpdate: true }); + dispatch(changeFrameAsync(frame.current, false, 1, true)); + } }, [filters]); return null; } From 1437e48746f601efa89ec93eb2a28e8e0c109c5d Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 30 Aug 2023 14:30:59 +0300 Subject: [PATCH 05/37] removed image filtering logic from opencv component --- .../controls-side-bar/opencv-control.tsx | 117 ++---------------- .../standard-workspace/image-processing.tsx | 5 +- 2 files changed, 12 insertions(+), 110 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index ffa6a8504c84..46850ca512fa 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -36,7 +36,7 @@ import CVATTooltip from 'components/common/cvat-tooltip'; import ApproximationAccuracy, { thresholdFromAccuracy, } from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy'; -import { ImageProcessing, OpenCVTracker, TrackerModel } from 'utils/opencv-wrapper/opencv-interfaces'; +import { OpenCVTracker, TrackerModel } from 'utils/opencv-wrapper/opencv-interfaces'; import { addImageFilter as addImageFilterAction, removeImageFilter as removeImageFilterAction, switchToolsBlockerState } from 'actions/settings-actions'; import withVisibilityHandling from './handle-popover-visibility'; @@ -79,18 +79,12 @@ interface State { initializationProgress: number; activeLabelID: number; approxPolyAccuracy: number; - activeImageModifiers: ImageModifier[]; mode: 'interaction' | 'tracking'; trackedShapes: TrackedShape[]; activeTracker: OpenCVTracker | null; trackers: OpenCVTracker[]; } -interface ImageModifier { - modifier: ImageProcessing, - alias: string -} - const core = getCore(); const CustomPopover = withVisibilityHandling(Popover, 'opencv-control'); @@ -159,7 +153,6 @@ class OpenCVControlComponent extends React.PureComponent => { - const { activeImageModifiers } = this.state; - const { - frameData, states, curZOrder, canvasInstance, frame, - } = this.props; - - try { - if (activeImageModifiers.length !== 0 && activeImageModifiers[0].modifier.currentProcessedImage !== frame) { - this.enableCanvasForceUpdate(); - const imageData = this.getCanvasImageData(); - const newImageData = activeImageModifiers - .reduce((oldImageData, activeImageModifier) => activeImageModifier - .modifier.processImage(oldImageData, frame), imageData); - const imageBitmap = await createImageBitmap(newImageData); - const proxy = new Proxy(frameData, { - get: (_frameData, prop, receiver) => { - if (prop === 'data') { - return async () => ({ - renderWidth: imageData.width, - renderHeight: imageData.height, - imageData: imageBitmap, - }); - } - - return Reflect.get(_frameData, prop, receiver); - }, - }); - canvasInstance.setup(proxy, states, curZOrder); - } - } catch (error: any) { - notification.error({ - description: error.toString(), - message: 'OpenCV.js processing error occurred', - className: 'cvat-notification-notice-opencv-processing-error', - }); - } finally { - this.disableCanvasForceUpdate(); - } - }; - private applyTracking = (imageData: ImageData, shape: TrackedShape, objectState: any): Promise => new Promise((resolve, reject) => { setTimeout(() => { @@ -573,47 +524,9 @@ class OpenCVControlComponent extends React.PureComponent imageModifier.alias === alias)?.modifier || null; - } - - private disableImageModifier(alias: string):void { - const { removeImageFilter } = this.props; - const { activeImageModifiers } = this.state; - const index = activeImageModifiers.findIndex((imageModifier) => imageModifier.alias === alias); - if (index !== -1) { - activeImageModifiers.splice(index, 1); - this.setState({ - activeImageModifiers: [...activeImageModifiers], - }); - } - removeImageFilter(alias); - } - - private enableImageModifier(modifier: ImageProcessing, alias: string): void { - const { addImageFilter } = this.props; - this.setState((prev: State) => ({ - ...prev, - activeImageModifiers: [...prev.activeImageModifiers, { modifier, alias }], - }), () => { - this.runImageModifier(); - }); - addImageFilter({ modifier, alias }); - } - - private enableCanvasForceUpdate():void { - const { canvasInstance } = this.props; - canvasInstance.configure({ forceFrameUpdate: true }); - this.canvasForceUpdateWasEnabled = true; - } - - private disableCanvasForceUpdate():void { - if (this.canvasForceUpdateWasEnabled) { - const { canvasInstance } = this.props; - canvasInstance.configure({ forceFrameUpdate: false }); - this.canvasForceUpdateWasEnabled = false; - } + private filterActive(alias: string): boolean { + const { filters } = this.props; + return filters.some((filter) => filter.alias === alias); } private async initializeOpenCV():Promise { @@ -692,31 +605,19 @@ class OpenCVControlComponent extends React.PureComponent - - + + + + + ); } diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss new file mode 100644 index 000000000000..612608d62416 --- /dev/null +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss @@ -0,0 +1,15 @@ +// Copyright (C) 2023 CVAT.ai Corporation +// +// SPDX-License-Identifier: MIT + +@import 'base'; + +.cvat-image-setups-filters { + margin: $grid-unit-size * 3 0; +} + +.cvat-image-setups-gamma { + .ant-checkbox { + margin-left: $grid-unit-size * 0.5; + } +} \ No newline at end of file diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index 062005be6713..15c5c034ca74 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -412,19 +412,28 @@ export default (state = defaultState, action: AnyAction): SettingsState => { } case SettingsActionTypes.REMOVE_IMAGE_FILTER: { const { filterAlias } = action.payload; - const filters = [...state.imageProcessing.filters]; - const index = filters.findIndex((imageFilter) => imageFilter.alias === filterAlias); - if (index !== -1) { - filters.splice(index, 1); + if (filterAlias) { + const filters = [...state.imageProcessing.filters]; + const index = filters.findIndex((imageFilter) => imageFilter.alias === filterAlias); + if (index !== -1) { + filters.splice(index, 1); + } + filters.forEach((imageFilter) => { + imageFilter.modifier.currentProcessedImage = null; + }); + return { + ...state, + imageProcessing: { + ...state.imageProcessing, + filters, + }, + }; } - filters.forEach((imageFilter) => { - imageFilter.modifier.currentProcessedImage = null; - }); return { ...state, imageProcessing: { ...state.imageProcessing, - filters, + filters: [], }, }; } From 29619dee0a6d56c0ef336684bedf7216801ccabd Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 14:41:52 +0300 Subject: [PATCH 12/37] improved gamma correction class --- cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts b/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts index 27a9d4e6bf36..4e5bb657c9a4 100644 --- a/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts +++ b/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts @@ -12,10 +12,13 @@ export interface GammaFilterOptions { export default class GammaCorrection extends FabricFilter { constructor(options: GammaFilterOptions) { super(); + const { gamma } = options; if (!Array.isArray(gamma) || gamma.length !== 3) { - throw Error('icorrect gamma'); + throw Error(`Incorrect option for gamma filter, expected array: [R, G, B] got ${gamma}`); } + + // @ts-ignore: Some filters are not typed yet https://github.com/DefinitelyTyped/DefinitelyTyped/issues/62371 this.filter = new fabric.Image.filters.Gamma({ gamma, }); From c67ffd713d80d24ecd8369088dbe8995ac0f3c8d Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:07:01 +0300 Subject: [PATCH 13/37] improved image-processing component --- .../standard-workspace/image-processing.tsx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx index 415f266f27e8..62574e16a645 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -1,5 +1,5 @@ // Copyright (C) 2022 Intel Corporation -// Copyright (C) CVAT.ai corp +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -79,17 +79,16 @@ export default function ImageProcessingComponent(): JSX.Element | null { } catch (error: any) { notification.error({ description: error.toString(), - message: 'OpenCV.js processing error occurred', - className: 'cvat-notification-notice-opencv-processing-error', + message: 'Image processing error occurred', + className: 'cvat-notification-notice-image-processing-error', }); } finally { - // canvasInstance.configure({ forceFrameUpdate: false }); + canvasInstance.configure({ forceFrameUpdate: false }); } }, [canvasInstance]); useEffect(() => { if (canvasInstance) { - canvasInstance.configure({ forceFrameUpdate: true }); canvasInstance.html().addEventListener('canvas.setup', runImageModifier); } return () => { @@ -98,13 +97,8 @@ export default function ImageProcessingComponent(): JSX.Element | null { }, []); useEffect(() => { - if (frame.current !== null && filters.length !== 0) { - // runImageModifier(); - // canvasInstance.configure({ forceFrameUpdate: true }); - dispatch(changeFrameAsync(frame.current, false, 1, true)); - } else if (frame.current !== null) { - // filter disabled -> change frame and runImageModifier applies other filters by 'canvas.setup' - // canvasInstance.configure({ forceFrameUpdate: true }); + if (frame.current !== null) { + canvasInstance.configure({ forceFrameUpdate: true }); dispatch(changeFrameAsync(frame.current, false, 1, true)); } }, [filters]); From e26d971e38f3aaf9d415cf3c5c45c668fa2d25d8 Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:12:52 +0300 Subject: [PATCH 14/37] fixed headers --- cvat-ui/src/actions/settings-actions.ts | 1 + .../canvas/views/canvas2d/image-setups-content.tsx | 1 + .../annotation-page/canvas/views/canvas2d/image-setups.scss | 2 +- .../standard-workspace/controls-side-bar/opencv-control.tsx | 1 + .../annotation-page/standard-workspace/image-processing.tsx | 1 - cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts | 1 + cvat-ui/src/utils/opencv-wrapper/opencv-interfaces.ts | 1 + cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts | 3 --- 8 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cvat-ui/src/actions/settings-actions.ts b/cvat-ui/src/actions/settings-actions.ts index 650427bd5f49..4fcbda9da4da 100644 --- a/cvat-ui/src/actions/settings-actions.ts +++ b/cvat-ui/src/actions/settings-actions.ts @@ -1,4 +1,5 @@ // Copyright (C) 2020-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups-content.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups-content.tsx index eb1cfa7aec82..20c86e9a2919 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups-content.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups-content.tsx @@ -1,4 +1,5 @@ // Copyright (C) 2021-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss index 612608d62416..50e5b4d8cc5e 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss @@ -12,4 +12,4 @@ .ant-checkbox { margin-left: $grid-unit-size * 0.5; } -} \ No newline at end of file +} diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 59d6a83364af..86e8f5458ef2 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -1,4 +1,5 @@ // Copyright (C) 2021-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx index 62574e16a645..75d66345fb11 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -1,4 +1,3 @@ -// Copyright (C) 2022 Intel Corporation // Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts index a762d68f76bf..bdb8fc250b5d 100644 --- a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts +++ b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts @@ -1,4 +1,5 @@ // Copyright (C) 2021-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-interfaces.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-interfaces.ts index 913ffc6eb548..593cc6c7e33d 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-interfaces.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-interfaces.ts @@ -1,4 +1,5 @@ // Copyright (C) 2021-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT diff --git a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts index f5d5613b6bdf..36e0568aca74 100644 --- a/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts +++ b/cvat-ui/src/utils/opencv-wrapper/opencv-wrapper.ts @@ -8,7 +8,6 @@ import HistogramEqualizationImplementation, { HistogramEqualization } from './hi import TrackerMImplementation from './tracker-mil'; import IntelligentScissorsImplementation, { IntelligentScissors } from './intelligent-scissors'; import { OpenCVTracker } from './opencv-interfaces'; -import GammaCorrectionImplementation, { GammaCorrection } from '../fabric-wrapper/gamma-correciton'; const core = getCore(); const baseURL = core.config.backendAPI.slice(0, -7); @@ -33,7 +32,6 @@ export interface Contours { export interface ImgProc { hist: () => HistogramEqualization; - gamma: () => GammaCorrection; } export interface Tracking { @@ -222,7 +220,6 @@ export class OpenCVWrapper { this.checkInitialization(); return { hist: () => new HistogramEqualizationImplementation(this.cv), - gamma: () => new GammaCorrectionImplementation(this.cv), }; } From ee7c6bfc107ca0bbec91018d183d89dc09a5afd9 Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:14:41 +0300 Subject: [PATCH 15/37] reverted yarn.lock changes --- yarn.lock | 64 ++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/yarn.lock b/yarn.lock index ebf4f16a7302..7af6ed7b11b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,9 +1666,9 @@ integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== "@mapbox/node-pre-gyp@^1.0.0": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" - integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== + version "1.0.10" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c" + integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== dependencies: detect-libc "^2.0.0" https-proxy-agent "^5.0.0" @@ -3373,9 +3373,9 @@ caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503: integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA== canvas@^2.8.0: - version "2.11.2" - resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860" - integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw== + version "2.11.0" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.0.tgz#7f0c3e9ae94cf469269b5d3a7963a7f3a9936434" + integrity sha512-bdTjFexjKJEwtIo0oRx8eD4G2yWoUOXP9lj279jmQ2zMnTQhT8C3512OKz3s+ZOaQlLbE7TuVvRDYDB3Llyy5g== dependencies: "@mapbox/node-pre-gyp" "^1.0.0" nan "^2.17.0" @@ -4245,9 +4245,9 @@ detect-browser@^5.2.1: integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== detect-libc@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" - integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== detect-newline@^3.0.0: version "3.1.0" @@ -8215,10 +8215,12 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +minipass@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.0.0.tgz#7cebb0f9fa7d56f0c5b17853cbe28838a8dbbd3b" + integrity sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw== + dependencies: + yallist "^4.0.0" minizlib@^2.1.1: version "2.1.2" @@ -8317,9 +8319,9 @@ no-case@^3.0.4: tslib "^2.0.3" node-fetch@^2.6.7: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + version "2.6.8" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e" + integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg== dependencies: whatwg-url "^5.0.0" @@ -8448,12 +8450,7 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== - -nwsapi@^2.2.2: +nwsapi@^2.2.0, nwsapi@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.2.tgz#e5418863e7905df67d51ec95938d67bf801f0bb0" integrity sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw== @@ -10189,7 +10186,7 @@ readable-stream@^2.0.1, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.2, readable-stream@^3.0.6: +readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -10198,15 +10195,6 @@ readable-stream@^3.0.2, readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -12161,13 +12149,13 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== tar@^6.1.11: - version "6.1.15" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" - integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== + version "6.1.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b" + integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" - minipass "^5.0.0" + minipass "^4.0.0" minizlib "^2.1.1" mkdirp "^1.0.3" yallist "^4.0.0" @@ -13266,12 +13254,12 @@ write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" -ws@^8.11.0, ws@^8.2.3: +ws@^8.11.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== -ws@^8.4.2: +ws@^8.2.3, ws@^8.4.2: version "8.12.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.0.tgz#485074cc392689da78e1828a9ff23585e06cddd8" integrity sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig== From cdeb4d9f57a6114e6134b5ddb4bf4c90fca6dea1 Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:15:47 +0300 Subject: [PATCH 16/37] fixed eslint --- .../annotation-page/standard-workspace/image-processing.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx index 75d66345fb11..2d19195aa080 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -101,5 +101,6 @@ export default function ImageProcessingComponent(): JSX.Element | null { dispatch(changeFrameAsync(frame.current, false, 1, true)); } }, [filters]); - return null; + + return <>; } From 85e7be164c7437de203908a001ffe53d6b3cd17e Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:17:04 +0300 Subject: [PATCH 17/37] updated histogram equalization test --- .../cypress/e2e/actions_tasks2/case_101_opencv_basic_actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cypress/e2e/actions_tasks2/case_101_opencv_basic_actions.js b/tests/cypress/e2e/actions_tasks2/case_101_opencv_basic_actions.js index 7c3bcd1b24eb..1d61b65307b0 100644 --- a/tests/cypress/e2e/actions_tasks2/case_101_opencv_basic_actions.js +++ b/tests/cypress/e2e/actions_tasks2/case_101_opencv_basic_actions.js @@ -173,7 +173,7 @@ context('OpenCV. Intelligent scissors. Histogram Equalization. TrackerMIL.', () .should('have.class', 'ant-tabs-tab-active'); cy.get('.cvat-opencv-image-tool').click(); cy.get('.cvat-opencv-image-tool').should('have.class', 'cvat-opencv-image-tool-active'); - cy.get('.cvat-notification-notice-opencv-processing-error').should('not.exist'); + cy.get('.cvat-notification-notice-image-processing-error').should('not.exist'); cy.get('.cvat-opencv-image-tool').click(); cy.get('.cvat-opencv-image-tool').should('not.have.class', 'cvat-opencv-image-tool-active'); cy.get('.cvat-opencv-image-tool').trigger('mouseleave').trigger('mouseout'); From 5b7c959602dbff5be38bcfb31c1f42ba447cf574 Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:18:59 +0300 Subject: [PATCH 18/37] updated version & changelog --- CHANGELOG.md | 2 +- cvat-ui/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca760515b259..6e82069870e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## \[Unreleased\] ### Added -- TDB +- Gamma correcton filter () ### Changed - TDB diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 694660c6c3c5..bbe99ba2b175 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.55.5", + "version": "1.56.0", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { From 0d43f96766b068c408a4c41adda6f58a6d13f2d6 Mon Sep 17 00:00:00 2001 From: klakhov Date: Thu, 31 Aug 2023 15:30:40 +0300 Subject: [PATCH 19/37] removed unnecessary canvas configure --- .../annotation-page/standard-workspace/image-processing.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx index 2d19195aa080..6dee6987f573 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/image-processing.tsx @@ -54,7 +54,6 @@ export default function ImageProcessingComponent(): JSX.Element | null { imageFilter.modifier.currentProcessedImage !== currentFrame )); if (imageIsNotProcessed) { - canvasInstance.configure({ forceFrameUpdate: true }); const imageData = getCanvasImageData(); const newImageData = currentFilters .reduce((oldImageData, activeImageModifier) => activeImageModifier From 14931851e6c7a97b187e40fefa5ec26756e68f4e Mon Sep 17 00:00:00 2001 From: klakhov Date: Mon, 4 Sep 2023 13:29:27 +0300 Subject: [PATCH 20/37] removed rgb sliders --- .../canvas/views/canvas2d/image-filters.tsx | 68 ++++--------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx index a4516ec8f0cf..6683c4d5c8ad 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx @@ -6,7 +6,6 @@ import React, { useCallback, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Row, Col } from 'antd/lib/grid'; import { CombinedState } from 'reducers'; -import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox'; import Text from 'antd/lib/typography/Text'; import Slider from 'antd/lib/slider'; @@ -22,16 +21,25 @@ import './image-setups.scss'; export default function ImageFilters(): JSX.Element { const dispatch = useDispatch(); - const [gamma, setGamma] = useState([1.5, 1.5, 1.5]); + const [gamma, setGamma] = useState(1); const filters = useSelector((state: CombinedState) => state.settings.imageProcessing.filters); const gammaFilterActive = filterActive(filters, ImageFilterAlias.GAMMA_CORRECTION); const onChangeGamma = useCallback((newGamma) => { setGamma(newGamma); - if (gammaFilterActive) { + if (newGamma === 1) { + if (gammaFilterActive) { + dispatch(removeImageFilter(ImageFilterAlias.GAMMA_CORRECTION)); + } + } else if (gammaFilterActive) { dispatch(setupImageFilter( ImageFilterAlias.GAMMA_CORRECTION, - { gamma: newGamma }, + { gamma: [newGamma, newGamma, newGamma] }, )); + } else { + dispatch(addImageFilter({ + modifier: new GammaCorrection({ gamma: [newGamma, newGamma, newGamma] }), + alias: ImageFilterAlias.GAMMA_CORRECTION, + })); } }, [filters]); @@ -43,63 +51,17 @@ export default function ImageFilters(): JSX.Element { - Gamma - - - { - if (e.target.checked) { - dispatch(addImageFilter({ - modifier: new GammaCorrection({ gamma }), - alias: ImageFilterAlias.GAMMA_CORRECTION, - })); - } else { - dispatch(removeImageFilter(ImageFilterAlias.GAMMA_CORRECTION)); - } - }} - /> - - - - - Red: - - - onChangeGamma([value, gamma[1], gamma[2]])} - /> + Gamma: - - Green: - - - onChangeGamma([gamma[0], value, gamma[2]])} - /> - - - - - Blue: - onChangeGamma([gamma[0], gamma[1], value])} + onChange={(value) => onChangeGamma(value)} /> From 87199fe51981d443198a6b9c6eee931f83b7110e Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 10:34:34 +0300 Subject: [PATCH 21/37] reworked actions --- cvat-ui/src/actions/settings-actions.ts | 24 ++++---- .../canvas/views/canvas2d/image-filters.tsx | 35 +++++------ .../views/canvas2d/image-setups-content.tsx | 4 +- .../controls-side-bar/opencv-control.tsx | 22 +++---- cvat-ui/src/reducers/settings-reducer.ts | 59 +++++++++---------- cvat-ui/src/utils/image-processing.tsx | 8 ++- 6 files changed, 75 insertions(+), 77 deletions(-) diff --git a/cvat-ui/src/actions/settings-actions.ts b/cvat-ui/src/actions/settings-actions.ts index 4fcbda9da4da..5cbf1f187947 100644 --- a/cvat-ui/src/actions/settings-actions.ts +++ b/cvat-ui/src/actions/settings-actions.ts @@ -47,9 +47,9 @@ export enum SettingsActionTypes { SWITCH_TOOLS_BLOCKER_STATE = 'SWITCH_TOOLS_BLOCKER_STATE', SWITCH_SHOWING_DELETED_FRAMES = 'SWITCH_SHOWING_DELETED_FRAMES', SWITCH_SHOWING_TAGS_ON_FRAME = 'SWITCH_SHOWING_TAGS_ON_FRAME', - ADD_IMAGE_FILTER = 'ADD_IMAGE_FILTER', - REMOVE_IMAGE_FILTER = 'REMOVE_IMAGE_FILTER', - SETUP_IMAGE_FILTER = 'SETUP_IMAGE_FILTER', + ENABLE_IMAGE_FILTER = 'ENABLE_IMAGE_FILTER', + DISABLE_IMAGE_FILTER = 'DISABLE_IMAGE_FILTER', + RESET_IMAGE_FILTERS = 'RESET_IMAGE_FILTERS', } export function changeShapesOpacity(opacity: number): AnyAction { @@ -386,30 +386,28 @@ export function switchShowingTagsOnFrame(showTagsOnFrame: boolean): AnyAction { }; } -export function addImageFilter(filter: ImageFilter): AnyAction { +export function enableImageFilter(filter: ImageFilter, options: object | null = null): AnyAction { return { - type: SettingsActionTypes.ADD_IMAGE_FILTER, + type: SettingsActionTypes.ENABLE_IMAGE_FILTER, payload: { filter, + options, }, }; } -export function removeImageFilter(filterAlias: ImageFilterAlias | null): AnyAction { +export function disableImageFilter(filterAlias: ImageFilterAlias): AnyAction { return { - type: SettingsActionTypes.REMOVE_IMAGE_FILTER, + type: SettingsActionTypes.DISABLE_IMAGE_FILTER, payload: { filterAlias, }, }; } -export function setupImageFilter(filterAlias: ImageFilterAlias, options: object): AnyAction { +export function resetImageFilters(): AnyAction { return { - type: SettingsActionTypes.SETUP_IMAGE_FILTER, - payload: { - filterAlias, - options, - }, + type: SettingsActionTypes.RESET_IMAGE_FILTERS, + payload: {}, }; } diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx index 6683c4d5c8ad..c9be992809ee 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-filters.tsx @@ -10,12 +10,11 @@ import Text from 'antd/lib/typography/Text'; import Slider from 'antd/lib/slider'; import { - addImageFilter, - removeImageFilter, - setupImageFilter, + enableImageFilter, + disableImageFilter, } from 'actions/settings-actions'; import GammaCorrection from 'utils/fabric-wrapper/gamma-correciton'; -import { ImageFilterAlias, filterActive } from 'utils/image-processing'; +import { ImageFilterAlias, hasFilter } from 'utils/image-processing'; import './image-setups.scss'; @@ -23,23 +22,23 @@ export default function ImageFilters(): JSX.Element { const dispatch = useDispatch(); const [gamma, setGamma] = useState(1); const filters = useSelector((state: CombinedState) => state.settings.imageProcessing.filters); - const gammaFilterActive = filterActive(filters, ImageFilterAlias.GAMMA_CORRECTION); + const gammaFilter = hasFilter(filters, ImageFilterAlias.GAMMA_CORRECTION); const onChangeGamma = useCallback((newGamma) => { setGamma(newGamma); if (newGamma === 1) { - if (gammaFilterActive) { - dispatch(removeImageFilter(ImageFilterAlias.GAMMA_CORRECTION)); + if (gammaFilter) { + dispatch(disableImageFilter(ImageFilterAlias.GAMMA_CORRECTION)); } - } else if (gammaFilterActive) { - dispatch(setupImageFilter( - ImageFilterAlias.GAMMA_CORRECTION, - { gamma: [newGamma, newGamma, newGamma] }, - )); } else { - dispatch(addImageFilter({ - modifier: new GammaCorrection({ gamma: [newGamma, newGamma, newGamma] }), - alias: ImageFilterAlias.GAMMA_CORRECTION, - })); + const convertedGamma = [newGamma, newGamma, newGamma]; + if (gammaFilter) { + dispatch(enableImageFilter(gammaFilter, { gamma: convertedGamma })); + } else { + dispatch(enableImageFilter({ + modifier: new GammaCorrection({ gamma: convertedGamma }), + alias: ImageFilterAlias.GAMMA_CORRECTION, + })); + } } }, [filters]); @@ -51,10 +50,8 @@ export default function ImageFilters(): JSX.Element { - Gamma: + Gamma - - Reset image settings diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx index 86e8f5458ef2..e39ab7c694c9 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/opencv-control.tsx @@ -38,8 +38,8 @@ import ApproximationAccuracy, { thresholdFromAccuracy, } from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy'; import { OpenCVTracker, TrackerModel } from 'utils/opencv-wrapper/opencv-interfaces'; -import { addImageFilter as addImageFilterAction, removeImageFilter as removeImageFilterAction, switchToolsBlockerState } from 'actions/settings-actions'; -import { ImageFilter, ImageFilterAlias, filterActive } from 'utils/image-processing'; +import { enableImageFilter as enableImageFilterAction, disableImageFilter as disableImageFilterAction, switchToolsBlockerState } from 'actions/settings-actions'; +import { ImageFilter, ImageFilterAlias, hasFilter } from 'utils/image-processing'; import withVisibilityHandling from './handle-popover-visibility'; interface Props { @@ -65,8 +65,8 @@ interface DispatchToProps { changeFrame(toFrame: number, fillBuffer?: boolean, frameStep?: number, forceUpdate?: boolean):void; onSwitchToolsBlockerState(toolsBlockerState: ToolsBlockerState):void; switchNavigationBlocked(navigationBlocked: boolean): void; - addImageFilter(filter: ImageFilter): void; - removeImageFilter(filterAlias: string): void; + enableImageFilter(filter: ImageFilter): void; + disableImageFilter(filterAlias: string): void; } interface TrackedShape { @@ -133,8 +133,8 @@ const mapDispatchToProps = { changeFrame: changeFrameAsync, onSwitchToolsBlockerState: switchToolsBlockerState, switchNavigationBlocked: switchNavigationBlockedAction, - addImageFilter: addImageFilterAction, - removeImageFilter: removeImageFilterAction, + enableImageFilter: enableImageFilterAction, + disableImageFilter: disableImageFilterAction, }; class OpenCVControlComponent extends React.PureComponent { @@ -594,26 +594,26 @@ class OpenCVControlComponent extends React.PureComponent diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss index 50e5b4d8cc5e..c6229a4f072f 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/image-setups.scss @@ -5,11 +5,5 @@ @import 'base'; .cvat-image-setups-filters { - margin: $grid-unit-size * 3 0; -} - -.cvat-image-setups-gamma { - .ant-checkbox { - margin-left: $grid-unit-size * 0.5; - } + margin-bottom: $grid-unit-size * 3; } From 3410674e9816ae74b936c967d864b5f4d9da7fa1 Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 14:14:34 +0300 Subject: [PATCH 29/37] added `no-extraneous-dependencies` eslint rule settings for global dependencies --- cvat-canvas/.eslintrc.js | 4 ++++ cvat-canvas3d/.eslintrc.js | 3 +++ cvat-core/.eslintrc.js | 3 +++ cvat-data/.eslintrc.js | 3 +++ cvat-ui/.eslintrc.js | 2 ++ 5 files changed, 15 insertions(+) diff --git a/cvat-canvas/.eslintrc.js b/cvat-canvas/.eslintrc.js index ab68a0338f42..f8e469242ad3 100644 --- a/cvat-canvas/.eslintrc.js +++ b/cvat-canvas/.eslintrc.js @@ -1,4 +1,5 @@ // Copyright (C) 2019-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -13,4 +14,7 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, }, + rules: { + 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], + }, }; diff --git a/cvat-canvas3d/.eslintrc.js b/cvat-canvas3d/.eslintrc.js index 144b2c3032a8..893d53d29da6 100644 --- a/cvat-canvas3d/.eslintrc.js +++ b/cvat-canvas3d/.eslintrc.js @@ -13,4 +13,7 @@ module.exports = { 'node_modules/**', 'dist/**', ], + rules: { + 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], + }, }; diff --git a/cvat-core/.eslintrc.js b/cvat-core/.eslintrc.js index 9dede90d961e..06333af1d4fc 100644 --- a/cvat-core/.eslintrc.js +++ b/cvat-core/.eslintrc.js @@ -16,4 +16,7 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, }, + rules: { + 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], + }, }; diff --git a/cvat-data/.eslintrc.js b/cvat-data/.eslintrc.js index 3aa39c7d09a9..c35817cfe39a 100644 --- a/cvat-data/.eslintrc.js +++ b/cvat-data/.eslintrc.js @@ -15,4 +15,7 @@ module.exports = { tsconfigRootDir: __dirname, }, plugins: ['jest'], + rules: { + 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], + }, }; diff --git a/cvat-ui/.eslintrc.js b/cvat-ui/.eslintrc.js index 22c20d3c9c43..f9d6fa934e01 100644 --- a/cvat-ui/.eslintrc.js +++ b/cvat-ui/.eslintrc.js @@ -1,4 +1,5 @@ // Copyright (C) 2020-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -29,5 +30,6 @@ module.exports = { 'react/jsx-indent-props': ['warn', 4], 'react/jsx-props-no-spreading': 0, 'jsx-quotes': ['error', 'prefer-single'], + 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], }, }; From 43e763119696a2bf3aab8c1ea1d5d23296dbc562 Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 14:28:59 +0300 Subject: [PATCH 30/37] added error handling --- .../canvas/views/canvas2d/canvas-wrapper.tsx | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index 3034d900d68f..d95e3d8bdb70 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -9,6 +9,7 @@ import Slider from 'antd/lib/slider'; import Spin from 'antd/lib/spin'; import Dropdown from 'antd/lib/dropdown'; import { PlusCircleOutlined, UpOutlined } from '@ant-design/icons'; +import notification from 'antd/lib/notification'; import GlobalHotKeys, { KeyMap } from 'utils/mousetrap-react'; import { @@ -930,28 +931,37 @@ class CanvasWrapperComponent extends React.PureComponent { const imageIsNotProcessed = imageFilters.some((imageFilter: ImageFilter) => ( imageFilter.modifier.currentProcessedImage !== frame )); + if (imageIsNotProcessed) { - const { renderWidth, renderHeight, imageData: imageBitmap } = originalImage; - - const offscreen = new OffscreenCanvas(renderWidth, renderHeight); - const ctx = offscreen.getContext('2d') as OffscreenCanvasRenderingContext2D; - ctx.drawImage(imageBitmap, 0, 0); - const imageData = ctx.getImageData(0, 0, renderWidth, renderHeight); - - const newImageData = imageFilters - .reduce((oldImageData, activeImageModifier) => activeImageModifier - .modifier.processImage(oldImageData, frame), imageData); - const newImageBitmap = await createImageBitmap(newImageData); - return { - renderWidth, - renderHeight, - imageData: newImageBitmap, - }; + try { + const { renderWidth, renderHeight, imageData: imageBitmap } = originalImage; + + const offscreen = new OffscreenCanvas(renderWidth, renderHeight); + const ctx = offscreen.getContext('2d') as OffscreenCanvasRenderingContext2D; + ctx.drawImage(imageBitmap, 0, 0); + const imageData = ctx.getImageData(0, 0, renderWidth, renderHeight); + + const newImageData = imageFilters + .reduce((oldImageData, activeImageModifier) => activeImageModifier + .modifier.processImage(oldImageData, frame), imageData); + const newImageBitmap = await createImageBitmap(newImageData); + return { + renderWidth, + renderHeight, + imageData: newImageBitmap, + }; + } catch (error: any) { + notification.error({ + description: error.toString(), + message: 'Image processing error occurred', + className: 'cvat-notification-notice-image-processing-error', + }); + } } + return originalImage; }; } - return Reflect.get(_frameData, prop, receiver); }, }); From 5b2b7611e2c1332fc45b942e095a1483e69014ba Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 21:24:51 +0300 Subject: [PATCH 31/37] added copy data for fabric filters, removed cache for histogram --- .../canvas/views/canvas2d/canvas-wrapper.tsx | 6 +- .../utils/fabric-wrapper/fabric-wrapper.ts | 5 +- .../opencv-wrapper/histogram-equalization.ts | 124 ++++++------------ 3 files changed, 45 insertions(+), 90 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index d95e3d8bdb70..70fe857708b8 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -536,9 +536,7 @@ class CanvasWrapperComponent extends React.PureComponent { }); } - if ( - prevProps.imageFilters !== imageFilters - ) { + if (prevProps.imageFilters !== imageFilters) { canvasInstance.configure({ forceFrameUpdate: true }); } @@ -970,7 +968,7 @@ class CanvasWrapperComponent extends React.PureComponent { frameData.deleted ? [] : filteredAnnotations, curZLayer, ); - canvasInstance.configure({ forceFrameUpdate: false }); + // canvasInstance.configure({ forceFrameUpdate: false }); } } diff --git a/cvat-ui/src/utils/fabric-wrapper/fabric-wrapper.ts b/cvat-ui/src/utils/fabric-wrapper/fabric-wrapper.ts index c03bef421aba..f710a97ce701 100644 --- a/cvat-ui/src/utils/fabric-wrapper/fabric-wrapper.ts +++ b/cvat-ui/src/utils/fabric-wrapper/fabric-wrapper.ts @@ -7,10 +7,13 @@ import { BaseImageFilter } from 'utils/image-processing'; export default class FabricFilter extends BaseImageFilter { public processImage(src: ImageData, frameNumber: number): ImageData { if (this.filter) { + const dataCopy = new Uint8ClampedArray(src.data); + const result = new ImageData(dataCopy, src.width, src.height); this.filter.applyTo2d({ - imageData: src, + imageData: result, }); this.currentProcessedImage = frameNumber; + return result; } return src; } diff --git a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts index a7b071191906..365e1a97c56e 100644 --- a/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts +++ b/cvat-ui/src/utils/opencv-wrapper/histogram-equalization.ts @@ -9,101 +9,55 @@ export interface HistogramEqualization extends ImageProcessing{ processImage: (src: ImageData, frameNumber: number) => ImageData; } -interface HashedImage{ - frameNumber: number, - frameData: ImageData, - timestamp: number, -} - export default class HistogramEqualizationImplementation extends BaseImageFilter { - private readonly bufferSize: number = 20; private cv:any; - private histHash: HashedImage[]; constructor(cv:any) { super(); this.cv = cv; - this.histHash = []; } public processImage(src:ImageData, frameNumber: number) : ImageData { - const hashedFrame = this.hashedFrame(frameNumber); - if (!hashedFrame) { - const { cv } = this; - let matImage = null; - const RGBImage = new cv.Mat(); - const YUVImage = new cv.Mat(); - const RGBDist = new cv.Mat(); - const YUVDist = new cv.Mat(); - const RGBADist = new cv.Mat(); - let channels = new cv.MatVector(); - const equalizedY = new cv.Mat(); - try { - this.currentProcessedImage = frameNumber; - matImage = cv.matFromImageData(src); - cv.cvtColor(matImage, RGBImage, cv.COLOR_RGBA2RGB, 0); - cv.cvtColor(RGBImage, YUVImage, cv.COLOR_RGB2YUV, 0); - cv.split(YUVImage, channels); - const [Y, U, V] = [channels.get(0), channels.get(1), channels.get(2)]; - channels.delete(); - channels = null; - cv.equalizeHist(Y, equalizedY); - Y.delete(); - channels = new cv.MatVector(); - channels.push_back(equalizedY); equalizedY.delete(); - channels.push_back(U); U.delete(); - channels.push_back(V); V.delete(); - cv.merge(channels, YUVDist); - cv.cvtColor(YUVDist, RGBDist, cv.COLOR_YUV2RGB, 0); - cv.cvtColor(RGBDist, RGBADist, cv.COLOR_RGB2RGBA, 0); - const arr = new Uint8ClampedArray(RGBADist.data, RGBADist.cols, RGBADist.rows); - const imgData = new ImageData(arr, src.width, src.height); - this.hashFrame(imgData, frameNumber); - return imgData; - } catch (e) { - throw new Error(e.toString()); - } finally { - if (matImage) matImage.delete(); - if (channels) channels.delete(); - RGBImage.delete(); - YUVImage.delete(); - RGBDist.delete(); - YUVDist.delete(); - RGBADist.delete(); - } - } else { + const { cv } = this; + let matImage = null; + const RGBImage = new cv.Mat(); + const YUVImage = new cv.Mat(); + const RGBDist = new cv.Mat(); + const YUVDist = new cv.Mat(); + const RGBADist = new cv.Mat(); + let channels = new cv.MatVector(); + const equalizedY = new cv.Mat(); + try { this.currentProcessedImage = frameNumber; - return hashedFrame; - } - } - - private hashedFrame(frameNumber: number): ImageData | null { - const hashed = this.histHash.find((_hashed) => _hashed.frameNumber === frameNumber); - if (hashed) { - hashed.timestamp = Date.now(); - } - return hashed?.frameData || null; - } - - private hashFrame(frameData: ImageData, frameNumber: number): void { - if (this.histHash.length >= this.bufferSize) { - const leastRecentlyUsed = this.histHash[0]; - const currentTimestamp = Date.now(); - let diff = currentTimestamp - leastRecentlyUsed.timestamp; - let leastIndex = 0; - for (let i = 1; i < this.histHash.length; i++) { - const currentDiff = currentTimestamp - this.histHash[i].timestamp; - if (currentDiff > diff) { - diff = currentDiff; - leastIndex = i; - } - } - this.histHash.splice(leastIndex, 1); + matImage = cv.matFromImageData(src); + cv.cvtColor(matImage, RGBImage, cv.COLOR_RGBA2RGB, 0); + cv.cvtColor(RGBImage, YUVImage, cv.COLOR_RGB2YUV, 0); + cv.split(YUVImage, channels); + const [Y, U, V] = [channels.get(0), channels.get(1), channels.get(2)]; + channels.delete(); + channels = null; + cv.equalizeHist(Y, equalizedY); + Y.delete(); + channels = new cv.MatVector(); + channels.push_back(equalizedY); equalizedY.delete(); + channels.push_back(U); U.delete(); + channels.push_back(V); V.delete(); + cv.merge(channels, YUVDist); + cv.cvtColor(YUVDist, RGBDist, cv.COLOR_YUV2RGB, 0); + cv.cvtColor(RGBDist, RGBADist, cv.COLOR_RGB2RGBA, 0); + const arr = new Uint8ClampedArray(RGBADist.data, RGBADist.cols, RGBADist.rows); + const imgData = new ImageData(arr, src.width, src.height); + return imgData; + } catch (e) { + throw new Error(e.toString()); + } finally { + if (matImage) matImage.delete(); + if (channels) channels.delete(); + RGBImage.delete(); + YUVImage.delete(); + RGBDist.delete(); + YUVDist.delete(); + RGBADist.delete(); } - this.histHash.push({ - frameData, - frameNumber, - timestamp: Date.now(), - }); } } From aa31a1ee3351954957dcd88de0dcfdca4c420ec8 Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 21:31:51 +0300 Subject: [PATCH 32/37] added debounce --- .../canvas/views/canvas2d/gamma-filter.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx index 9a5463e675ab..acd2a1fe6505 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Row, Col } from 'antd/lib/grid'; import { CombinedState } from 'reducers'; @@ -17,13 +17,15 @@ import GammaCorrection from 'utils/fabric-wrapper/gamma-correciton'; import { ImageFilterAlias, hasFilter } from 'utils/image-processing'; import './image-setups.scss'; +import debounce from 'lodash/debounce'; export default function GammaFilter(): JSX.Element { const dispatch = useDispatch(); const [gamma, setGamma] = useState(1); const filters = useSelector((state: CombinedState) => state.settings.imageFilters); const gammaFilter = hasFilter(filters, ImageFilterAlias.GAMMA_CORRECTION); - const onChangeGamma = useCallback((newGamma) => { + + const onChangeGamma = debounce((newGamma) => { setGamma(newGamma); if (newGamma === 1) { if (gammaFilter) { @@ -40,7 +42,7 @@ export default function GammaFilter(): JSX.Element { })); } } - }, [filters]); + }, 250); useEffect(() => { if (filters.length === 0) { @@ -62,7 +64,7 @@ export default function GammaFilter(): JSX.Element { max={2.6} value={gamma} step={0.01} - onChange={(value) => onChangeGamma(value)} + onChange={onChangeGamma} /> From aefd222941645a0574d30b7f0fe6bf6308d9bd9e Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 21:58:05 +0300 Subject: [PATCH 33/37] fixed eslint --- .eslintrc.js | 9 +++++++++ cvat-canvas/.eslintrc.js | 4 ---- cvat-canvas3d/.eslintrc.js | 3 --- cvat-core/.eslintrc.js | 3 --- cvat-data/.eslintrc.js | 3 --- cvat-ui/.eslintrc.js | 1 - 6 files changed, 9 insertions(+), 14 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 83d8765a2448..be079cc1f72a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,6 +52,15 @@ module.exports = { 'security/detect-object-injection': 0, // the rule is relevant for user input data on the node.js environment 'import/order': ['error', {'groups': ['builtin', 'external', 'internal']}], 'import/prefer-default-export': 0, // works incorrect with interfaces + 'import/no-extraneous-dependencies': [ + 'error', + { + packageDir: [ + './cvat-ui/', './cvat-canvas/', './cvat-core/', + './cvat-canvas3d/', './cvat-data/', './tests/', '.', + ] + }, + ], '@typescript-eslint/ban-ts-comment': 0, '@typescript-eslint/no-explicit-any': 0, diff --git a/cvat-canvas/.eslintrc.js b/cvat-canvas/.eslintrc.js index f8e469242ad3..ab68a0338f42 100644 --- a/cvat-canvas/.eslintrc.js +++ b/cvat-canvas/.eslintrc.js @@ -1,5 +1,4 @@ // Copyright (C) 2019-2022 Intel Corporation -// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT @@ -14,7 +13,4 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, }, - rules: { - 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], - }, }; diff --git a/cvat-canvas3d/.eslintrc.js b/cvat-canvas3d/.eslintrc.js index 893d53d29da6..144b2c3032a8 100644 --- a/cvat-canvas3d/.eslintrc.js +++ b/cvat-canvas3d/.eslintrc.js @@ -13,7 +13,4 @@ module.exports = { 'node_modules/**', 'dist/**', ], - rules: { - 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], - }, }; diff --git a/cvat-core/.eslintrc.js b/cvat-core/.eslintrc.js index 06333af1d4fc..9dede90d961e 100644 --- a/cvat-core/.eslintrc.js +++ b/cvat-core/.eslintrc.js @@ -16,7 +16,4 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, }, - rules: { - 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], - }, }; diff --git a/cvat-data/.eslintrc.js b/cvat-data/.eslintrc.js index c35817cfe39a..3aa39c7d09a9 100644 --- a/cvat-data/.eslintrc.js +++ b/cvat-data/.eslintrc.js @@ -15,7 +15,4 @@ module.exports = { tsconfigRootDir: __dirname, }, plugins: ['jest'], - rules: { - 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], - }, }; diff --git a/cvat-ui/.eslintrc.js b/cvat-ui/.eslintrc.js index f9d6fa934e01..47959819b5a2 100644 --- a/cvat-ui/.eslintrc.js +++ b/cvat-ui/.eslintrc.js @@ -30,6 +30,5 @@ module.exports = { 'react/jsx-indent-props': ['warn', 4], 'react/jsx-props-no-spreading': 0, 'jsx-quotes': ['error', 'prefer-single'], - 'import/no-extraneous-dependencies': ['error', { packageDir: ['.', '../'] }], }, }; From a2c8820fb7fcba59bf820cc0ad14607810d04c3e Mon Sep 17 00:00:00 2001 From: klakhov Date: Tue, 5 Sep 2023 22:29:25 +0300 Subject: [PATCH 34/37] upodated eslint + removed comment --- .eslintrc.js | 9 --------- cvat-canvas/.eslintrc.js | 11 +++++++++++ cvat-ui/.eslintrc.js | 7 +++++++ .../canvas/views/canvas2d/canvas-wrapper.tsx | 2 +- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index be079cc1f72a..83d8765a2448 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,15 +52,6 @@ module.exports = { 'security/detect-object-injection': 0, // the rule is relevant for user input data on the node.js environment 'import/order': ['error', {'groups': ['builtin', 'external', 'internal']}], 'import/prefer-default-export': 0, // works incorrect with interfaces - 'import/no-extraneous-dependencies': [ - 'error', - { - packageDir: [ - './cvat-ui/', './cvat-canvas/', './cvat-core/', - './cvat-canvas3d/', './cvat-data/', './tests/', '.', - ] - }, - ], '@typescript-eslint/ban-ts-comment': 0, '@typescript-eslint/no-explicit-any': 0, diff --git a/cvat-canvas/.eslintrc.js b/cvat-canvas/.eslintrc.js index ab68a0338f42..23b211a9a3fd 100644 --- a/cvat-canvas/.eslintrc.js +++ b/cvat-canvas/.eslintrc.js @@ -1,7 +1,10 @@ // Copyright (C) 2019-2022 Intel Corporation +// Copyright (C) 2023 CVAT.ai Corporation // // SPDX-License-Identifier: MIT +const { join } = require('path'); + module.exports = { ignorePatterns: [ '.eslintrc.js', @@ -13,4 +16,12 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, }, + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + { + packageDir: [__dirname, join(__dirname, '../')] + }, + ], + } }; diff --git a/cvat-ui/.eslintrc.js b/cvat-ui/.eslintrc.js index 47959819b5a2..0f89242e3d23 100644 --- a/cvat-ui/.eslintrc.js +++ b/cvat-ui/.eslintrc.js @@ -4,6 +4,7 @@ // SPDX-License-Identifier: MIT const globalConfig = require('../.eslintrc.js'); +const { join } = require('path'); module.exports = { parserOptions: { @@ -30,5 +31,11 @@ module.exports = { 'react/jsx-indent-props': ['warn', 4], 'react/jsx-props-no-spreading': 0, 'jsx-quotes': ['error', 'prefer-single'], + 'import/no-extraneous-dependencies': [ + 'error', + { + packageDir: [__dirname, join(__dirname, '../')] + }, + ], }, }; diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index 70fe857708b8..1dbeec8d6f34 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -968,7 +968,7 @@ class CanvasWrapperComponent extends React.PureComponent { frameData.deleted ? [] : filteredAnnotations, curZLayer, ); - // canvasInstance.configure({ forceFrameUpdate: false }); + canvasInstance.configure({ forceFrameUpdate: false }); } } From 32422e0c847e90f7100c35be248f8fd34d9352f5 Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 6 Sep 2023 10:44:12 +0300 Subject: [PATCH 35/37] reset filters on open job --- cvat-ui/src/reducers/settings-reducer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index 8a16f988edf3..8cdc4de60be2 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -477,6 +477,7 @@ export default (state = defaultState, action: AnyAction): SettingsState => { } : {}), }, + imageFilters: [], }; } case AnnotationActionTypes.INTERACT_WITH_CANVAS: { From 28e61c222a2090844f4cdf07fa9c3b1341cf0658 Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 6 Sep 2023 11:40:16 +0300 Subject: [PATCH 36/37] debounced canvas update on filter changes --- .../canvas/views/canvas2d/canvas-wrapper.tsx | 10 ++++++++-- .../canvas/views/canvas2d/gamma-filter.tsx | 7 +++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index 1dbeec8d6f34..3b1f67ec3c3e 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -10,6 +10,7 @@ import Spin from 'antd/lib/spin'; import Dropdown from 'antd/lib/dropdown'; import { PlusCircleOutlined, UpOutlined } from '@ant-design/icons'; import notification from 'antd/lib/notification'; +import debounce from 'lodash/debounce'; import GlobalHotKeys, { KeyMap } from 'utils/mousetrap-react'; import { @@ -363,6 +364,8 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { type Props = StateToProps & DispatchToProps; class CanvasWrapperComponent extends React.PureComponent { + private debouncedUpdate = debounce(this.updateCanvas.bind(this), 750, { leading: true }); + public componentDidMount(): void { const { automaticBordering, @@ -544,10 +547,13 @@ class CanvasWrapperComponent extends React.PureComponent { prevProps.annotations !== annotations || prevProps.statesSources !== statesSources || prevProps.frameData !== frameData || - prevProps.curZLayer !== curZLayer || - prevProps.imageFilters !== imageFilters + prevProps.curZLayer !== curZLayer ) { this.updateCanvas(); + } else if (prevProps.imageFilters !== imageFilters) { + // In case of frequent image filters changes, we apply debounced canvas update + // that makes UI smoother + this.debouncedUpdate(); } if (prevProps.showBitmap !== showBitmap) { diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx index acd2a1fe6505..cdd2d887f2ac 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/gamma-filter.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Row, Col } from 'antd/lib/grid'; import { CombinedState } from 'reducers'; @@ -17,7 +17,6 @@ import GammaCorrection from 'utils/fabric-wrapper/gamma-correciton'; import { ImageFilterAlias, hasFilter } from 'utils/image-processing'; import './image-setups.scss'; -import debounce from 'lodash/debounce'; export default function GammaFilter(): JSX.Element { const dispatch = useDispatch(); @@ -25,7 +24,7 @@ export default function GammaFilter(): JSX.Element { const filters = useSelector((state: CombinedState) => state.settings.imageFilters); const gammaFilter = hasFilter(filters, ImageFilterAlias.GAMMA_CORRECTION); - const onChangeGamma = debounce((newGamma) => { + const onChangeGamma = useCallback((newGamma: number): void => { setGamma(newGamma); if (newGamma === 1) { if (gammaFilter) { @@ -42,7 +41,7 @@ export default function GammaFilter(): JSX.Element { })); } } - }, 250); + }, [gammaFilter]); useEffect(() => { if (filters.length === 0) { From 68ae2f4184dbb063acf9120f56a01ea343c6f9d0 Mon Sep 17 00:00:00 2001 From: klakhov Date: Wed, 6 Sep 2023 11:57:58 +0300 Subject: [PATCH 37/37] updated debounce time --- .../annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index 3b1f67ec3c3e..9ecd1efd0a68 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -364,7 +364,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { type Props = StateToProps & DispatchToProps; class CanvasWrapperComponent extends React.PureComponent { - private debouncedUpdate = debounce(this.updateCanvas.bind(this), 750, { leading: true }); + private debouncedUpdate = debounce(this.updateCanvas.bind(this), 250, { leading: true }); public componentDidMount(): void { const {