def read_class_csv(csv_class_file): """ function that reads in a class csv file that is used as an input to the retinanet training routine, and outputs a list of class names which is the format required by Keras ImageGenerator :param csv_class_file: the filename of the csv containing class names and indices :return: list of classnames """ try: with csv_generator._open_for_csv(csv_class_file) as file: classes = csv_generator._read_classes( csv.reader(file, delimiter=',')) class_list = list(classes.keys()) for c in classes: class_idx = classes[c] class_list[class_idx] = c return class_list except ValueError as e: raise_from( ValueError('invalid CSV class file: {}: {}'.format( csv_class_file, e)), None)
def main(args=None): # parse arguments if args is None: args = sys.argv[1:] args = parse_args(args) # make sure keras is the minimum required version check_keras_version() # optionally choose specific GPU if args.gpu: os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu keras.backend.tensorflow_backend.set_session(get_session()) # make save path if it doesn't exist if args.save_path is not None and not os.path.exists(args.save_path): os.makedirs(args.save_path) # optionally load config parameters if args.config: args.config = read_config_file(args.config) # create the generator #generator = create_generator(args) # optionally load anchor parameters anchor_params = None if args.config and 'anchor_parameters' in args.config: anchor_params = parse_anchor_parameters(args.config) # load the model print('Loading model, this may take a second...') model = models.load_model(args.model, backbone_name=args.backbone) # optionally convert the model if args.convert_model: model = models.convert_model(model, anchor_params=anchor_params) # print model summary print(model.summary()) print("annotations", args.annotations) print("classes", args.classes) print("min", args.image_min_side) print("max", args.image_max_side) print("configs", args.config) iou_threshold = args.iou_threshold score_threshold = args.score_threshold max_detections = args.max_detections image_names = [] image_data = {} # Take base_dir from annotations file if not explicitly specified. # parse the provided class file try: with _open_for_csv(args.classes) as file: classes = _read_classes(csv.reader(file, delimiter=',')) except ValueError as e: raise_from( ValueError('invalid CSV class file: {}: {}'.format( args.classes, e)), None) labels = {} for key, value in classes.items(): labels[value] = key # csv with img_path, x1, y1, x2, y2, class_name try: with _open_for_csv(args.annotations) as file: file_annotations = _read_annotations( csv.reader(file, delimiter=','), classes) except ValueError as e: raise_from( ValueError('invalid CSV annotations file: {}: {}'.format( args.annotations, e)), None) image_names = list(file_annotations.keys()) num_classes = len(labels) all_detections = [[None for i in range(num_classes) if i in labels] for j in range(len(image_names))] for image_index in range(len(image_names)): """ Load annotations for an image_index. """ path = file_annotations[image_names[image_index]] annotations = {'labels': np.empty((0, )), 'bboxes': np.empty((0, 4))} for idx, annot in enumerate( file_annotations[image_names[image_index]]): for key, value in classes.items(): if annot['class'] == key: break annotations['labels'] = np.concatenate( (annotations['labels'], [value])) annotations['bboxes'] = np.concatenate((annotations['bboxes'], [[ float(annot['x1']), float(annot['y1']), float(annot['x2']), float(annot['y2']), ]])) f = [] for label in range(num_classes): for cls in classes: if classes[cls] == label: print('class', cls) break f.append( open( "results/comp4_det_" + args.annotations.split("/")[-1].split(".")[0] + "_" + cls + ".txt", 'w')) for i in range(0, len(image_names)): print('image num', i) file_name = image_names[i] # load image image = read_image_bgr(file_name) image = preprocess_image(image) image, scale = resize_image(image) boxes, scores, labels = model.predict_on_batch( np.expand_dims(image, axis=0)) boxes /= scale # select indices which have a score above the threshold indices = np.where(scores[0, :] > score_threshold)[0] # select those scores scores = scores[0][indices] # find the order with which to sort the scores scores_sort = np.argsort(-scores)[:max_detections] # select detections image_boxes = boxes[0, indices[scores_sort], :] image_scores = scores[scores_sort] image_labels = labels[0, indices[scores_sort]] image_detections = np.concatenate([ image_boxes, np.expand_dims(image_scores, axis=1), np.expand_dims(image_labels, axis=1) ], axis=1) # copy detections to all_detections for label in range(num_classes): if not label in labels: continue dets = image_detections[image_detections[:, -1] == label, :-1] for cls in classes: if classes[cls] == label: print('class', cls) break for scr in dets: f[label].write( file_name.split("/")[-1].split(".")[0] + " " + str(scr[4]) + " " + str(scr[0]) + " " + str(scr[1]) + " " + str(scr[2]) + " " + str(scr[3]) + "\n") for label in range(num_classes): f[label].close()
def anchors_optimize( annotations, ratios=3, scales=3, objective='focal', popsize=15, mutation=0.5, image_min_side=512, image_max_side=512, # default SIZES values SIZES=[32, 64, 128, 256, 512], # default STRIDES values STRIDES=[8, 16, 32, 64, 128], include_stride=False, resize=False, threads=1, verbose=False, seed=None): """ Important Note: The python "anchors_optimize" function is meant to be used from the command line (from within a Python console it gives incorrect results) """ if ratios % 2 != 1: raise Exception('The number of ratios has to be odd.') entries = np.zeros((0, 4)) max_x = 0 max_y = 0 updating = 'immediate' if threads > 1: # when the number of threads is > 1 then 'updating' is set to 'deferred' by default (see the documentation of "scipy.optimize.differential_evolution()) updating = 'deferred' if seed is None: seed = np.random.RandomState() else: seed = np.random.RandomState(seed) if verbose: print('Loading object dimensions.') with _open_for_csv(annotations) as file: for line, row in enumerate(csv.reader(file, delimiter=',')): x1, y1, x2, y2 = list(map(lambda x: int(x), row[1:5])) if not x1 or not y1 or not x2 or not y2: continue if resize: # Concat base path from annotations file follow retinanet base_dir = os.path.split(annotations)[0] relative_path = row[0] image_path = os.path.join(base_dir, relative_path) img = Image.open(image_path) if hasattr(img, "shape"): image_shape = img.shape else: image_shape = (img.size[0], img.size[1], 3) scale = compute_resize_scale(image_shape, min_side=image_min_side, max_side=image_max_side) x1, y1, x2, y2 = list(map(lambda x: int(x) * scale, row[1:5])) max_x = max(x2, max_x) max_y = max(y2, max_y) if include_stride: entry = np.expand_dims(np.array([x1, y1, x2, y2]), axis=0) entries = np.append(entries, entry, axis=0) else: width = x2 - x1 height = y2 - y1 entry = np.expand_dims(np.array( [-width / 2, -height / 2, width / 2, height / 2]), axis=0) entries = np.append(entries, entry, axis=0) image_shape = [max_y, max_x] if verbose: print('Optimising anchors.') bounds = [] for i in range(int((ratios - 1) / 2)): bounds.append((1, 4)) for i in range(scales): bounds.append((0.4, 2)) update_state = None if threads == 1: update_state = state ARGS = ( entries, image_shape, objective, ratios, include_stride, SIZES, STRIDES, verbose, update_state, # return a single value ('to_tuple' parameter is set to False) False, threads) result = scipy.optimize.differential_evolution( func=average_overlap, # pass the '*args' as a tuple (see: https://stackoverflow.com/q/32302654) args=ARGS, mutation=mutation, updating=updating, workers=threads, bounds=bounds, popsize=popsize, seed=seed) if hasattr(result, 'success') and result.success: print('Optimization ended successfully!') elif not hasattr(result, 'success'): print('Optimization ended!') else: print('Optimization ended unsuccessfully!') print('Reason: {}'.format(result.message)) values = result.x anchor_params = calculate_config(values, ratios, SIZES, STRIDES) (avg, not_matched) = average_overlap( values, entries, image_shape, 'avg', ratios, include_stride, SIZES, STRIDES, verbose, # pass a specific value to the 'set_state' parameter {'best_result': 0}, # return a 'tuple' ('to_tuple' parameter is set to True) True, # set the 'threads' parameter to 1 1) # as 'end_state' set the 'avg' value end_state = np.round(avg, 5) RATIOS_result = sorted(np.round(anchor_params.ratios, 3)) SCALES_result = sorted(np.round(anchor_params.scales, 3)) print() print('Final best anchor configuration') print('State: {}'.format(end_state)) print('Ratios: {}'.format(RATIOS_result)) print('Scales: {}'.format(SCALES_result)) dict_out = { 'ratios': RATIOS_result, 'scales': SCALES_result, 'not_matched': not_matched, 'end_state': end_state } if include_stride: STRIDE = np.round(1 - avg, 3) print('Average overlap: {}'.format(STRIDE)) dict_out['stride'] = STRIDE print("Number of labels that don't have any matching anchor: {}".format( not_matched)) return dict_out
if args.ratios % 2 != 1: raise Exception('The number of ratios has to be odd.') entries = np.zeros((0, 4)) max_x = 0 max_y = 0 if args.seed: seed = np.random.RandomState(args.seed) else: seed = np.random.RandomState() print('Loading object dimensions.') with _open_for_csv(args.annotations) as file: for line, row in enumerate(csv.reader(file, delimiter=',')): x1, y1, x2, y2 = list(map(lambda x: int(x), row[1:5])) if not x1 or not y1 or not x2 or not y2: continue if args.resize: img = Image.open(row[0]) if hasattr(img, "shape"): image_shape = img.shape else: image_shape = (img.size[0], img.size[1], 3) scale = compute_resize_scale(image_shape,