5 import matplotlib.pyplot as plt
6 from itertools import izip
8 """ Convert numPy matrices with rectangles and confidences to sorted list of detections."""
9 def convert2detections(rects, confs, crop_factor = 0.125):
13 dts = zip(*[rects.tolist(), confs.tolist()])
14 dts = zip(dts[0][0], dts[0][1])
15 dts = [Detection(r,c) for r, c in dts]
17 dts.sort(lambda x, y : -1 if (x.conf - y.conf) > 0 else 1)
24 """ Create new instance of soft cascade."""
25 def cascade(min_scale, max_scale, nscales, f):
26 # where we use nms cv::SoftCascadeDetector::DOLLAR == 2
27 c = cv2.softcascade_Detector(min_scale, max_scale, nscales, 2)
28 xml = cv2.FileStorage(f, 0)
29 dom = xml.getFirstTopLevelNode()
33 """ Compute prefix sum for en array."""
42 """ Compute x and y arrays for ROC plot."""
43 def computeROC(confidenses, tp, nannotated, nframes, ignored):
44 confidenses, tp, ignored = zip(*sorted(zip(confidenses, tp, ignored), reverse = True))
46 fp = [(1 - x) for x in tp]
47 fp = [(x - y) for x, y in izip(fp, ignored)]
51 miss_rate = [(1 - x / (nannotated + 0.000001)) for x in tp]
52 fppi = [x / float(nframes) for x in fp]
54 return fppi, miss_rate
56 """ Crop rectangle by factor."""
57 def crop_rect(rect, factor):
58 val_x = factor * float(rect[2])
59 val_y = factor * float(rect[3])
60 x = [int(rect[0] + val_x), int(rect[1] + val_y), int(rect[2] - 2.0 * val_x), int(rect[3] - 2.0 * val_y)]
63 """ Initialize plot axises."""
66 plt.ylabel("miss rate")
73 def plotLogLog(fppi, miss_rate, c):
74 plt.loglog(fppi, miss_rate, color = c, linewidth = 2)
76 """ Show resulted plot."""
77 def showPlot(file_name, labels):
78 plt.axis((pow(10, -3), pow(10, 1), .035, 1))
79 plt.yticks( [0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.64, 0.8, 1], ['.05', '.10', '.20', '.30', '.40', '.50', '.64', '.80', '1'] )
80 plt.legend(labels, loc = "lower left")
81 plt.savefig(file_name)
84 """ Filter true positives and ignored detections for cascade detector output."""
86 matches_gt = [0]*len(gts)
87 matches_dt = [0]*len(dts)
88 matches_ignore = [0]*len(dts)
91 return matches_dt, matches_ignore
93 # Cartesian product for each detection BB_dt with each BB_gt
94 overlaps = [[dt.overlap(gt) for gt in gts]for dt in dts]
96 for idx, row in enumerate(overlaps):
97 imax = row.index(max(row))
99 # try to match ground truth
100 if (matches_gt[imax] == 0 and row[imax] > 0.5):
104 for idx, dt in enumerate(dts):
105 # try to math ignored
106 if matches_dt[idx] == 0:
108 row = [i for i in row if (i[3] - i[1]) < 53 or (i[3] - i[1]) > 256]
110 if dts[idx].overlapIgnored(each) > 0.5:
111 matches_ignore[idx] = 1
112 return matches_dt, matches_ignore
115 """ Draw detections or ground truth on image."""
116 def draw_rects(img, rects, color, l = lambda x, y : x + y):
117 if rects is not None:
118 for x1, y1, x2, y2 in rects:
119 cv2.rectangle(img, (x1, y1), (l(x1, x2), l(y1, y2)), color, 2)
122 def draw_dt(img, dts, color, l = lambda x, y : x + y):
126 x1, y1, x2, y2 = dt.bb[0], dt.bb[1], dt.bb[2], dt.bb[3]
128 cv2.rectangle(img, (x1, y1), (l(x1, x2), l(y1, y2)), color, 2)
131 def __init__(self, bb, conf):
136 def crop(self, factor):
137 self.bb = crop_rect(self.bb, factor)
139 # we use rect-style for dt and box style for gt. ToDo: fix it
140 def overlap(self, b):
143 w = min( a[0] + a[2], b[2]) - max(a[0], b[0]);
144 h = min( a[1] + a[3], b[3]) - max(a[1], b[1]);
146 cross_area = 0.0 if (w < 0 or h < 0) else float(w * h)
147 union_area = (a[2] * a[3]) + ((b[2] - b[0]) * (b[3] - b[1])) - cross_area;
149 return cross_area / union_area
151 # we use rect-style for dt and box style for gt. ToDo: fix it
152 def overlapIgnored(self, b):
155 w = min( a[0] + a[2], b[2]) - max(a[0], b[0]);
156 h = min( a[1] + a[3], b[3]) - max(a[1], b[1]);
158 cross_area = 0.0 if (w < 0 or h < 0) else float(w * h)
159 self_area = (a[2] * a[3]);
161 return cross_area / self_area
163 def mark_matched(self):
166 """Parse INPIA annotation format"""
167 def parse_inria(ipath, f):
172 if l.startswith("Bounding box"):
173 b = [x.strip() for x in l.split(":")[1].split("-")]
174 c = [x[1:-1].split(",") for x in b]
175 d = [int(x) for x in sum(c, [])]
178 if l.startswith("Image filename"):
179 path = l.split('"')[-2]
181 return Sample(path, bbs)
184 def glob_set(pattern):
185 return [__n for __n in glob.iglob(pattern)]
187 """ Parse ETH idl file. """
191 l = re.sub(r"^\"left\/", "{\"", l)
192 l = re.sub(r"\:", ":[", l)
193 l = re.sub(r"(\;|\.)$", "]}", l)
197 """ Normalize detection box to unified aspect ration."""
198 def norm_box(box, ratio):
199 middle = float(box[0] + box[2]) / 2.0
200 new_half_width = float(box[3] - box[1]) * ratio / 2.0
201 return (int(round(middle - new_half_width)), box[1], int(round(middle + new_half_width)), box[3])
203 """ Process array of boxes."""
204 def norm_acpect_ratio(boxes, ratio):
205 return [ norm_box(box, ratio) for box in boxes]
207 """ Filter detections out of extended range. """
208 def filter_for_range(boxes, scale_range, ext_ratio):
209 boxes = norm_acpect_ratio(boxes, 0.5)
210 boxes = [b for b in boxes if (b[3] - b[1]) > scale_range[0] / ext_ratio]
211 boxes = [b for b in boxes if (b[3] - b[1]) < scale_range[1] * ext_ratio]
214 """ Resize sample for training."""
215 def resize_sample(image, d_w, d_h):
216 h, w, _ = image.shape
217 if (d_h < h) or (d_w < w):
218 ratio = min(d_h / float(h), d_w / float(w))
220 kernel_size = int( 5 / (2 * ratio))
222 image_to_resize = cv2.filter2D(image, cv2.CV_8UC3, cv2.getGaussianKernel(kernel_size, sigma))
223 interpolation_type = cv2.INTER_AREA
225 image_to_resize = image
226 interpolation_type = cv2.INTER_CUBIC
228 return cv2.resize(image_to_resize,(d_w, d_h), None, 0, 0, interpolation_type)
230 newobj = re.compile("^lbl=\'(\w+)\'\s+str=(\d+)\s+end=(\d+)\s+hide=0$")
234 def extract_objects(f):
238 if newobj.match(l) is not None:
246 _ = f.readline() # skip first line (version string)
248 (nFrame, nSample) = re.search(r'nFrame=(\d+) n=(\d+)', head).groups()
249 return (int(nFrame), int(nSample))
253 pos = re.match(r'^posv?\s*=(\[[\d\s\.\;]+\])$', l).group(1)
254 pos = re.sub(r"(\[)(\d)", "\\1[\\2", pos)
255 pos = re.sub(r"\s", ", ", re.sub(r"\;\s+(?=\])", "]", re.sub(r"\;\s+(?!\])", "],[", pos)))
260 occl = re.match(r'^occl\s*=(\[[\d\s\.\;]+\])$', l).group(1)
261 occl = re.sub(r"\s(?!\])", ",", occl)
264 def parse_caltech(f):
265 (nFrame, nSample) = caltech.parse_header(f)
266 objects = caltech.extract_objects(f)
268 annotations = [[] for i in range(nFrame)]
270 (type, start, end) = re.search(r'^lbl=\'(\w+)\'\s+str=(\d+)\s+end=(\d+)\s+hide=0$', obj[0]).groups()
271 print type, start, end
272 start = int(start) -1
274 pos = caltech.parse_pos(obj[1])
275 posv = caltech.parse_pos(obj[2])
276 occl = caltech.parse_occl(obj[3])
278 for idx, (p, pv, oc) in enumerate(zip(*[pos, posv, occl])):
279 annotations[start + idx].append((type, p, oc, pv))