Skip to content

Commit 7f8b96d

Browse files
authored
Add extreme clicking feature to draw box by 4 points (#1111)
* Add extreme clicking feature to draw box by 4 points * Add documentation for extreme clicking
1 parent e062c23 commit 7f8b96d

File tree

7 files changed

+90
-7
lines changed

7 files changed

+90
-7
lines changed

cvat/apps/dextr_segmentation/static/dextr_segmentation/js/enginePlugin.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ window.addEventListener('DOMContentLoaded', () => {
5454
Object.defineProperty(instance, 'defaultType', {
5555
get: () => instance._defaultType,
5656
set: (type) => {
57-
if (!['box', 'points', 'polygon', 'polyline', 'auto_segmentation'].includes(type)) {
57+
if (!['box', 'box_by_4_points', 'points', 'polygon',
58+
'polyline', 'auto_segmentation'].includes(type)) {
5859
throw Error(`Unknown shape type found ${type}`);
5960
}
6061
instance._defaultType = type;
Loading
Loading

cvat/apps/documentation/user_guide.md

+15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- [Annotation mode (advanced)](#annotation-mode-advanced)
2626
- [Interpolation mode (advanced)](#interpolation-mode-advanced)
2727
- [Attribute annotation mode (advanced)](#attribute-annotation-mode-advanced)
28+
- [Annotation with box by 4 points](#annotation-with-box-by-4-points)
2829
- [Annotation with polygons](#annotation-with-polygons)
2930
- [Annotation with polylines](#annotation-with-polylines)
3031
- [Annotation with points](#annotation-with-points)
@@ -934,6 +935,20 @@ To navigate between objects (pedestrians in the case), use the following shortcu
934935
By default, objects in the mode are zoomed. Check
935936
``Open Menu`` —> ``Settings`` —> ``AAM Zoom Margin`` to adjust that.
936937

938+
## Annotation with box by 4 points
939+
It is an efficient method of bounding box annotation, proposed
940+
[here](https://arxiv.org/pdf/1708.02750.pdf).
941+
Before starting, you need to be sure that ``Box by 4 points`` is selected.
942+
943+
![](static/documentation/images/image134.jpg)
944+
945+
Press ``N`` for entering drawing mode. Click exactly four extreme points:
946+
the top, bottom, left- and right-most physical points on the object.
947+
Drawing is automatically completed right after clicking the fourth point.
948+
Press ``Esc`` to cancel editing.
949+
950+
![](static/documentation/images/gif016.gif)
951+
937952
## Annotation with polygons
938953

939954
It is used for semantic / instance segmentation.

cvat/apps/engine/static/engine/js/shapeCreator.js

+68-6
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class ShapeCreatorModel extends Listener {
5454
}
5555

5656
// FIXME: In the future we have to make some generic solution
57-
if (this._defaultMode === 'interpolation' && ['box', 'points'].includes(this._defaultType)) {
57+
if (this._defaultMode === 'interpolation'
58+
&& ['box', 'points', 'box_by_4_points'].includes(this._defaultType)) {
5859
data.shapes = [];
5960
data.shapes.push(Object.assign({}, result, data));
6061
this._shapeCollection.add(data, `interpolation_${this._defaultType}`);
@@ -125,7 +126,7 @@ class ShapeCreatorModel extends Listener {
125126
}
126127

127128
set defaultType(type) {
128-
if (!['box', 'points', 'polygon', 'polyline'].includes(type)) {
129+
if (!['box', 'box_by_4_points', 'points', 'polygon', 'polyline'].includes(type)) {
129130
throw Error(`Unknown shape type found ${type}`);
130131
}
131132
this._defaultType = type;
@@ -234,8 +235,8 @@ class ShapeCreatorView {
234235
// FIXME: In the future we have to make some generic solution
235236
const mode = this._modeSelector.prop('value');
236237
const type = $(e.target).prop('value');
237-
if (type !== 'box' && !(type === 'points' && this._polyShapeSize === 1)
238-
&& mode !== 'annotation') {
238+
if (type !== 'box' && type !== 'box_by_4_points'
239+
&& !(type === 'points' && this._polyShapeSize === 1) && mode !== 'annotation') {
239240
this._modeSelector.prop('value', 'annotation');
240241
this._controller.setDefaultShapeMode('annotation');
241242
showMessage('Only the annotation mode allowed for the shape');
@@ -252,7 +253,7 @@ class ShapeCreatorView {
252253
const mode = $(e.target).prop('value');
253254
const type = this._typeSelector.prop('value');
254255
if (mode !== 'annotation' && !(type === 'points' && this._polyShapeSize === 1)
255-
&& type !== 'box') {
256+
&& type !== 'box' && type !== 'box_by_4_points') {
256257
this._typeSelector.prop('value', 'box');
257258
this._controller.setDefaultShapeType('box');
258259
showMessage('Only boxes and single point allowed in the interpolation mode');
@@ -492,7 +493,7 @@ class ShapeCreatorView {
492493
ytl,
493494
xbr,
494495
ybr,
495-
}
496+
};
496497

497498
if (this._mode === 'interpolation') {
498499
box.outside = false;
@@ -511,6 +512,67 @@ class ShapeCreatorView {
511512
}
512513
});
513514
break;
515+
case 'box_by_4_points':
516+
let numberOfPoints = 0;
517+
this._drawInstance = this._frameContent.polyline().draw({ snapToGrid: 0.1 })
518+
.addClass('shapeCreation').attr({
519+
'stroke-width': 0,
520+
}).on('drawstart', () => {
521+
// init numberOfPoints as one on drawstart
522+
numberOfPoints = 1;
523+
}).on('drawpoint', (e) => {
524+
// increase numberOfPoints by one on drawpoint
525+
numberOfPoints += 1;
526+
527+
// finish if numberOfPoints are exactly four
528+
if (numberOfPoints === 4) {
529+
let actualPoints = window.cvat.translate.points.canvasToActual(e.target.getAttribute('points'));
530+
actualPoints = PolyShapeModel.convertStringToNumberArray(actualPoints);
531+
const { frameWidth, frameHeight } = window.cvat.player.geometry;
532+
533+
// init bounding box
534+
const box = {
535+
'xtl': frameWidth,
536+
'ytl': frameHeight,
537+
'xbr': 0,
538+
'ybr': 0
539+
};
540+
541+
for (const point of actualPoints) {
542+
// clamp point
543+
point.x = Math.clamp(point.x, 0, frameWidth);
544+
point.y = Math.clamp(point.y, 0, frameHeight);
545+
546+
// update bounding box
547+
box.xtl = Math.min(point.x, box.xtl);
548+
box.ytl = Math.min(point.y, box.ytl);
549+
box.xbr = Math.max(point.x, box.xbr);
550+
box.ybr = Math.max(point.y, box.ybr);
551+
}
552+
553+
if ((box.ybr - box.ytl) * (box.xbr - box.xtl) >= AREA_TRESHOLD) {
554+
if (this._mode === 'interpolation') {
555+
box.outside = false;
556+
}
557+
// finish drawing
558+
this._controller.finish(box, this._type);
559+
}
560+
this._controller.switchCreateMode(true);
561+
}
562+
}).on('undopoint', () => {
563+
if (numberOfPoints > 0) {
564+
numberOfPoints -= 1;
565+
}
566+
}).off('drawdone').on('drawdone', () => {
567+
if (numberOfPoints !== 4) {
568+
showMessage('Click exactly four extreme points for an object');
569+
this._controller.switchCreateMode(true);
570+
} else {
571+
throw Error('numberOfPoints is exactly four, but box drawing did not finish.');
572+
}
573+
});
574+
this._createPolyEvents();
575+
break;
514576
case 'points':
515577
this._drawInstance = this._frameContent.polyline().draw({ snapToGrid: 0.1 })
516578
.addClass('shapeCreation').attr({

cvat/apps/engine/static/engine/js/shapes.js

+4
Original file line numberDiff line numberDiff line change
@@ -3313,6 +3313,10 @@ function buildShapeModel(data, type, clientID, color) {
33133313
switch (type) {
33143314
case 'interpolation_box':
33153315
case 'annotation_box':
3316+
case 'interpolation_box_by_4_points':
3317+
case 'annotation_box_by_4_points':
3318+
// convert type into 'box' if 'box_by_4_points'
3319+
type = type.replace('_by_4_points', '');
33163320
return new BoxModel(data, type, clientID, color);
33173321
case 'interpolation_points':
33183322
case 'annotation_points':

cvat/apps/engine/templates/engine/annotation.html

+1
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@
437437
</select>
438438
<select id="shapeTypeSelector" class="regular h2">
439439
<option value="box" class="regular" selected> Box </option>
440+
<option value="box_by_4_points" class="regular" selected> Box by 4 points </option>
440441
<option value="polygon" class="regular"> Polygon </option>
441442
<option value="polyline" class="regular"> Polyline </option>
442443
<option value="points" class="regular"> Points </option>

0 commit comments

Comments
 (0)