Added smooth image option (#3933)

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

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add Cityscapes format (<https://github.com/openvinotoolkit/cvat/pull/3758>) - Add Cityscapes format (<https://github.com/openvinotoolkit/cvat/pull/3758>)
- Add Open Images V6 format (<https://github.com/openvinotoolkit/cvat/pull/3679>) - Add Open Images V6 format (<https://github.com/openvinotoolkit/cvat/pull/3679>)
- Rotated bounding boxes (<https://github.com/openvinotoolkit/cvat/pull/3832>) - Rotated bounding boxes (<https://github.com/openvinotoolkit/cvat/pull/3832>)
- Player option: Smooth image when zoom-in, enabled by default (<https://github.com/openvinotoolkit/cvat/pull/3933>)
### Changed ### Changed
- TDB - TDB

@ -1,12 +1,12 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.9.1", "version": "2.10.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.9.1", "version": "2.10.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"svg.draggable.js": "2.2.2", "svg.draggable.js": "2.2.2",

@ -1,6 +1,6 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.9.1", "version": "2.10.0",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library", "description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts", "main": "src/canvas.ts",
"scripts": { "scripts": {

@ -229,6 +229,17 @@ polyline.cvat_canvas_shape_splitting {
} }
} }
.cvat_canvas_pixelized {
image-rendering: optimizeSpeed; /* Legal fallback */
image-rendering: -moz-crisp-edges; /* Firefox */
image-rendering: -o-crisp-edges; /* Opera */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: optimize-contrast; /* CSS3 Proposed */
image-rendering: crisp-edges; /* CSS4 Proposed */
image-rendering: pixelated; /* CSS4 Proposed */
-ms-interpolation-mode: nearest-neighbor; /* IE8+ */
}
#cvat_canvas_wrapper { #cvat_canvas_wrapper {
width: calc(100% - 10px); width: calc(100% - 10px);
height: calc(100% - 10px); height: calc(100% - 10px);
@ -273,6 +284,8 @@ polyline.cvat_canvas_shape_splitting {
} }
#cvat_canvas_bitmap { #cvat_canvas_bitmap {
@extend .cvat_canvas_pixelized;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
z-index: 4; z-index: 4;

@ -52,6 +52,7 @@ export enum CuboidDrawingMethod {
} }
export interface Configuration { export interface Configuration {
smoothImage?: boolean;
autoborders?: boolean; autoborders?: boolean;
displayAllText?: boolean; displayAllText?: boolean;
undefinedAttrValue?: string; undefinedAttrValue?: string;
@ -652,23 +653,21 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
if (typeof configuration.autoborders === 'boolean') { if (typeof configuration.autoborders === 'boolean') {
this.data.configuration.autoborders = configuration.autoborders; this.data.configuration.autoborders = configuration.autoborders;
} }
if (typeof configuration.smoothImage === 'boolean') {
this.data.configuration.smoothImage = configuration.smoothImage;
}
if (typeof configuration.undefinedAttrValue === 'string') { if (typeof configuration.undefinedAttrValue === 'string') {
this.data.configuration.undefinedAttrValue = configuration.undefinedAttrValue; this.data.configuration.undefinedAttrValue = configuration.undefinedAttrValue;
} }
if (typeof configuration.forceDisableEditing === 'boolean') { if (typeof configuration.forceDisableEditing === 'boolean') {
this.data.configuration.forceDisableEditing = configuration.forceDisableEditing; this.data.configuration.forceDisableEditing = configuration.forceDisableEditing;
} }
if (typeof configuration.intelligentPolygonCrop === 'boolean') { if (typeof configuration.intelligentPolygonCrop === 'boolean') {
this.data.configuration.intelligentPolygonCrop = configuration.intelligentPolygonCrop; this.data.configuration.intelligentPolygonCrop = configuration.intelligentPolygonCrop;
} }
if (typeof configuration.forceFrameUpdate === 'boolean') { if (typeof configuration.forceFrameUpdate === 'boolean') {
this.data.configuration.forceFrameUpdate = configuration.forceFrameUpdate; this.data.configuration.forceFrameUpdate = configuration.forceFrameUpdate;
} }
if (typeof configuration.creationOpacity === 'number') { if (typeof configuration.creationOpacity === 'number') {
this.data.configuration.creationOpacity = configuration.creationOpacity; this.data.configuration.creationOpacity = configuration.creationOpacity;
} }

@ -1169,15 +1169,16 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (reason === UpdateReasons.CONFIG_UPDATED) { if (reason === UpdateReasons.CONFIG_UPDATED) {
const { activeElement } = this; const { activeElement } = this;
this.deactivate(); this.deactivate();
const { configuration } = model;
if (model.configuration.displayAllText && !this.configuration.displayAllText) { if (configuration.displayAllText && !this.configuration.displayAllText) {
for (const i in this.drawnStates) { for (const i in this.drawnStates) {
if (!(i in this.svgTexts)) { if (!(i in this.svgTexts)) {
this.svgTexts[i] = this.addText(this.drawnStates[i]); this.svgTexts[i] = this.addText(this.drawnStates[i]);
this.updateTextPosition(this.svgTexts[i], this.svgShapes[i]); this.updateTextPosition(this.svgTexts[i], this.svgShapes[i]);
} }
} }
} else if (model.configuration.displayAllText === false && this.configuration.displayAllText) { } else if (configuration.displayAllText === false && this.configuration.displayAllText) {
for (const i in this.drawnStates) { for (const i in this.drawnStates) {
if (i in this.svgTexts && Number.parseInt(i, 10) !== activeElement.clientID) { if (i in this.svgTexts && Number.parseInt(i, 10) !== activeElement.clientID) {
this.svgTexts[i].remove(); this.svgTexts[i].remove();
@ -1186,7 +1187,15 @@ export class CanvasViewImpl implements CanvasView, Listener {
} }
} }
this.configuration = model.configuration; if ('smoothImage' in configuration) {
if (configuration.smoothImage) {
this.background.classList.remove('cvat_canvas_pixelized');
} else {
this.background.classList.add('cvat_canvas_pixelized');
}
}
this.configuration = configuration;
this.activate(activeElement); this.activate(activeElement);
this.editHandler.configurate(this.configuration); this.editHandler.configurate(this.configuration);
this.drawHandler.configurate(this.configuration); this.drawHandler.configurate(this.configuration);

@ -1,12 +1,12 @@
{ {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.26.0", "version": "1.27.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.26.0", "version": "1.27.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.6.3", "@ant-design/icons": "^4.6.3",

@ -1,6 +1,6 @@
{ {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.26.0", "version": "1.27.0",
"description": "CVAT single-page application", "description": "CVAT single-page application",
"main": "src/index.tsx", "main": "src/index.tsx",
"scripts": { "scripts": {

@ -22,6 +22,7 @@ export enum SettingsActionTypes {
CHANGE_FRAME_STEP = 'CHANGE_FRAME_STEP', CHANGE_FRAME_STEP = 'CHANGE_FRAME_STEP',
CHANGE_FRAME_SPEED = 'CHANGE_FRAME_SPEED', CHANGE_FRAME_SPEED = 'CHANGE_FRAME_SPEED',
SWITCH_RESET_ZOOM = 'SWITCH_RESET_ZOOM', SWITCH_RESET_ZOOM = 'SWITCH_RESET_ZOOM',
SWITCH_SMOOTH_IMAGE = 'SWITCH_SMOOTH_IMAGE',
CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL', CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL',
CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL', CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL',
CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL', CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL',
@ -166,6 +167,15 @@ export function switchResetZoom(resetZoom: boolean): AnyAction {
}; };
} }
export function switchSmoothImage(enabled: boolean): AnyAction {
return {
type: SettingsActionTypes.SWITCH_SMOOTH_IMAGE,
payload: {
smoothImage: enabled,
},
};
}
export function changeBrightnessLevel(level: number): AnyAction { export function changeBrightnessLevel(level: number): AnyAction {
return { return {
type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL, type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL,

@ -27,7 +27,7 @@ const MAX_DISTANCE_TO_OPEN_SHAPE = 50;
interface Props { interface Props {
sidebarCollapsed: boolean; sidebarCollapsed: boolean;
canvasInstance: Canvas | Canvas3d; canvasInstance: Canvas | Canvas3d | null;
jobInstance: any; jobInstance: any;
activatedStateID: number | null; activatedStateID: number | null;
activatedAttributeID: number | null; activatedAttributeID: number | null;
@ -57,6 +57,7 @@ interface Props {
contrastLevel: number; contrastLevel: number;
saturationLevel: number; saturationLevel: number;
resetZoom: boolean; resetZoom: boolean;
smoothImage: boolean;
aamZoomMargin: number; aamZoomMargin: number;
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
showAllInterpolationTracks: boolean; showAllInterpolationTracks: boolean;
@ -105,6 +106,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
workspace, workspace,
showProjections, showProjections,
selectedOpacity, selectedOpacity,
smoothImage,
} = this.props; } = this.props;
const { canvasInstance } = this.props as { canvasInstance: Canvas }; const { canvasInstance } = this.props as { canvasInstance: Canvas };
@ -114,6 +116,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
wrapper.appendChild(canvasInstance.html()); wrapper.appendChild(canvasInstance.html());
canvasInstance.configure({ canvasInstance.configure({
smoothImage,
autoborders: automaticBordering, autoborders: automaticBordering,
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE, undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
displayAllText: showObjectsTextAlways, displayAllText: showObjectsTextAlways,
@ -144,6 +147,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
activatedStateID, activatedStateID,
curZLayer, curZLayer,
resetZoom, resetZoom,
smoothImage,
grid, grid,
gridSize, gridSize,
gridOpacity, gridOpacity,
@ -167,7 +171,8 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
prevProps.automaticBordering !== automaticBordering || prevProps.automaticBordering !== automaticBordering ||
prevProps.showProjections !== showProjections || prevProps.showProjections !== showProjections ||
prevProps.intelligentPolygonCrop !== intelligentPolygonCrop || prevProps.intelligentPolygonCrop !== intelligentPolygonCrop ||
prevProps.selectedOpacity !== selectedOpacity prevProps.selectedOpacity !== selectedOpacity ||
prevProps.smoothImage !== smoothImage
) { ) {
canvasInstance.configure({ canvasInstance.configure({
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE, undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
@ -176,6 +181,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
showProjections, showProjections,
intelligentPolygonCrop, intelligentPolygonCrop,
creationOpacity: selectedOpacity, creationOpacity: selectedOpacity,
smoothImage,
}); });
} }
@ -418,7 +424,9 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
private fitCanvas = (): void => { private fitCanvas = (): void => {
const { canvasInstance } = this.props; const { canvasInstance } = this.props;
canvasInstance.fitCanvas(); if (canvasInstance) {
canvasInstance.fitCanvas();
}
}; };
private onCanvasMouseDown = (e: MouseEvent): void => { private onCanvasMouseDown = (e: MouseEvent): void => {
@ -677,7 +685,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
curZLayer, annotations, frameData, canvasInstance, curZLayer, annotations, frameData, canvasInstance,
} = this.props; } = this.props;
if (frameData !== null) { if (frameData !== null && canvasInstance) {
canvasInstance.setup( canvasInstance.setup(
frameData, frameData,
annotations.filter((e) => e.objectType !== ObjectType.TAG), annotations.filter((e) => e.objectType !== ObjectType.TAG),

@ -24,12 +24,14 @@ interface Props {
frameSpeed: FrameSpeed; frameSpeed: FrameSpeed;
resetZoom: boolean; resetZoom: boolean;
rotateAll: boolean; rotateAll: boolean;
smoothImage: boolean;
canvasBackgroundColor: string; canvasBackgroundColor: string;
onChangeFrameStep(step: number): void; onChangeFrameStep(step: number): void;
onChangeFrameSpeed(speed: FrameSpeed): void; onChangeFrameSpeed(speed: FrameSpeed): void;
onSwitchResetZoom(enabled: boolean): void; onSwitchResetZoom(enabled: boolean): void;
onSwitchRotateAll(rotateAll: boolean): void; onSwitchRotateAll(rotateAll: boolean): void;
onChangeCanvasBackgroundColor(color: string): void; onChangeCanvasBackgroundColor(color: string): void;
onSwitchSmoothImage(enabled: boolean): void;
} }
export default function PlayerSettingsComponent(props: Props): JSX.Element { export default function PlayerSettingsComponent(props: Props): JSX.Element {
@ -38,11 +40,13 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
frameSpeed, frameSpeed,
resetZoom, resetZoom,
rotateAll, rotateAll,
smoothImage,
canvasBackgroundColor, canvasBackgroundColor,
onChangeFrameStep, onChangeFrameStep,
onChangeFrameSpeed, onChangeFrameSpeed,
onSwitchResetZoom, onSwitchResetZoom,
onSwitchRotateAll, onSwitchRotateAll,
onSwitchSmoothImage,
onChangeCanvasBackgroundColor, onChangeCanvasBackgroundColor,
} = props; } = props;
@ -176,6 +180,26 @@ export default function PlayerSettingsComponent(props: Props): JSX.Element {
</Row> </Row>
</Col> </Col>
</Row> </Row>
<Row justify='start'>
<Col span={7}>
<Row className='cvat-player-settings-smooth-image'>
<Col span={24} className='cvat-player-settings-smooth-image-checkbox'>
<Checkbox
className='cvat-text-color'
checked={smoothImage}
onChange={(event: CheckboxChangeEvent): void => {
onSwitchSmoothImage(event.target.checked);
}}
>
Smooth image
</Checkbox>
</Col>
<Col span={24}>
<Text type='secondary'> Smooth image when zoom-in it </Text>
</Col>
</Row>
</Col>
</Row>
</div> </div>
); );
} }

@ -53,7 +53,7 @@ import { Canvas3d } from 'cvat-canvas3d-wrapper';
interface StateToProps { interface StateToProps {
sidebarCollapsed: boolean; sidebarCollapsed: boolean;
canvasInstance: Canvas | Canvas3d; canvasInstance: Canvas | Canvas3d | null;
jobInstance: any; jobInstance: any;
activatedStateID: number | null; activatedStateID: number | null;
activatedAttributeID: number | null; activatedAttributeID: number | null;
@ -80,6 +80,7 @@ interface StateToProps {
contrastLevel: number; contrastLevel: number;
saturationLevel: number; saturationLevel: number;
resetZoom: boolean; resetZoom: boolean;
smoothImage: boolean;
aamZoomMargin: number; aamZoomMargin: number;
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
showAllInterpolationTracks: boolean; showAllInterpolationTracks: boolean;
@ -155,6 +156,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
contrastLevel, contrastLevel,
saturationLevel, saturationLevel,
resetZoom, resetZoom,
smoothImage,
}, },
workspace: { workspace: {
aamZoomMargin, aamZoomMargin,
@ -201,6 +203,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
contrastLevel: contrastLevel / 100, contrastLevel: contrastLevel / 100,
saturationLevel: saturationLevel / 100, saturationLevel: saturationLevel / 100,
resetZoom, resetZoom,
smoothImage,
aamZoomMargin, aamZoomMargin,
showObjectsTextAlways, showObjectsTextAlways,
showAllInterpolationTracks, showAllInterpolationTracks,

@ -11,6 +11,7 @@ import {
switchResetZoom, switchResetZoom,
switchRotateAll, switchRotateAll,
changeCanvasBackgroundColor, changeCanvasBackgroundColor,
switchSmoothImage,
} from 'actions/settings-actions'; } from 'actions/settings-actions';
import { CombinedState, FrameSpeed } from 'reducers/interfaces'; import { CombinedState, FrameSpeed } from 'reducers/interfaces';
@ -19,6 +20,7 @@ interface StateToProps {
frameSpeed: FrameSpeed; frameSpeed: FrameSpeed;
resetZoom: boolean; resetZoom: boolean;
rotateAll: boolean; rotateAll: boolean;
smoothImage: boolean;
canvasBackgroundColor: string; canvasBackgroundColor: string;
} }
@ -28,6 +30,7 @@ interface DispatchToProps {
onSwitchResetZoom(enabled: boolean): void; onSwitchResetZoom(enabled: boolean): void;
onSwitchRotateAll(rotateAll: boolean): void; onSwitchRotateAll(rotateAll: boolean): void;
onChangeCanvasBackgroundColor(color: string): void; onChangeCanvasBackgroundColor(color: string): void;
onSwitchSmoothImage(enabled: boolean): void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
@ -55,6 +58,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onChangeCanvasBackgroundColor(color: string): void { onChangeCanvasBackgroundColor(color: string): void {
dispatch(changeCanvasBackgroundColor(color)); dispatch(changeCanvasBackgroundColor(color));
}, },
onSwitchSmoothImage(enabled: boolean): void {
dispatch(switchSmoothImage(enabled));
},
}; };
} }

@ -617,6 +617,7 @@ export interface PlayerSettingsState {
frameSpeed: FrameSpeed; frameSpeed: FrameSpeed;
resetZoom: boolean; resetZoom: boolean;
rotateAll: boolean; rotateAll: boolean;
smoothImage: boolean;
grid: boolean; grid: boolean;
gridSize: number; gridSize: number;
gridColor: GridColor; gridColor: GridColor;

@ -43,6 +43,7 @@ const defaultState: SettingsState = {
frameSpeed: FrameSpeed.Usual, frameSpeed: FrameSpeed.Usual,
resetZoom: false, resetZoom: false,
rotateAll: false, rotateAll: false,
smoothImage: true,
grid: false, grid: false,
gridSize: 100, gridSize: 100,
gridColor: GridColor.White, gridColor: GridColor.White,
@ -183,6 +184,15 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
}, },
}; };
} }
case SettingsActionTypes.SWITCH_SMOOTH_IMAGE: {
return {
...state,
player: {
...state.player,
smoothImage: action.payload.smoothImage,
},
};
}
case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: { case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: {
return { return {
...state, ...state,

Loading…
Cancel
Save