Diff of /eval/detection/bbox.py [000000] .. [139527]

Switch to unified view

a b/eval/detection/bbox.py
1
from .utils import *
2
3
4
class BoundingBox:
5
    def __init__(self,
6
                 imageName,
7
                 classId,
8
                 x,
9
                 y,
10
                 w,
11
                 h,
12
                 typeCoordinates=CoordinatesType.Absolute,
13
                 imgSize=None,
14
                 bbType=BBType.GroundTruth,
15
                 classConfidence=None,
16
                 format=BBFormat.XYWH):
17
        """Constructor.
18
        Args:
19
            imageName: String representing the image name.
20
            classId: String value representing class id.
21
            x: Float value representing the X upper-left coordinate of the bounding box.
22
            y: Float value representing the Y upper-left coordinate of the bounding box.
23
            w: Float value representing the width bounding box.
24
            h: Float value representing the height bounding box.
25
            typeCoordinates: (optional) Enum (Relative or Absolute) represents if the bounding box
26
            coordinates (x,y,w,h) are absolute or relative to size of the image. Default:'Absolute'.
27
            imgSize: (optional) 2D vector (width, height)=>(int, int) represents the size of the
28
            image of the bounding box. If typeCoordinates is 'Relative', imgSize is required.
29
            bbType: (optional) Enum (Groundtruth or Detection) identifies if the bounding box
30
            represents a ground truth or a detection. If it is a detection, the classConfidence has
31
            to be informed.
32
            classConfidence: (optional) Float value representing the confidence of the detected
33
            class. If detectionType is Detection, classConfidence needs to be informed.
34
            format: (optional) Enum (BBFormat.XYWH or BBFormat.XYX2Y2) indicating the format of the
35
            coordinates of the bounding boxes. BBFormat.XYWH: <left> <top> <width> <height>
36
            BBFormat.XYX2Y2: <left> <top> <right> <bottom>.
37
        """
38
        self._imageName = imageName
39
        self._typeCoordinates = typeCoordinates
40
        if typeCoordinates == CoordinatesType.Relative and imgSize is None:
41
            raise IOError(
42
                'Parameter \'imgSize\' is required. It is necessary to inform the image size.')
43
        if bbType == BBType.Detected and classConfidence is None:
44
            raise IOError(
45
                'For bbType=\'Detection\', it is necessary to inform the classConfidence value.')
46
        # if classConfidence != None and (classConfidence < 0 or classConfidence > 1):
47
        # raise IOError('classConfidence value must be a real value between 0 and 1. Value: %f' %
48
        # classConfidence)
49
50
        self._classConfidence = classConfidence
51
        self._bbType = bbType
52
        self._classId = classId
53
        self._format = format
54
55
        # If relative coordinates, convert to absolute values
56
        # For relative coords: (x,y,w,h)=(X_center/img_width ,
57
        # Y_center/img_height)
58
        if (typeCoordinates == CoordinatesType.Relative):
59
            (self._x, self._y, self._w, self._h) = convertToAbsoluteValues(
60
                imgSize, (x, y, w, h))
61
            self._width_img = imgSize[0]
62
            self._height_img = imgSize[1]
63
            if format == BBFormat.XYWH:
64
                self._x2 = self._w
65
                self._y2 = self._h
66
                self._w = self._x2 - self._x
67
                self._h = self._y2 - self._y
68
            else:
69
                raise IOError(
70
                    'For relative coordinates, the format must be XYWH (x,y,width,height)')
71
        # For absolute coords: (x,y,w,h)=real bb coords
72
        else:
73
            self._x = x
74
            self._y = y
75
            if format == BBFormat.XYWH:
76
                self._w = w
77
                self._h = h
78
                self._x2 = self._x + self._w
79
                self._y2 = self._y + self._h
80
            else:  # format == BBFormat.XYX2Y2: <left> <top> <right> <bottom>.
81
                self._x2 = w
82
                self._y2 = h
83
                self._w = self._x2 - self._x
84
                self._h = self._y2 - self._y
85
        if imgSize is None:
86
            self._width_img = None
87
            self._height_img = None
88
        else:
89
            self._width_img = imgSize[0]
90
            self._height_img = imgSize[1]
91
92
    def getAbsoluteBoundingBox(self, format=BBFormat.XYWH):
93
        if format == BBFormat.XYWH:
94
            return (self._x, self._y, self._w, self._h)
95
        elif format == BBFormat.XYX2Y2:
96
            return (self._x, self._y, self._x2, self._y2)
97
98
    def getRelativeBoundingBox(self, imgSize=None):
99
        if imgSize is None and self._width_img is None and self._height_img is None:
100
            raise IOError(
101
                'Parameter \'imgSize\' is required. It is necessary to inform the image size.')
102
        if imgSize is not None:
103
            return convertToRelativeValues(
104
                (imgSize[0], imgSize[1]), (self._x, self._x2, self._y, self._y2))
105
        else:
106
            return convertToRelativeValues(
107
                (self._width_img, self._height_img), (self._x, self._x2, self._y, self._y2))
108
109
    def getImageName(self):
110
        return self._imageName
111
112
    def getConfidence(self):
113
        return self._classConfidence
114
115
    def getFormat(self):
116
        return self._format
117
118
    def getClassId(self):
119
        return self._classId
120
121
    def getImageSize(self):
122
        return (self._width_img, self._height_img)
123
124
    def getCoordinatesType(self):
125
        return self._typeCoordinates
126
127
    def getBBType(self):
128
        return self._bbType
129
130
    @staticmethod
131
    def compare(det1, det2):
132
        det1BB = det1.getAbsoluteBoundingBox()
133
        det1ImgSize = det1.getImageSize()
134
        det2BB = det2.getAbsoluteBoundingBox()
135
        det2ImgSize = det2.getImageSize()
136
137
        if det1.getClassId() == det2.getClassId() and \
138
           det1.classConfidence == det2.classConfidenc() and \
139
           det1BB[0] == det2BB[0] and \
140
           det1BB[1] == det2BB[1] and \
141
           det1BB[2] == det2BB[2] and \
142
           det1BB[3] == det2BB[3] and \
143
           det1ImgSize[0] == det1ImgSize[0] and \
144
           det2ImgSize[1] == det2ImgSize[1]:
145
            return True
146
        return False
147
148
    @staticmethod
149
    def clone(boundingBox):
150
        absBB = boundingBox.getAbsoluteBoundingBox(format=BBFormat.XYWH)
151
        # return (self._x,self._y,self._x2,self._y2)
152
        newBoundingBox = BoundingBox(
153
            boundingBox.getImageName(),
154
            boundingBox.getClassId(),
155
            absBB[0],
156
            absBB[1],
157
            absBB[2],
158
            absBB[3],
159
            typeCoordinates=boundingBox.getCoordinatesType(),
160
            imgSize=boundingBox.getImageSize(),
161
            bbType=boundingBox.getBBType(),
162
            classConfidence=boundingBox.getConfidence(),
163
            format=BBFormat.XYWH)
164
        return newBoundingBox
165
166
167
class BoundingBoxes:
168
    def __init__(self):
169
        self._boundingBoxes = []
170
171
    def addBoundingBox(self, bb):
172
        self._boundingBoxes.append(bb)
173
174
    def removeBoundingBox(self, _boundingBox):
175
        for d in self._boundingBoxes:
176
            if BoundingBox.compare(d, _boundingBox):
177
                del self._boundingBoxes[d]
178
                return
179
180
    def removeAllBoundingBoxes(self):
181
        self._boundingBoxes = []
182
183
    def getBoundingBoxes(self):
184
        return self._boundingBoxes
185
186
    def getBoundingBoxByClass(self, classId):
187
        boundingBoxes = []
188
        for d in self._boundingBoxes:
189
            if d.getClassId() == classId:  # get only specified bounding box type
190
                boundingBoxes.append(d)
191
        return boundingBoxes
192
193
    def getClasses(self):
194
        classes = []
195
        for d in self._boundingBoxes:
196
            c = d.getClassId()
197
            if c not in classes:
198
                classes.append(c)
199
        return classes
200
201
    def getBoundingBoxesByType(self, bbType):
202
        # get only specified bb type
203
        return [d for d in self._boundingBoxes if d.getBBType() == bbType]
204
205
    def getBoundingBoxesByImageName(self, imageName):
206
        # get only specified bb type
207
        return [d for d in self._boundingBoxes if d.getImageName() == imageName]
208
209
    def count(self, bbType=None):
210
        if bbType is None:  # Return all bounding boxes
211
            return len(self._boundingBoxes)
212
        count = 0
213
        for d in self._boundingBoxes:
214
            if d.getBBType() == bbType:  # get only specified bb type
215
                count += 1
216
        return count
217
218
    def clone(self):
219
        newBoundingBoxes = BoundingBoxes()
220
        for d in self._boundingBoxes:
221
            det = BoundingBox.clone(d)
222
            newBoundingBoxes.addBoundingBox(det)
223
        return newBoundingBoxes
224
225
    def drawAllBoundingBoxes(self, image, imageName):
226
        bbxes = self.getBoundingBoxesByImageName(imageName)
227
        for bb in bbxes:
228
            if bb.getBBType() == BBType.GroundTruth:  # if ground truth
229
                image = add_bb_into_image(image, bb, color=(0, 255, 0))  # green
230
            else:  # if detection
231
                image = add_bb_into_image(image, bb, color=(255, 0, 0))  # red
232
        return image