Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed fit for images with different resolution #6081

Merged
merged 9 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Tracking of multiple objects (30 and more) with TransT tracker
(<https://github.com/opencv/cvat/pull/6073>)
- The issue azure.core.exceptions.ResourceExistsError: The specified blob already exists (<https://github.com/opencv/cvat/pull/6082>)
- The issue azure.core.exceptions.ResourceExistsError: The specified blob already exists (<https://github.com/opencv/cvat/pull/6082>)
- Image scaling when moving between images with different resolution (<https://github.com/opencv/cvat/pull/6081>)

### Security
- TDB
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "2.16.3",
"version": "2.16.4",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
Expand Down
39 changes: 35 additions & 4 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface Configuration {
shapeOpacity?: number;
controlPointsSize?: number;
outlinedBorders?: string | false;
resetZoom?: boolean;
}

export interface BrushTool {
Expand Down Expand Up @@ -160,6 +161,7 @@ export enum UpdateReasons {
IMAGE_ZOOMED = 'image_zoomed',
IMAGE_FITTED = 'image_fitted',
IMAGE_MOVED = 'image_moved',
IMAGE_ROTATED = 'image_rotated',
GRID_UPDATED = 'grid_updated',

ISSUE_REGIONS_UPDATED = 'issue_regions_updated',
Expand Down Expand Up @@ -312,11 +314,12 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
imageIsDeleted: boolean;
focusData: FocusData;
gridSize: Size;
left: number;
objects: any[];
issueRegions: Record<number, { hidden: boolean; points: number[] }>;
scale: number;
top: number;
left: number;
fittedScale: number;
zLayer: number | null;
drawData: DrawData;
editData: MasksEditData;
Expand Down Expand Up @@ -355,6 +358,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
selectedShapeOpacity: 0.5,
shapeOpacity: 0.2,
outlinedBorders: false,
resetZoom: true,
textFontSize: consts.DEFAULT_SHAPE_TEXT_SIZE,
controlPointsSize: consts.BASE_POINT_SIZE,
textPosition: consts.DEFAULT_SHAPE_TEXT_POSITION,
Expand All @@ -378,11 +382,12 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
height: 100,
width: 100,
},
left: 0,
objects: [],
issueRegions: {},
scale: 1,
top: 0,
left: 0,
fittedScale: 0,
zLayer: null,
selected: null,
mode: Mode.IDLE,
Expand Down Expand Up @@ -506,6 +511,12 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
return;
}

const relativeScaling = this.data.scale / this.data.fittedScale;
const prevImageLeft = this.data.left;
const prevImageTop = this.data.top;
const prevImageWidth = this.data.imageSize.width;
const prevImageHeight = this.data.imageSize.height;

this.data.imageSize = {
height: frameData.height as number,
width: frameData.width as number,
Expand All @@ -516,6 +527,20 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
if (this.data.imageIsDeleted) {
this.data.angle = 0;
}

this.fit();

// restore correct image position after switching to a new frame
// if corresponding option is disabled
// prevImageHeight and prevImageWidth are initialized by 0 by default
if (prevImageHeight !== 0 && prevImageWidth !== 0 && !this.data.configuration.resetZoom) {
const leftOffset = Math.round((this.data.imageSize.width - prevImageWidth) / 2);
const topOffset = Math.round((this.data.imageSize.height - prevImageHeight) / 2);
this.data.left = prevImageLeft - leftOffset;
this.data.top = prevImageTop - topOffset;
this.data.scale *= relativeScaling;
}

this.notify(UpdateReasons.IMAGE_CHANGED);
this.data.zLayer = zLayer;
this.data.objects = objectStates;
Expand Down Expand Up @@ -562,7 +587,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
public rotate(rotationAngle: number): void {
if (this.data.angle !== rotationAngle && !this.data.imageIsDeleted) {
this.data.angle = (360 + Math.floor(rotationAngle / 90) * 90) % 360;
this.fit();
this.notify(UpdateReasons.IMAGE_ROTATED);
}
}

Expand Down Expand Up @@ -592,10 +617,13 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
}

this.data.scale = Math.min(Math.max(this.data.scale, FrameZoom.MIN), FrameZoom.MAX);

this.data.top = this.data.canvasSize.height / 2 - this.data.imageSize.height / 2;
this.data.left = this.data.canvasSize.width / 2 - this.data.imageSize.width / 2;

// scale is changed during zooming or translating
// so, remember fitted scale to compute fit-relative scaling
this.data.fittedScale = this.data.scale;

this.notify(UpdateReasons.IMAGE_FITTED);
}

Expand Down Expand Up @@ -813,6 +841,9 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
if (typeof configuration.forceFrameUpdate === 'boolean') {
this.data.configuration.forceFrameUpdate = configuration.forceFrameUpdate;
}
if (typeof configuration.resetZoom === 'boolean') {
this.data.configuration.resetZoom = configuration.resetZoom;
}
if (typeof configuration.selectedShapeOpacity === 'number') {
this.data.configuration.selectedShapeOpacity = configuration.selectedShapeOpacity;
}
Expand Down
16 changes: 8 additions & 8 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,12 @@ export class CanvasViewImpl implements CanvasView, Listener {
// Setup event handlers
this.canvas.addEventListener('dblclick', (e: MouseEvent): void => {
this.controller.fit();
this.canvas.dispatchEvent(
new CustomEvent('canvas.fit', {
bubbles: false,
cancelable: true,
}),
);
e.preventDefault();
});

Expand Down Expand Up @@ -1460,14 +1466,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
} else if ([UpdateReasons.IMAGE_ZOOMED, UpdateReasons.IMAGE_FITTED].includes(reason)) {
this.moveCanvas();
this.transformCanvas();
if (reason === UpdateReasons.IMAGE_FITTED) {
this.canvas.dispatchEvent(
new CustomEvent('canvas.fit', {
bubbles: false,
cancelable: true,
}),
);
}
} else if (reason === UpdateReasons.IMAGE_ROTATED) {
this.transformCanvas();
} else if (reason === UpdateReasons.IMAGE_MOVED) {
this.moveCanvas();
} else if (reason === UpdateReasons.OBJECTS_UPDATED) {
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.50.8",
"version": "1.50.9",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
colorBy,
outlined,
outlineColor,
resetZoom,
} = this.props;
const { canvasInstance } = this.props as { canvasInstance: Canvas };

Expand All @@ -383,6 +384,7 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
textFontSize,
textPosition,
textContent,
resetZoom,
});

this.initialSetup();
Expand Down Expand Up @@ -439,7 +441,8 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
prevProps.textContent !== textContent ||
prevProps.colorBy !== colorBy ||
prevProps.outlineColor !== outlineColor ||
prevProps.outlined !== outlined
prevProps.outlined !== outlined ||
prevProps.resetZoom !== resetZoom
) {
canvasInstance.configure({
undefinedAttrValue: config.UNDEFINED_ATTRIBUTE_VALUE,
Expand All @@ -456,6 +459,7 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
controlPointsSize,
textPosition,
textContent,
resetZoom,
});
}

Expand Down Expand Up @@ -502,22 +506,16 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
this.updateCanvas();
}

if (prevProps.frame !== frameData.number && resetZoom && workspace !== Workspace.ATTRIBUTE_ANNOTATION) {
canvasInstance.html().addEventListener(
'canvas.setup',
() => {
canvasInstance.fit();
},
{ once: true },
);
}

if (prevProps.showBitmap !== showBitmap) {
canvasInstance.bitmap(showBitmap);
}

if (prevProps.frameAngle !== frameAngle) {
canvasInstance.rotate(frameAngle);
if (prevProps.frameData === frameData) {
// explicitly rotated, not a new frame
canvasInstance.fit();
}
}

if (prevProps.workspace !== workspace) {
Expand Down Expand Up @@ -859,6 +857,8 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
if (activatedState && activatedState.objectType !== ObjectType.TAG) {
canvasInstance.activate(activatedStateID, activatedAttributeID);
}
} else if (workspace === Workspace.ATTRIBUTE_ANNOTATION) {
canvasInstance.fit();
bsekachev marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -905,13 +905,11 @@ class CanvasWrapperComponent extends React.PureComponent<Props> {
`brightness(${brightnessLevel}) contrast(${contrastLevel}) saturate(${saturationLevel})`,
});

// Events
canvasInstance.fitCanvas();
canvasInstance.html().addEventListener(
'canvas.setup',
() => {
const { activatedStateID, activatedAttributeID } = this.props;
canvasInstance.fitCanvas();
canvasInstance.fit();
canvasInstance.activate(activatedStateID, activatedAttributeID);
},
{ once: true },
Expand Down
Loading