Skip to content

Commit

Permalink
React UI: cuboid interpolation and cuboid drawing from rectangles (#1560
Browse files Browse the repository at this point in the history
)

* Added backend cuboid interpolation and cuboid drawing from rectangles
* Added CHANELOG.md
* Fixed cuboid front edges stroke width
* PR fixes
  • Loading branch information
ActiveChooN authored May 21, 2020
1 parent 42fb305 commit 5816494
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- cvat-ui: added cookie policy drawer for login page (<https://github.com/opencv/cvat/pull/1511>)
- Added `datumaro_project` export format (https://github.com/opencv/cvat/pull/1352)
- Ability to configure user agreements for the user registration form (https://github.com/opencv/cvat/pull/1464)
- Added cuboid interpolation and cuboid drawing from rectangles (<https://github.com/opencv/cvat/pull/1560>)

### Changed
- Downloaded file name in annotations export became more informative (https://github.com/opencv/cvat/pull/1352)
Expand Down
6 changes: 6 additions & 0 deletions cvat-canvas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ Canvas itself handles:
EXTREME_POINTS = 'By 4 points'
}

enum CuboidDrawingMethod {
CLASSIC = 'From rectangle',
CORNER_POINTS = 'By 4 points',
}

enum Mode {
IDLE = 'idle',
DRAG = 'drag',
Expand All @@ -59,6 +64,7 @@ Canvas itself handles:
enabled: boolean;
shapeType?: string;
rectDrawingMethod?: RectDrawingMethod;
cuboidDrawingMethod?: CuboidDrawingMethod;
numberOfPoints?: number;
initialState?: any;
crosshair?: boolean;
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "1.0.0",
"version": "1.1.0",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
Expand Down
2 changes: 2 additions & 0 deletions cvat-canvas/src/typescript/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
CanvasModel,
CanvasModelImpl,
RectDrawingMethod,
CuboidDrawingMethod,
Configuration,
} from './canvasModel';

Expand Down Expand Up @@ -159,5 +160,6 @@ export {
CanvasVersion,
Configuration,
RectDrawingMethod,
CuboidDrawingMethod,
Mode as CanvasMode,
};
6 changes: 6 additions & 0 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export enum RectDrawingMethod {
EXTREME_POINTS = 'By 4 points'
}

export enum CuboidDrawingMethod {
CLASSIC = 'From rectangle',
CORNER_POINTS = 'By 4 points',
}

export interface Configuration {
autoborders?: boolean;
displayAllText?: boolean;
Expand All @@ -57,6 +62,7 @@ export interface DrawData {
enabled: boolean;
shapeType?: string;
rectDrawingMethod?: RectDrawingMethod;
cuboidDrawingMethod?: CuboidDrawingMethod;
numberOfPoints?: number;
initialState?: any;
crosshair?: boolean;
Expand Down
4 changes: 4 additions & 0 deletions cvat-canvas/src/typescript/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const SIZE_THRESHOLD = 3;
const POINTS_STROKE_WIDTH = 1.5;
const POINTS_SELECTED_STROKE_WIDTH = 4;
const MIN_EDGE_LENGTH = 3;
const CUBOID_ACTIVE_EDGE_STROKE_WIDTH = 2.5;
const CUBOID_UNACTIVE_EDGE_STROKE_WIDTH = 1.75;
const UNDEFINED_ATTRIBUTE_VALUE = '__undefined__';

export default {
Expand All @@ -23,5 +25,7 @@ export default {
POINTS_STROKE_WIDTH,
POINTS_SELECTED_STROKE_WIDTH,
MIN_EDGE_LENGTH,
CUBOID_ACTIVE_EDGE_STROKE_WIDTH,
CUBOID_UNACTIVE_EDGE_STROKE_WIDTH,
UNDEFINED_ATTRIBUTE_VALUE,
};
36 changes: 33 additions & 3 deletions cvat-canvas/src/typescript/drawHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Geometry,
RectDrawingMethod,
Configuration,
CuboidDrawingMethod,
} from './canvasModel';

import { cuboidFrom4Points } from './cuboid';
Expand Down Expand Up @@ -227,7 +228,8 @@ export class DrawHandlerImpl implements DrawHandler {
// Or when no drawn points, but we call cancel() drawing
// We check if it is activated with remember function
if (this.drawInstance.remember('_paintHandler')) {
if (this.drawData.shapeType !== 'rectangle') {
if (this.drawData.shapeType !== 'rectangle'
&& this.drawData.cuboidDrawingMethod !== CuboidDrawingMethod.CLASSIC) {
// Check for unsaved drawn shapes
this.drawInstance.draw('done');
}
Expand Down Expand Up @@ -451,14 +453,37 @@ export class DrawHandlerImpl implements DrawHandler {
this.drawPolyshape();
}

private drawCuboid(): void {
private drawCuboidBy4Points(): void {
this.drawInstance = (this.canvas as any).polyline()
.addClass('cvat_canvas_shape_drawing').attr({
'stroke-width': consts.BASE_STROKE_WIDTH / this.geometry.scale,
});
this.drawPolyshape();
}

private drawCuboid(): void {
this.drawInstance = this.canvas.rect();
this.drawInstance.on('drawstop', (e: Event): void => {
const bbox = (e.target as SVGRectElement).getBBox();
const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox);
const { shapeType } = this.drawData;
this.release();

if (this.canceled) return;
if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) {
const d = { x: (xbr - xtl) * 0.1, y: (ybr - ytl)*0.1}
this.onDrawDone({
shapeType,
points: cuboidFrom4Points([xtl, ybr, xbr, ybr, xbr, ytl, xbr + d.x, ytl - d.y]),
}, Date.now() - this.startTimestamp);
}
}).on('drawupdate', (): void => {
this.shapeSizeElement.update(this.drawInstance);
}).addClass('cvat_canvas_shape_drawing').attr({
'stroke-width': consts.BASE_STROKE_WIDTH / this.geometry.scale,
});
}

private pastePolyshape(): void {
this.drawInstance.on('done', (e: CustomEvent): void => {
const targetPoints = this.drawInstance
Expand Down Expand Up @@ -679,7 +704,12 @@ export class DrawHandlerImpl implements DrawHandler {
} else if (this.drawData.shapeType === 'points') {
this.drawPoints();
} else if (this.drawData.shapeType === 'cuboid') {
this.drawCuboid();
if (this.drawData.cuboidDrawingMethod === CuboidDrawingMethod.CORNER_POINTS) {
this.drawCuboidBy4Points();
} else {
this.drawCuboid();
this.shapeSizeElement = displayShapeSize(this.canvas, this.text);
}
}
this.setupDrawEvents();
}
Expand Down
11 changes: 7 additions & 4 deletions cvat-canvas/src/typescript/svg.patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ function getTopDown(edgeIndex: EdgeIndex): number[] {
this.bot = this.polygon(this.cuboidModel.bot.points);
this.top = this.polygon(this.cuboidModel.top.points);
this.right = this.polygon(this.cuboidModel.right.points);
this.dorsal = this.polygon(this.cuboidModel.dorsal.points);
this.left = this.polygon(this.cuboidModel.left.points);
this.dorsal = this.polygon(this.cuboidModel.dorsal.points);
this.face = this.polygon(this.cuboidModel.front.points);
},

Expand Down Expand Up @@ -631,6 +631,7 @@ function getTopDown(edgeIndex: EdgeIndex): number[] {

this.cuboidModel.dr.points = [topPoint, botPoint];
this.updateViewAndVM();
this.fire(new CustomEvent('resizing', event));
}).on('dragend', (event: CustomEvent) => {
this.fire(new CustomEvent('resizedone', event));
});
Expand Down Expand Up @@ -658,6 +659,7 @@ function getTopDown(edgeIndex: EdgeIndex): number[] {

this.cuboidModel.dl.points = [topPoint, botPoint];
this.updateViewAndVM(true);
this.fire(new CustomEvent('resizing', event));
}).on('dragend', (event: CustomEvent) => {
this.fire(new CustomEvent('resizedone', event));
});;
Expand Down Expand Up @@ -856,16 +858,17 @@ function getTopDown(edgeIndex: EdgeIndex): number[] {
const edges = [this.frontLeftEdge, this.frontRightEdge, this.frontTopEdge, this.frontBotEdge]
const width = this.attr('stroke-width');
edges.forEach((edge: SVG.Element) => {
edge.attr('stroke-width', width * (this.strokeOffset || 1.75));
edge.attr('stroke-width', width * (this.strokeOffset || consts.CUBOID_UNACTIVE_EDGE_STROKE_WIDTH));
});
this.on('mouseover', () => {
edges.forEach((edge: SVG.Element) => {
this.strokeOffset = 2.5;
this.strokeOffset = this.node.classList.contains('cvat_canvas_shape_activated')
? consts.CUBOID_ACTIVE_EDGE_STROKE_WIDTH : consts.CUBOID_UNACTIVE_EDGE_STROKE_WIDTH;
edge.attr('stroke-width', width * this.strokeOffset);
})
}).on('mouseout', () => {
edges.forEach((edge: SVG.Element) => {
this.strokeOffset = 1.75;
this.strokeOffset = consts.CUBOID_UNACTIVE_EDGE_STROKE_WIDTH;
edge.attr('stroke-width', width * this.strokeOffset);
})
});
Expand Down
2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "2.0.0",
"version": "2.0.1",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "babel.config.js",
"scripts": {
Expand Down
21 changes: 18 additions & 3 deletions cvat-core/src/annotations-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -1402,7 +1402,7 @@
}
}

class CuboidShape extends PolyShape {
class CuboidShape extends Shape {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = ObjectShape.CUBOID;
Expand Down Expand Up @@ -1967,7 +1967,7 @@
}
}

class CuboidTrack extends PolyTrack {
class CuboidTrack extends Track {
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = ObjectShape.CUBOID;
Expand All @@ -1976,14 +1976,29 @@
checkNumberOfPoints(this.shapeType, shape.points);
}
}

interpolatePosition(leftPosition, rightPosition, offset) {

const positionOffset = leftPosition.points.map((point, index) => (
rightPosition.points[index] - point
))

return {
points: leftPosition.points.map((point ,index) => (
point + positionOffset[index] * offset
)),
occluded: leftPosition.occluded,
outside: leftPosition.outside,
zOrder: leftPosition.zOrder,
};
}
}

RectangleTrack.distance = RectangleShape.distance;
PolygonTrack.distance = PolygonShape.distance;
PolylineTrack.distance = PolylineShape.distance;
PointsTrack.distance = PointsShape.distance;
CuboidTrack.distance = CuboidShape.distance;
CuboidTrack.interpolatePosition = RectangleTrack.interpolatePosition;

module.exports = {
RectangleShape,
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.1.3",
"version": "1.1.4",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Radio, { RadioChangeEvent } from 'antd/lib/radio';
import Tooltip from 'antd/lib/tooltip';
import Text from 'antd/lib/typography/Text';

import { RectDrawingMethod } from 'cvat-canvas-wrapper';
import { RectDrawingMethod, CuboidDrawingMethod } from 'cvat-canvas-wrapper';
import { ShapeType } from 'reducers/interfaces';
import { clamp } from 'utils/math';
import DEXTRPlugin from './dextr-plugin';
Expand All @@ -21,12 +21,14 @@ interface Props {
labels: any[];
minimumPoints: number;
rectDrawingMethod?: RectDrawingMethod;
cuboidDrawingMethod?: CuboidDrawingMethod;
numberOfPoints?: number;
selectedLabeID: number;
repeatShapeShortcut: string;
onChangeLabel(value: string): void;
onChangePoints(value: number | undefined): void;
onChangeRectDrawingMethod(event: RadioChangeEvent): void;
onChangeCuboidDrawingMethod(event: RadioChangeEvent): void;
onDrawTrack(): void;
onDrawShape(): void;
}
Expand All @@ -39,16 +41,18 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
selectedLabeID,
numberOfPoints,
rectDrawingMethod,
cuboidDrawingMethod,
repeatShapeShortcut,
onDrawTrack,
onDrawShape,
onChangeLabel,
onChangePoints,
onChangeRectDrawingMethod,
onChangeCuboidDrawingMethod,
} = props;

const trackDisabled = shapeType === ShapeType.POLYGON || shapeType === ShapeType.POLYLINE
|| shapeType === ShapeType.CUBOID || (shapeType === ShapeType.POINTS && numberOfPoints !== 1);
|| (shapeType === ShapeType.POINTS && numberOfPoints !== 1);

return (
<div className='cvat-draw-shape-popover-content'>
Expand Down Expand Up @@ -117,6 +121,39 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
</>
)
}
{
shapeType === ShapeType.CUBOID && (
<>
<Row>
<Col>
<Text className='cvat-text-color'> Drawing method </Text>
</Col>
</Row>
<Row type='flex' justify='space-around'>
<Col>
<Radio.Group
style={{ display: 'flex' }}
value={cuboidDrawingMethod}
onChange={onChangeCuboidDrawingMethod}
>
<Radio
value={CuboidDrawingMethod.CLASSIC}
style={{ width: 'auto' }}
>
From rectangle
</Radio>
<Radio
value={CuboidDrawingMethod.CORNER_POINTS}
style={{ width: 'auto' }}
>
By 4 Points
</Radio>
</Radio.Group>
</Col>
</Row>
</>
)
}
{
shapeType !== ShapeType.RECTANGLE && shapeType !== ShapeType.CUBOID && (
<Row type='flex' justify='space-around' align='middle'>
Expand Down
Loading

0 comments on commit 5816494

Please sign in to comment.