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 import pyvision as pv
35 import numpy as np
36
38 '''
39 Create a rectangle that includes all of the points or rectangles.
40 '''
41 xs = []
42 ys = []
43 for each in points:
44 if type(each) == list or type(each) == tuple:
45
46 rect = BoundingRect(*each)
47 xs.append(rect.x)
48 xs.append(rect.x+rect.w)
49 ys.append(rect.y)
50 ys.append(rect.y+rect.h)
51 elif isinstance(each, pv.Rect):
52
53 rect = each
54 xs.append(rect.x)
55 xs.append(rect.x+rect.w)
56 ys.append(rect.y)
57 ys.append(rect.y+rect.h)
58 elif isinstance(each,pv.Point):
59
60 xs.append(each.X())
61 ys.append(each.Y())
62 else:
63 raise TypeError("Cannot create bounding rect for geometry of type: %s"%each.__class__)
64
65
66 assert len(xs) > 0
67 minx = min(*xs)
68 maxx = max(*xs)
69 miny = min(*ys)
70 maxy = max(*ys)
71
72
73 return Rect(minx,miny,maxx-minx,maxy-miny)
74
76 '''Specify a rectangle using a center point and a width and height.'''
77 return pv.Rect(cx-0.5*w,cy-0.5*h,w,h)
78
79
81 '''
82 This is a simple structure that represents a rectangle.
83 '''
84
85 - def __init__(self,x=0.0,y=0.0,w=0.0,h=0.0):
86 '''
87 Initialize a rectangle instance.
88
89 Arguments:
90 @param x: top left x coordinate
91 @param y: top left y coordinate
92 @param w: width
93 @param h: height
94 '''
95 self.x = float(x)
96 self.y = float(y)
97 self.w = float(w)
98 self.h = float(h)
99
101 '''
102 Compute the intersection of two rectangles.
103
104 @returns: a rectangle representing the intersection.
105 '''
106
107 r1 = self
108 r2 = rect
109
110
111 r1_x1 = r1.x
112 r1_x2 = r1.x + r1.w
113 r1_y1 = r1.y
114 r1_y2 = r1.y + r1.h
115
116
117 r2_x1 = r2.x
118 r2_x2 = r2.x + r2.w
119 r2_y1 = r2.y
120 r2_y2 = r2.y + r2.h
121
122
123 r3_x1 = max(r1_x1,r2_x1)
124 r3_x2 = min(r1_x2,r2_x2)
125 r3_y1 = max(r1_y1,r2_y1)
126 r3_y2 = min(r1_y2,r2_y2)
127
128
129 r3_w = r3_x2-r3_x1
130 r3_h = r3_y2-r3_y1
131
132 if r3_w < 0.0 or r3_h < 0.0:
133 return None
134
135
136 return Rect(r3_x1,r3_y1,r3_w, r3_h)
137
139 '''
140 Determines if rect is entirely within (contained by) this rectangle.
141 @param rect: an object of type pv.Rect
142 @return: True if the rect is entirely within this rectangle's boundaries.
143 '''
144 t1 = (self.x <= rect.x)
145 t2 = (self.y <= rect.y)
146 t3 = ( (self.x+self.w) >= (rect.x+rect.w) )
147 t4 = ( (self.y+self.h) >= (rect.y+rect.h) )
148 if( t1 and t2 and t3 and t4):
149 return True
150 else:
151 return False
152
154 '''
155 Determine if a point is within a rectangle.
156
157 @param point: an object of type pv.Point.
158 @returns: True if the point is withen the Rect.
159 '''
160 x = point.X()
161 y = point.Y()
162
163 return x >= self.x and x <= self.x+self.w and y >= self.y and y <= self.y + self.h
164
166 '''
167 Compute and return a point at the center of the rectangle
168
169 @returns: a pv.Point at the center.
170 '''
171 return pv.Point(self.x+0.5*self.w,self.y+0.5*self.h)
172
174 '''
175 @returns: the area of the rect
176 '''
177 return self.w*self.h
178
180 '''
181 Compute an overlap measure for two detection rectangles.
182 '''
183 i = self.intersect(rect2)
184 if i == None:
185 return 0.0
186 u = self.area() + rect2.area() - i.area()
187 return i.area()/u
188
189
191 '''
192 Compute the similarity of the rectangles in terms of overlap.
193 '''
194 i = self.intersect(rect)
195 if i == None:
196 return 0.0
197 return i.area() / (0.5*self.area() + 0.5*rect.area())
198
199
201 '''
202 Expand or contract the size of the rectangle by a "scale" while
203 keeping the Rect centered at the same location.
204
205 @param scale: the scale factor
206 @returns: the rescaled rect
207 '''
208 center = self.center()
209 cx,cy = center.X(),center.Y()
210 w = scale*self.w
211 h = scale*self.h
212 return Rect(cx-0.5*w,cy-0.5*h,w,h)
213
215 '''
216 Return a dictionary representing the rectangle with integer values
217 '''
218 x = int(np.floor(self.x))
219 y = int(np.floor(self.y))
220 w = int(np.floor(self.w))
221 h = int(np.floor(self.h))
222 return {'x':x,'y':y,'w':w,'h':h}
223
225 '''
226 @returns: a string representing this rectangle
227 '''
228 return "pv.Rect(%f,%f,%f,%f)"%(self.x,self.y,self.w,self.h)
229
231 '''
232 @returns: a string representing this rectangle
233 '''
234 return "pv.Rect(%f,%f,%f,%f)"%(self.x,self.y,self.w,self.h)
235
237 '''
238 Get this rectangle as a bounding box as expected by many PIL functions.
239
240 @returns: tuple of (left,top,right,bottom)
241 '''
242 return int(round(self.x)), int(round(self.y)), int(round(self.x+self.w)), int(round(self.y+self.h))
243
245 '''
246 @returns a representation compatible with opencv.
247 '''
248 return (int(round(self.x)),int(round(self.y)),int(round(self.w)),int(round(self.h)))
249
251 '''
252 @returns a tuple (x,y,w,h).
253 '''
254 return (self.x,self.y,self.w,self.h)
255
257 '''
258 @returns a tuple (cx,cy,w,h).
259 '''
260 return (self.x+0.5*self.w,self.y+0.5*self.h,self.w,self.h)
261
263 '''
264 Returns the four corners. Can be used to transform this rect
265 through an affine or perspective transformation.
266 '''
267 x,y,w,h = self.asTuple()
268 pt1 = pv.Point(x,y)
269 pt2 = pv.Point(x+w,y)
270 pt3 = pv.Point(x+w,y+h)
271 pt4 = pv.Point(x,y+h)
272 return [pt1,pt2,pt3,pt4]
273
275 '''
276 Returns the four corners with the upper left corner repeated twice.
277 Can be used to transform this rect through an affine or perspective
278 transformations. It can also be plotted with annotatePolygon.
279 '''
280 x,y,w,h = self.asTuple()
281 pt1 = pv.Point(x,y)
282 pt2 = pv.Point(x+w,y)
283 pt3 = pv.Point(x+w,y+h)
284 pt4 = pv.Point(x,y+h)
285 return [pt1,pt2,pt3,pt4,pt1]
286
288 '''
289 Multiply the rectangle by a constant.
290 '''
291 if isinstance(val,float) or isinstance(val,int):
292 return Rect(self.x*val,self.y*val,self.w*val,self.h*val)
293
295 '''
296 Multiply the rectangle by a constant.
297 '''
298 if isinstance(val,float) or isinstance(val,int):
299 return Rect(self.x*val,self.y*val,self.w*val,self.h*val)
300
302 '''
303 Divide the rectangle by a constant
304 '''
305 if isinstance(val,float) or isinstance(val,int):
306 return Rect(self.x/val,self.y/val,self.w/val,self.h/val)
307
308
325
326
327 if __name__ == "__main__":
328 test()
329