def combine_all_detections(detections, iou_threshold): """ Input: m by n_i by 5, where m is the number of models and n_i is the number of detections from model i Output: n by 5 """ if len(detections) == 1: return detections[0] else: resulting_detections = [] for reference_detection in detections[0]: if len(detections[1]) == 0: resulting_detections.append(reference_detection) continue overlaps = compute_overlap( np.expand_dims(reference_detection, axis=0), detections[1]) if len(overlaps) == 0: resulting_detections.append(reference_detection) continue best_index = np.argmax(overlaps, axis=1) # print("Assigned annotation:") # print(assigned_annotation) max_overlap = overlaps[0, best_index][0] if max_overlap > 0 or max_overlap >= iou_threshold: combined_box = _combine_bounding_boxes( reference_detection, detections[1][best_index][0]) resulting_detections.append(combined_box) return resulting_detections
def combine_detections(all_detections, image_number, label, iou_threshold): """ all_detections = [ detections_from_model for model in all_models ] :param all_detections: :param image_number: :param label: :return: """ if len(all_detections) == 1: return all_detections[0][0] resulting_detections = [] for detection in all_detections[0][image_number][label]: overlaps = compute_overlap(np.expand_dims(detection, axis=0), all_detections[1][image_number][label]) assigned_annotation = np.argmax(overlaps, axis=1) # print("Assigned annotation:") # print(assigned_annotation) max_overlap = overlaps[0, assigned_annotation][0] # print("Max overlap:") # print(max_overlap) if max_overlap > 0 or max_overlap >= iou_threshold: combined_box = _combine_bounding_boxes( detection, all_detections[1][image_number][label][assigned_annotation[0]]) resulting_detections.append(combined_box) return resulting_detections
def compute_annotations(anchors, annotations, negative_overlap=0.2, positive_overlap=0.5): """ Obtain indices of gt annotations with the greatest overlap. Args anchors: np.array of annotations of shape (N, 4) for (x1, y1, x2, y2). annotations: np.array of shape (N, 5) for (x1, y1, x2, y2, label). negative_overlap: IoU overlap for negative anchors (all anchors with overlap < negative_overlap are negative). positive_overlap: IoU overlap or positive anchors (all anchors with overlap > positive_overlap are positive). Returns positive_indices: indices of positive anchors ignore_indices: indices of ignored anchors argmax_overlaps_inds: ordered overlaps indices """ overlaps = compute_overlap(anchors.astype(np.float64), annotations.astype(np.float64)) argmax_overlaps_inds = np.argmax(overlaps, axis=1) max_overlaps = overlaps[np.arange(overlaps.shape[0]), argmax_overlaps_inds] # assign "dont care" labels positive_indices = max_overlaps >= positive_overlap negative_indices = max_overlaps < negative_overlap return positive_indices, negative_indices
def anchor_targets_bbox(anchors, annotations, num_classes, mask_shape=None, negative_overlap=0.4, positive_overlap=0.5, **kwargs): """ Generate anchor targets for bbox detection. Args anchors: np.array of annotations of shape (N, 4) for (x1, y1, x2, y2). annotations: np.array of shape (N, 5) for (x1, y1, x2, y2, label). num_classes: Number of classes to predict. mask_shape: If the image is padded with zeros, mask_shape can be used to mark the relevant part of the image. negative_overlap: IoU overlap for negative anchors (all anchors with overlap < negative_overlap are negative). positive_overlap: IoU overlap or positive anchors (all anchors with overlap > positive_overlap are positive). Returns labels: np.array of shape (A, num_classes) where a row consists of 0 for negative and 1 for positive for a certain class. annotations: np.array of shape (A, 5) for (x1, y1, x2, y2, label) containing the annotations corresponding to each anchor or 0 if there is no corresponding anchor. anchor_states: np.array of shape (N,) containing the state of an anchor (-1 for ignore, 0 for bg, 1 for fg). """ # anchor states: 1 is positive, 0 is negative, -1 is dont care anchor_states = np.zeros((anchors.shape[0], )) labels = np.zeros((anchors.shape[0], num_classes)) if annotations.shape[0]: # obtain indices of gt annotations with the greatest overlap overlaps = compute_overlap(anchors.astype(np.float64), annotations.astype(np.float64)) argmax_overlaps_inds = np.argmax(overlaps, axis=1) max_overlaps = overlaps[np.arange(overlaps.shape[0]), argmax_overlaps_inds] # assign "dont care" labels positive_indices = max_overlaps >= positive_overlap ignore_indices = (max_overlaps > negative_overlap) & ~positive_indices anchor_states[ignore_indices] = -1 anchor_states[positive_indices] = 1 # compute box regression targets annotations = annotations[argmax_overlaps_inds] # compute target class labels labels[positive_indices, annotations[positive_indices, 4].astype(int)] = 1 else: # no annotations? then everything is background annotations = np.zeros((anchors.shape[0], annotations.shape[1])) # ignore annotations outside of image if mask_shape: anchors_centers = np.vstack([(anchors[:, 0] + anchors[:, 2]) / 2, (anchors[:, 1] + anchors[:, 3]) / 2]).T indices = np.logical_or(anchors_centers[:, 0] >= mask_shape[1], anchors_centers[:, 1] >= mask_shape[0]) anchor_states[indices] = -1 return labels, annotations, anchor_states
def average_overlap(values): global not_matched anchor_params = calculate_config(values, args.ratios) if args.include_stride: anchors = anchors_for_shape(image_shape, anchor_params=anchor_params) else: anchors = base_anchors_for_shape(anchor_params=anchor_params) overlap = compute_overlap(entries, anchors) max_overlap = np.amax(overlap, axis=1) not_matched = len(np.where(max_overlap < 0.5)[0]) if args.objective == 'avg': result = 1 - np.average(max_overlap) elif args.objective == 'ce': result = np.average(-np.log(max_overlap)) elif args.objective == 'focal': result = np.average(-(1 - max_overlap) ** 2 * np.log(max_overlap)) else: raise Exception('Invalid mode.') if result < state['best_result']: state['best_result'] = result print('Current best anchor configuration') print(f'Ratios: {sorted(np.round(anchor_params.ratios, 3))}') print(f'Scales: {sorted(np.round(anchor_params.scales, 3))}') if args.include_stride: print(f'Average overlap: {np.round(np.average(max_overlap), 3)}') print(f'Number of labels that don\'t have any matching anchor: {not_matched}') print() return result
def evaluate_dual_memory_model(generator, models, iou_threshold=0.5, score_threshold=0.05, max_detections=100, save_path=None): detections_per_model = [] all_inferences = [] for model in models: current_detections, current_inferences = _get_detections( generator, model, score_threshold=score_threshold, max_detections=max_detections, save_path=save_path) detections_per_model.append(current_detections) all_inferences.append(current_inferences) average_precisions = {} all_annotations = _get_annotations(generator) # all_detections = detections_per_model[0] # process detections and annotations final_detections = {} for label in range(generator.num_classes()): if not generator.has_label(label): continue false_positives = np.zeros((0, )) true_positives = np.zeros((0, )) scores = np.zeros((0, )) num_annotations = 0.0 for i in range(generator.size()): detections = [ all_detections[i][label] for all_detections in detections_per_model ] detections = combine_all_detections(detections, iou_threshold) key = f"label={label}, instance_index={i}" final_detections[key] = [[d.tolist() for d in detection] for detection in detections] annotations = all_annotations[i][label] num_annotations += annotations.shape[0] detected_annotations = [] for d in detections: scores = np.append(scores, d[4]) if annotations.shape[0] == 0: false_positives = np.append(false_positives, 1) true_positives = np.append(true_positives, 0) continue overlaps = compute_overlap(np.expand_dims(d, axis=0), annotations) assigned_annotation = np.argmax(overlaps, axis=1) max_overlap = overlaps[0, assigned_annotation] if max_overlap >= iou_threshold and assigned_annotation not in detected_annotations: false_positives = np.append(false_positives, 0) true_positives = np.append(true_positives, 1) detected_annotations.append(assigned_annotation) else: false_positives = np.append(false_positives, 1) true_positives = np.append(true_positives, 0) if num_annotations == 0: average_precisions[label] = 0, 0 continue # Sort by score: indices = np.argsort(-scores) false_positives = false_positives[indices] true_positives = true_positives[indices] # Compute false positives and true positives: false_positives = np.cumsum(false_positives) true_positives = np.cumsum(true_positives) # Compute recall and precision: recall = true_positives / num_annotations precision = true_positives / np.maximum( true_positives + false_positives, np.finfo(np.float64).eps) # Compute average precision: average_precision = _compute_ap(recall, precision) average_precisions[label] = average_precision, num_annotations # Inference time: inference_time = np.sum(all_inferences) / generator.size() return average_precisions, inference_time, detections_per_model, final_detections