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 copy
35 import time
36
37 import pyvision as pv
38
40 '''
41 Given eye coordinates estimate the face rectangle
42 Assumes the face is reasonably horizontal.
43 '''
44 truth_rect = pv.BoundingRect(eye1, eye2)
45 truth_rect.w = 3.0 * truth_rect.w
46 truth_rect.h = truth_rect.w
47 truth_rect.x = truth_rect.x - 0.33 * truth_rect.w
48 truth_rect.y = truth_rect.y - 0.4 * truth_rect.w
49 return truth_rect
50
51
52
53 -def is_success(truth_rect, detected_rect, threshhold=0.25):
54 '''
55 This code takes a truth rect and a detected rect and determines
56 if the detection is a success or a failure. The default behavior
57 is true if the intersection of the two rects is has 50% of the
58 area of the larger rectangle.
59 '''
60
61 if overlap_score(truth_rect, detected_rect) < threshhold:
62 return False
63 return True
64
65
67 '''
68 This code takes a truth rect and a detected rect and determines
69 if the detection is a success or a failure. The default behavior
70 is true if the intersection of the two rects is has 50% of the
71 area of the larger rectangle.
72 '''
73 same = truth_rect.intersect(detected_rect)
74 max_area = max(truth_rect.area(), detected_rect.area())
75 if same == None:
76 return 0.0
77 return same.area()/max_area
78
79
80
82 - def __init__(self,name=None,threshold=0.25):
83 '''
84 Create a face detection test.
85
86 INPUTS:
87 @param name: Label for the test.
88 @param threshold: The fraction of joint area that counts as success.
89 '''
90 self.name = name
91 self.threshold=threshold
92 self.sample_id = 1
93
94 self.table = pv.Table()
95 self.summary_table = pv.Table()
96
97
98 self.images = 0
99 self.positives = 0
100 self.successes = 0
101 self.negatives = 0
102 self.pixels = 0
103
104
105 self.pos_rate = 0.0
106 self.pos_bounds = (0.0,0.0)
107 self.neg_rate = 0.0
108
109 self.image_time = None
110 self.total_time = None
111 self.start_time = time.time()
112 self.end_time = None
113
114 - def addSample(self, truth_rects, detected_rects, im=None, annotate=False):
115 '''
116 Adds a sample to face detection test.
117
118 @param truth_rects: truth for an image.
119 @param detected_rects: output of the detector
120 @param im: the image or filename to assciate with the sample.
121 @param annotate: add diagnostic annotations to the images.
122 '''
123 self.images += 1
124 name = None
125 detected_rects = copy.copy(detected_rects)
126
127 if isinstance(im,pv.Image):
128 name = im.filename
129 if self.pixels != None:
130 self.pixels += im.asPIL().size[0] * im.asPIL().size[1]
131 elif isinstance(im,str):
132 name = im
133 self.pixels = None
134 else:
135 name = "%d"%self.sample_id
136 self.pixels = None
137
138 table = self.table
139
140 for i in range(len(truth_rects)):
141 truth = truth_rects[i]
142 self.positives += 1
143 success = False
144 best_overlap = 0.0
145 best_detection = None
146
147 for j in range(len(detected_rects)):
148 detected = detected_rects[j]
149 overlap = overlap_score(truth,detected)
150 if overlap >= self.threshold and overlap > best_overlap:
151 success = True
152 best_overlap = overlap
153 best_detection = j
154
155 table.setData(self.sample_id,'id',self.sample_id)
156 table.setData(self.sample_id,'name',name)
157 table.setData(self.sample_id,'truth_rect',str(truth))
158 if best_detection != None:
159 table.setData(self.sample_id,'detection_rect',str(detected_rects[best_detection]))
160 else:
161 table.setData(self.sample_id,'detection_rect',None)
162 table.setData(self.sample_id,'success',success)
163 table.setData(self.sample_id,'overlap',best_overlap)
164 self.sample_id+=1
165
166 if success:
167 self.successes += 1
168 if annotate and isinstance(im,pv.Image):
169 if success:
170 im.annotateEllipse(truth,color='green')
171 else:
172 im.annotateEllipse(truth,color='red')
173
174
175
176 if best_detection != None:
177 del detected_rects[best_detection]
178
179 if annotate:
180 for each in detected_rects:
181 im.annotateRect(each,color='red')
182
183 self.negatives += len(detected_rects)
184
185 self.end_time = time.time()
186 self.total_time = self.end_time - self.start_time
187 self.image_time = self.total_time/float(self.images)
188
189 if self.positives > 0:
190 self.pos_rate = float(self.successes)/self.positives
191 self.pos_bounds = pv.cibinom(self.positives,self.successes,alpha=0.05)
192 if self.pixels != None:
193 self.neg_rate = float(self.negatives)/float(1.0e-6*self.pixels)
194
195 self.createSummary()
196
198 '''
199 Summary of a test as a table.
200 '''
201 self.summary_table.setElement('PosRate','Value',self.pos_rate)
202 self.summary_table.setElement('Lower95','Value',self.pos_bounds[0])
203 self.summary_table.setElement('Upper95','Value',self.pos_bounds[1])
204 self.summary_table.setElement('NegRate','Value',self.neg_rate)
205 self.summary_table.setElement('NegCount','Value',self.negatives)
206 self.summary_table.setElement('ImageCount','Value',self.images)
207 self.summary_table.setElement('TotalTime','Value',self.total_time)
208 self.summary_table.setElement('TimePerImage','Value',self.image_time)
209
211 ''' One line summary of the test '''
212 return "FaceDetectionTest(name:%s,PosRate:%f,PosBounds:%s,NegRate:%f,Neg:%d,Im:%d)"%(self.name,self.pos_rate,self.pos_bounds,self.neg_rate,self.negatives,self.images)
213
214
215
217 '''
218 Create a summary table for a list containing FaceDetectionTest objects.
219 '''
220 summary = pv.Table()
221 summary.setColumnFormat('PosRate','%0.4f')
222 summary.setColumnFormat('Lower95','%0.4f')
223 summary.setColumnFormat('Upper95','%0.4f')
224 summary.setColumnFormat('NegRate','%0.4f')
225 summary.setColumnFormat('Time','%0.2f')
226 for test in tests:
227 summary.setElement(test.name,'PosRate',test.pos_rate)
228 summary.setElement(test.name,'Lower95',test.pos_bounds[0])
229 summary.setElement(test.name,'Upper95',test.pos_bounds[1])
230 summary.setElement(test.name,'NegRate',test.neg_rate)
231 summary.setElement(test.name,'Time',test.total_time)
232 return summary
233
234
235