Package pyvision :: Package analysis :: Package FaceAnalysis :: Module EyeDetectionTest
[hide private]
[frames] | no frames]

Source Code for Module pyvision.analysis.FaceAnalysis.EyeDetectionTest

  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 copy 
 35  import time 
 36  import math 
 37   
 38  import pyvision as pv 
 39  from pyvision.analysis.FaceAnalysis.FaceDetectionTest import face_from_eyes,is_success 
 40   
41 -class EyeDetectionTest:
42 ''' 43 BUGFIX: 20080813 Bailey Draper found a bug that the field dl in the full 44 report was really dl^2. 45 '''
46 - def __init__(self,name=None,threshold=0.25, test_detect=True):
47 '''''' 48 self.name = name 49 self.table = pv.Table() 50 self.summary_table = pv.Table() 51 self.face_successes = 0 52 self.both25_successes = 0 53 self.left25_successes = 0 54 self.right25_successes = 0 55 self.both10_successes = 0 56 self.left10_successes = 0 57 self.right10_successes = 0 58 self.both05_successes = 0 59 self.left05_successes = 0 60 self.right05_successes = 0 61 self.bothsse = 0.0 62 self.rightsse = 0.0 63 self.leftsse = 0.0 64 self.pixels = 0 65 self.images = 0 66 self.faces = 0 67 self.start_time = time.time() 68 self.stop_time = None 69 self.test_detect = test_detect 70 self.sample_id = 0
71
72 - def addSample(self, truth_eyes, detected_eyes, im=None, annotate=False):
73 '''''' 74 self.images += 1 75 76 if isinstance(im,pv.Image): 77 name = im.filename 78 if self.pixels != None: 79 self.pixels += im.asPIL().size[0] * im.asPIL().size[1] 80 elif isinstance(im,str): 81 name = im 82 self.pixels = None 83 else: 84 name = "%d"%self.sample_id 85 self.pixels = None 86 self.sample_id += 1 87 88 self.stop_time = time.time() 89 90 for tl,tr in truth_eyes: 91 tface = face_from_eyes(tl,tr) 92 93 detect_face = False 94 eye_dist = None 95 detect_b25 = False 96 detect_b10 = False 97 detect_b05 = False 98 detect_l25 = False 99 detect_l10 = False 100 detect_l05 = False 101 detect_r25 = False 102 detect_r10 = False 103 detect_r05 = False 104 eye_dist = None 105 tl_x = None 106 tl_y = None 107 tr_x = None 108 tr_y = None 109 pl_x = None 110 pl_y = None 111 pr_x = None 112 pr_y = None 113 dlx = None 114 dly = None 115 dl2 = None 116 dl = None 117 dlfrac= None 118 drx = None 119 dry = None 120 dr2 = None 121 dr = None 122 drfrac= None 123 deye = None 124 dmean = None 125 126 for pl,pr in detected_eyes: 127 dface = face_from_eyes(pl,pr) 128 129 if not self.test_detect or is_success(tface,dface): 130 tl_x = tl.X() 131 tl_y = tl.Y() 132 tr_x = tr.X() 133 tr_y = tr.Y() 134 eye_dist = math.sqrt((tl_x-tr_x)*(tl_x-tr_x) + (tl_y-tr_y)*(tl_y-tr_y)) 135 pl_x = pl.X() 136 pl_y = pl.Y() 137 pr_x = pr.X() 138 pr_y = pr.Y() 139 140 detect_face = True 141 142 eye_dist = math.sqrt((tl_x-tr_x)*(tl_x-tr_x) + (tl_y-tr_y)*(tl_y-tr_y)) 143 144 dlx = pl_x-tl_x 145 dly = pl_y-tl_y 146 dl2 = dlx*dlx + dly*dly 147 dl = math.sqrt(dl2) 148 dlfrac = dl/eye_dist 149 150 drx = pr_x-tr_x 151 dry = pr_y-tr_y 152 dr2 = drx*drx + dry*dry 153 dr = math.sqrt(dr2) 154 drfrac = dr/eye_dist 155 156 deye = max(drfrac,dlfrac) 157 158 dmean = 0.5*(dr+dl) 159 160 detect_l25 = 0.25 > dlfrac 161 detect_l10 = 0.10 > dlfrac 162 detect_l05 = 0.05 > dlfrac 163 detect_r25 = 0.25 > drfrac 164 detect_r10 = 0.10 > drfrac 165 detect_r05 = 0.05 > drfrac 166 detect_b25 = 0.25 > deye 167 detect_b10 = 0.10 > deye 168 detect_b05 = 0.05 > deye 169 170 break 171 172 self.table.setElement(self.faces,'name',name) 173 self.table.setElement(self.faces,'detect_face',detect_face) 174 self.table.setElement(self.faces,'detect_l25',detect_l25) 175 self.table.setElement(self.faces,'detect_l10',detect_l10) 176 self.table.setElement(self.faces,'detect_l05',detect_l05) 177 self.table.setElement(self.faces,'detect_r25',detect_r25) 178 self.table.setElement(self.faces,'detect_r10',detect_r10) 179 self.table.setElement(self.faces,'detect_r05',detect_r05) 180 self.table.setElement(self.faces,'detect_b25',detect_b25) 181 self.table.setElement(self.faces,'detect_b10',detect_b10) 182 self.table.setElement(self.faces,'detect_b05',detect_b05) 183 self.table.setElement(self.faces,'eye_dist',eye_dist) 184 185 self.table.setElement(self.faces,'truth_lx',tl_x) 186 self.table.setElement(self.faces,'truth_ly',tl_y) 187 self.table.setElement(self.faces,'truth_rx',tr_x) 188 self.table.setElement(self.faces,'truth_ry',tr_y) 189 190 self.table.setElement(self.faces,'pred_lx',pl_x) 191 self.table.setElement(self.faces,'pred_ly',pl_y) 192 self.table.setElement(self.faces,'pred_rx',pr_x) 193 self.table.setElement(self.faces,'pred_ry',pr_y) 194 195 self.table.setElement(self.faces,'dlx',dlx) 196 self.table.setElement(self.faces,'dly',dly) 197 #self.table.setElement(self.faces,'dl2',dl2) 198 self.table.setElement(self.faces,'dl',dl) # BUGFIX: 20080813 This was outputing dl2. 199 self.table.setElement(self.faces,'dlfrac',dlfrac) 200 self.table.setElement(self.faces,'drx',drx) 201 self.table.setElement(self.faces,'dry',dry) 202 #self.table.setElement(self.faces,'dr2',dr2) 203 self.table.setElement(self.faces,'dr',dr) 204 self.table.setElement(self.faces,'drfrac',drfrac) 205 self.table.setElement(self.faces,'deye',deye) 206 self.table.setElement(self.faces,'dmean',dmean) 207 208 self.faces += 1 209 if dlfrac != None: 210 self.bothsse += dlfrac**2 + drfrac**2 211 self.leftsse += dlfrac**2 212 self.rightsse += drfrac**2 213 214 if detect_face: self.face_successes += 1 215 if detect_b25: self.both25_successes += 1 216 if detect_l25: self.left25_successes += 1 217 if detect_r25: self.right25_successes += 1 218 if detect_b10: self.both10_successes += 1 219 if detect_l10: self.left10_successes += 1 220 if detect_r10: self.right10_successes += 1 221 if detect_b05: self.both05_successes += 1 222 if detect_l05: self.left05_successes += 1 223 if detect_r05: self.right05_successes += 1
224 225
226 - def finish(self):
227 self.face_rate = float(self.face_successes)/self.faces 228 self.face_ci = pv.cibinom(self.faces,self.face_successes,alpha=0.05) 229 self.both25_rate = float(self.both25_successes)/self.faces 230 self.both25_ci = pv.cibinom(self.faces,self.both25_successes,alpha=0.05) 231 self.both10_rate = float(self.both10_successes)/self.faces 232 self.both10_ci = pv.cibinom(self.faces,self.both10_successes,alpha=0.05) 233 self.both05_rate = float(self.both05_successes)/self.faces 234 self.both05_ci = pv.cibinom(self.faces,self.both05_successes,alpha=0.05) 235 self.left25_rate = float(self.left25_successes)/self.faces 236 self.left25_ci = pv.cibinom(self.faces,self.left25_successes,alpha=0.05) 237 self.left10_rate = float(self.left10_successes)/self.faces 238 self.left10_ci = pv.cibinom(self.faces,self.left10_successes,alpha=0.05) 239 self.left05_rate = float(self.left05_successes)/self.faces 240 self.left05_ci = pv.cibinom(self.faces,self.left05_successes,alpha=0.05) 241 self.right25_rate = float(self.right25_successes)/self.faces 242 self.right25_ci = pv.cibinom(self.faces,self.right25_successes,alpha=0.05) 243 self.right10_rate = float(self.right10_successes)/self.faces 244 self.right10_ci = pv.cibinom(self.faces,self.right10_successes,alpha=0.05) 245 self.right05_rate = float(self.right05_successes)/self.faces 246 self.right05_ci = pv.cibinom(self.faces,self.right05_successes,alpha=0.05) 247 if self.face_successes > 0: 248 self.bothrmse = math.sqrt(self.bothsse/(2*self.face_successes)) 249 self.leftrmse = math.sqrt(self.leftsse/self.face_successes) 250 self.rightrmse = math.sqrt(self.rightsse/self.face_successes) 251 self.elapse_time = self.stop_time - self.start_time 252 self.time_per_image = self.elapse_time / self.images 253 self.time_per_face = self.elapse_time / self.faces
254 255 256
257 - def createSummary(self):
258 '''''' 259 self.finish() 260 self.summary_table.setElement('FaceRate','Estimate',self.face_rate) 261 self.summary_table.setElement('FaceRate','Lower95',self.face_ci[0]) 262 self.summary_table.setElement('FaceRate','Upper95',self.face_ci[1]) 263 self.summary_table.setElement('Both25Rate','Estimate',self.both25_rate) 264 self.summary_table.setElement('Both25Rate','Lower95',self.both25_ci[0]) 265 self.summary_table.setElement('Both25Rate','Upper95',self.both25_ci[1]) 266 self.summary_table.setElement('Both10Rate','Estimate',self.both10_rate) 267 self.summary_table.setElement('Both10Rate','Lower95',self.both10_ci[0]) 268 self.summary_table.setElement('Both10Rate','Upper95',self.both10_ci[1]) 269 self.summary_table.setElement('Both05Rate','Estimate',self.both05_rate) 270 self.summary_table.setElement('Both05Rate','Lower95',self.both05_ci[0]) 271 self.summary_table.setElement('Both05Rate','Upper95',self.both05_ci[1]) 272 self.summary_table.setElement('BothRMSE','Estimate',self.bothrmse) 273 self.summary_table.setElement('Left25Rate','Estimate',self.left25_rate) 274 self.summary_table.setElement('Left25Rate','Lower95',self.left25_ci[0]) 275 self.summary_table.setElement('Left25Rate','Upper95',self.left25_ci[1]) 276 self.summary_table.setElement('Left10Rate','Estimate',self.left10_rate) 277 self.summary_table.setElement('Left10Rate','Lower95',self.left10_ci[0]) 278 self.summary_table.setElement('Left10Rate','Upper95',self.left10_ci[1]) 279 self.summary_table.setElement('Left05Rate','Estimate',self.left05_rate) 280 self.summary_table.setElement('Left05Rate','Lower95',self.left05_ci[0]) 281 self.summary_table.setElement('Left05Rate','Upper95',self.left05_ci[1]) 282 self.summary_table.setElement('LeftRMSE','Estimate',self.leftrmse) 283 self.summary_table.setElement('Right25Rate','Estimate',self.right25_rate) 284 self.summary_table.setElement('Right25Rate','Lower95',self.right25_ci[0]) 285 self.summary_table.setElement('Right25Rate','Upper95',self.right25_ci[1]) 286 self.summary_table.setElement('Right10Rate','Estimate',self.right10_rate) 287 self.summary_table.setElement('Right10Rate','Lower95',self.right10_ci[0]) 288 self.summary_table.setElement('Right10Rate','Upper95',self.right10_ci[1]) 289 self.summary_table.setElement('Right05Rate','Estimate',self.right05_rate) 290 self.summary_table.setElement('Right05Rate','Lower95',self.right05_ci[0]) 291 self.summary_table.setElement('Right05Rate','Upper95',self.right05_ci[1]) 292 self.summary_table.setElement('RightRMSE','Estimate',self.rightrmse) 293 self.summary_table.setElement('ElapsedTime','Estimate',self.elapse_time) 294 self.summary_table.setElement('ImageTime','Estimate',self.time_per_image) 295 self.summary_table.setElement('FaceTime','Estimate',self.time_per_face) 296 self.summary_table.setElement('ImageCount','Estimate',self.images) 297 self.summary_table.setElement('FaceCount','Estimate',self.faces) 298 return self.summary_table
299
300 - def getTable(self):
301 return self.table
302
303 - def __str__(self):
304 ''' One line summary of the test ''' 305 self.finish() 306 return "EyeDetectionTest(name:%s,FaceRate:%0.4f,Both10Rate:%0.4f,Left10Rate:%0.4f,Right10Rate:%0.4f,BothRMSE:%0.4f,NFaces:%d,Time:%0.2f)"%(self.name,self.face_rate,self.both10_rate,self.left10_rate,self.right10_rate,self.bothrmse,self.faces,self.elapse_time)
307 308 #############################################################################
309 -def summarizeEyeDetectionTests(tests):
310 ''' 311 Create a summary table for a list containing FaceDetectionTest objects. 312 ''' 313 print 'Creating summaries...' 314 summary25 = pv.Table() 315 summary25.setColumnFormat('Face_Rate','%0.4f') 316 summary25.setColumnFormat('Rate_25','%0.4f') 317 summary25.setColumnFormat('Lower95_25','%0.4f') 318 summary25.setColumnFormat('Upper95_25','%0.4f') 319 summary25.setColumnFormat('Time','%0.2f') 320 for test in tests: 321 print test.name 322 summary25.setElement(test.name,'Face_Rate',test.face_rate) 323 summary25.setElement(test.name,'Rate_25',test.both25_rate) 324 summary25.setElement(test.name,'Lower95_25',test.both25_ci[0]) 325 summary25.setElement(test.name,'Upper95_25',test.both25_ci[1]) 326 summary25.setElement(test.name,'Time',test.elapse_time) 327 328 329 summary10 = pv.Table() 330 summary10.setColumnFormat('Face_Rate','%0.4f') 331 summary10.setColumnFormat('Rate_10','%0.4f') 332 summary10.setColumnFormat('Lower95_10','%0.4f') 333 summary10.setColumnFormat('Upper95_10','%0.4f') 334 summary10.setColumnFormat('Time','%0.2f') 335 for test in tests: 336 summary10.setElement(test.name,'Face_Rate',test.face_rate) 337 summary10.setElement(test.name,'Rate_10',test.both10_rate) 338 summary10.setElement(test.name,'Lower95_10',test.both10_ci[0]) 339 summary10.setElement(test.name,'Upper95_10',test.both10_ci[1]) 340 summary10.setElement(test.name,'Time',test.elapse_time) 341 342 343 summary05 = pv.Table() 344 summary05.setColumnFormat('Face_Rate','%0.4f') 345 summary05.setColumnFormat('Rate_05','%0.4f') 346 summary05.setColumnFormat('Lower95_05','%0.4f') 347 summary05.setColumnFormat('Upper95_05','%0.4f') 348 summary05.setColumnFormat('Time','%0.2f') 349 for test in tests: 350 summary05.setElement(test.name,'Face_Rate',test.face_rate) 351 summary05.setElement(test.name,'Rate_05',test.both05_rate) 352 summary05.setElement(test.name,'Lower95_05',test.both05_ci[0]) 353 summary05.setElement(test.name,'Upper95_05',test.both05_ci[1]) 354 summary05.setElement(test.name,'Time',test.elapse_time) 355 356 return summary05,summary10,summary25
357