Package pyvision :: Package types :: Module Rect
[hide private]
[frames] | no frames]

Source Code for Module pyvision.types.Rect

  1  # PyVision License 
  2  # 
  3  # Copyright (c) 2006-2008 David S. Bolme 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  #  
 10  # 1. Redistributions of source code must retain the above copyright 
 11  # notice, this list of conditions and the following disclaimer. 
 12  #  
 13  # 2. Redistributions in binary form must reproduce the above copyright 
 14  # notice, this list of conditions and the following disclaimer in the 
 15  # documentation and/or other materials provided with the distribution. 
 16  #  
 17  # 3. Neither name of copyright holders nor the names of its contributors 
 18  # may be used to endorse or promote products derived from this software 
 19  # without specific prior written permission. 
 20  #  
 21  #  
 22  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 23  # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 24  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 25  # A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR 
 26  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 27  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 28  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 29  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 30  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 31  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 32  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 33   
 34  import pyvision as pv 
 35  import numpy as np 
 36   
37 -def BoundingRect(*points):
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 # if the first argument is a list of points 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 # If this is a list of rects 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 # if it is a pv point 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 # Find the mins an maxs 66 assert len(xs) > 0 67 minx = min(*xs) 68 maxx = max(*xs) 69 miny = min(*ys) 70 maxy = max(*ys) 71 72 # Create the rect 73 return Rect(minx,miny,maxx-minx,maxy-miny)
74
75 -def CenteredRect(cx,cy,w,h):
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
80 -class Rect:
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
100 - def intersect(self, rect):
101 ''' 102 Compute the intersection of two rectangles. 103 104 @returns: a rectangle representing the intersection. 105 ''' 106 # define rect 1 and rect 2 107 r1 = self 108 r2 = rect 109 110 # find rect 1 coordinates 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 # find rect 2 coordinates 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 # find the bounds of the intersection 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 # translate to width and height 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 # Return the intersection 136 return Rect(r3_x1,r3_y1,r3_w, r3_h)
137
138 - def containsRect(self,rect):
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
153 - def containsPoint(self,point):
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
165 - def center(self):
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
173 - def area(self):
174 ''' 175 @returns: the area of the rect 176 ''' 177 return self.w*self.h
178
179 - def overlap(self,rect2):
180 ''' 181 Compute an overlap measure for two detection rectangles. 182 ''' 183 i = self.intersect(rect2) # Compute the intersection 184 if i == None: 185 return 0.0 186 u = self.area() + rect2.area() - i.area() # Compute the union 187 return i.area()/u
188 189
190 - def similarity(self,rect):
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
200 - def rescale(self,scale):
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
214 - def asInt(self):
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
224 - def __str__(self):
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
230 - def __repr__(self):
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
236 - def box(self):
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
244 - def asOpenCV(self):
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
250 - def asTuple(self):
251 ''' 252 @returns a tuple (x,y,w,h). 253 ''' 254 return (self.x,self.y,self.w,self.h)
255
256 - def asCenteredTuple(self):
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
262 - def asCorners(self):
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
274 - def asPolygon(self):
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
287 - def __mul__(self,val):
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
294 - def __rmul__(self,val):
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
301 - def __div__(self,val):
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
309 -def test():
310 ''' 311 Run some simple rectangle tests. 312 ''' 313 p1 = pv.Point(1,1) 314 p2 = pv.Point(4,4) 315 p3 = pv.Point(5,4) 316 p4 = pv.Point(6,8) 317 318 r1 = BoundingRect(p1,p2) 319 r2 = BoundingRect(p3,p4) 320 r3 = Rect(3,3,3,3) 321 print r1 322 print r2 323 print r1.intersect(r2) 324 print r3.intersect(r2)
325 326 # A main function that runs tests. 327 if __name__ == "__main__": 328 test() 329