This repository has been archived by the owner on Sep 10, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
annotator.py
160 lines (122 loc) · 5.2 KB
/
annotator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Implementation of annotator.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import np_box_ops # available from https://github.com/tensorflow/models/blob/master/research/object_detection/utils/np_box_ops.py
class Annotator(object):
DRAW = 1
VERIFY = 0
"""Annotator class."""
def __init__(self, ground_truth, time_verify, time_draw, min_iou):
"""Basic class for Annotator.
Args:
ground_truth: image_id + class_id with coordinates of ground truth boxes,
pandas dataframe
time_verify: time per box verification in seconds, float
time_draw: time per drawing in seconds, float
min_iou: minimal iou required for the box to be accepted, float
"""
self.ground_truth = ground_truth
self.time_verify = time_verify
self.time_draw = time_draw
self.min_iou = min_iou
def compute_iou(self, box1, box2):
"""Copute intersection over union between 2 given boxes.
Args:
box1: first box in the form of pandas series with columns
'xmin', 'xmax', 'ymin', 'ymax'
box2: second box in the form of pandas series with columns
'xmin', 'xmax', 'ymin', 'ymax'
Returns:
iou: IoU between box1 and box2
"""
if (len(box1) != 1) or (len(box2) != 1):
raise ValueError()
box1_array = np.array([[box1['ymin'], box1['xmin'],
box1['ymax'], box1['xmax']]])
box2_array = np.array([[box2['ymin'], box2['xmin'],
box2['ymax'], box2['xmax']]])
iou = np_box_ops.iou(box1_array, box2_array)[0, 0]
return iou
def compute_iou_to_group(self, box1, boxes):
"""Compute intersection over union between 2 given boxes.
Args:
box1: first box in the form of pandas series with columns
'xmin', 'xmax', 'ymin', 'ymax'
boxes: second box in the form of pandas dataframe with columns
'xmin', 'xmax', 'ymin', 'ymax'
Returns:
ious: the computed iou between box1 and boxes, numpy.ndarray 1xn where
n is the number of rows in dataframe boxes
"""
box1_array = np.array([[box1['ymin'], box1['xmin'],
box1['ymax'], box1['xmax']]])
if np.shape(box1_array)[0] != 1:
raise ValueError()
boxes_array = boxes.as_matrix(columns=['ymin', 'xmin', 'ymax', 'xmax'])
ious = np_box_ops.iou(box1_array, boxes_array)
return ious
class AnnotatorSimple(Annotator):
"""Simple annotator model.
It acceptes images with iou with ground truth highest than min_iou and
rejects the others.
"""
def __init__(self, ground_truth, random_seed, time_verify=3.5,
time_draw=7, min_iou=0.7):
Annotator.__init__(self, ground_truth, time_verify, time_draw, min_iou)
self.random_seed = random_seed
def do_box_verification(self, image_id, class_id, coord):
"""Do box verification.
Args:
image_id: image id for verification, str
class_id: class id for verification, int64
coord: coordinates of the box to verify in the form f pandas series
{'xmin': 0, 'xmax': 1, 'ymin': 0, 'ymax': 1}
Returns:
time_verify: time that it took for operation, float
is_accepted: boolean variable if it was accepted or not
"""
is_accepted = False
# find the relevant ground truth
gt = self.ground_truth[(self.ground_truth['image_id'] == image_id) &
(self.ground_truth['class_id'] == class_id)]
# try to rewrite:
if np.amax(self.compute_iou_to_group(coord, gt)) >= self.min_iou:
is_accepted = True
return self.time_verify, is_accepted
def do_extreme_clicking(self, image_id, class_id):
"""Do extreme clicking.
Args:
image_id: image id for verification, str
class_id: class id for verification, int64
Returns:
time_draw: time that took for operation
coordinates: dictionary of coordinates in the form
{'xmin': 0, 'xmax': 1, 'ymin': 0, 'ymax': 1})
for one of the boxes corresponding to gt
"""
gt = self.ground_truth[(self.ground_truth['image_id'] == image_id) &
(self.ground_truth['class_id'] == class_id)]
# if there are several boxes for this class in this image, get one at random
selected_gt = gt.sample(1, random_state=self.random_seed)
coordinates = {'xmin': int(selected_gt['xmin']),
'xmax': int(selected_gt['xmax']),
'ymin': int(selected_gt['ymin']),
'ymax': int(selected_gt['ymax'])}
return self.time_draw, coordinates