Exemplo n.º 1
0
    def _add_proposals_from_file(
        self, roidb, proposal_file, min_proposal_size, top_k, crowd_thresh
    ):
        """Add proposals from a proposals file to an roidb."""
        logger.info('Loading proposals from: {}'.format(proposal_file))
        proposals = load_object(proposal_file)

        id_field = 'indexes' if 'indexes' in proposals else 'ids'  # compat fix
        _sort_proposals(proposals, id_field)
        box_list = []
        for i, entry in enumerate(roidb):
            if i % 2500 == 0:
                logger.info(' {:d}/{:d}'.format(i + 1, len(roidb)))
            boxes = proposals['boxes'][i]
            # Sanity check that these boxes are for the correct image id
            assert entry['id'] == proposals[id_field][i]
            # Remove duplicate boxes and very small boxes and then take top k
            boxes = box_utils.clip_boxes_to_image(
                boxes, entry['height'], entry['width']
            )
            keep = box_utils.unique_boxes(boxes)
            boxes = boxes[keep, :]
            keep = box_utils.filter_small_boxes(boxes, min_proposal_size)
            boxes = boxes[keep, :]
            if top_k > 0:
                boxes = boxes[:top_k, :]
            box_list.append(boxes)
        _merge_proposal_boxes_into_roidb(roidb, box_list)
        if crowd_thresh > 0:
            _filter_crowd_proposals(roidb, crowd_thresh)
Exemplo n.º 2
0
    def _add_proposals_from_file(self, roidb, proposal_file, min_proposal_size,
                                 top_k, crowd_thresh):
        """Add proposals from a proposals file to an roidb."""
        logger.info('Loading proposals from: {}'.format(proposal_file))
        proposals = load_object(proposal_file)

        id_field = 'indexes' if 'indexes' in proposals else 'ids'  # compat fix
        _sort_proposals(proposals, id_field)
        box_list = []
        for i, entry in enumerate(roidb):
            if i % 2500 == 0:
                logger.info(' {:d}/{:d}'.format(i + 1, len(roidb)))
            boxes = proposals['boxes'][i]
            # Sanity check that these boxes are for the correct image id
            assert entry['id'] == proposals[id_field][i]
            # Remove duplicate boxes and very small boxes and then take top k
            boxes = box_utils.clip_boxes_to_image(boxes, entry['height'],
                                                  entry['width'])
            keep = box_utils.unique_boxes(boxes)
            boxes = boxes[keep, :]
            keep = box_utils.filter_small_boxes(boxes, min_proposal_size)
            boxes = boxes[keep, :]
            if top_k > 0:
                boxes = boxes[:top_k, :]
            box_list.append(boxes)
        _merge_proposal_boxes_into_roidb(roidb, box_list)
        if crowd_thresh > 0:
            _filter_crowd_proposals(roidb, crowd_thresh)
def accuracy(dataset, detections_pkl):
	# Load predictions and ground truths
	ds = JsonDataset(dataset)
	roidb = ds.get_roidb(gt=True)
	dets = load_object(detections_pkl)
	all_boxes = dets['all_boxes']

	def id_or_index(ix, val):
		if len(val) == 0:
			return val
		else:
			return val[ix]

	trues = 0.
	# Iterate through all images
	for ix, entry in enumerate(roidb):
		cls_boxes_i = [
			id_or_index(ix, cls_k_boxes) for cls_k_boxes in all_boxes
		]
		true_boxes = entry['boxes']
		if (true_boxes.shape[0] == 0) == (len(cls_boxes_i[3]) == 0):
			trues += 1
	# Finally, calculate accuracy by dividing the sum of true predictions by total samples
	acc = trues/len(roidb)
	print("Accuracy: " + str(acc))
	return acc
Exemplo n.º 4
0
def do_reval(dataset_name, output_dir, args):
    dataset = JsonDataset(dataset_name)
    dets = load_object(os.path.join(output_dir, 'detections.pkl'))

    # Override config with the one saved in the detections file
    if args.cfg_file is not None:
        core_config.merge_cfg_from_cfg(core_config.load_cfg(dets['cfg']))
    else:
        core_config._merge_a_into_b(core_config.load_cfg(dets['cfg']), cfg)

    # re-filter on score threshold:
    dets['all_boxes'] = \
        [
            [
                im[im[:,4] > cfg.TEST.SCORE_THRESH,:] if len(im) != 0 else []
                for im in cls
            ]
            for cls in dets['all_boxes']
        ]

    results = task_evaluation.evaluate_all(dataset,
                                           dets['all_boxes'],
                                           dets['all_segms'],
                                           dets['all_keyps'],
                                           output_dir,
                                           use_matlab=args.matlab_eval)
    task_evaluation.log_copy_paste_friendly_results(results)
Exemplo n.º 5
0
def process_in_parallel(tag, total_range_size, binary, output_dir, opts=''):
    """Run the specified binary cfg.NUM_GPUS times in parallel, each time as a
    subprocess that uses one GPU. The binary must accept the command line
    arguments `--range {start} {end}` that specify a data processing range.
    """
    # Snapshot the current cfg state in order to pass to the inference
    # subprocesses
    cfg_file = os.path.join(output_dir, '{}_range_config.yaml'.format(tag))
    with open(cfg_file, 'w') as f:
        envu.yaml_dump(cfg, stream=f)
    subprocess_env = os.environ.copy()
    processes = []
    subinds = np.array_split(range(total_range_size), cfg.NUM_GPUS)
    # Determine GPUs to use
    cuda_visible_devices = os.environ.get('CUDA_VISIBLE_DEVICES')
    if cuda_visible_devices:
        gpu_inds = map(int, cuda_visible_devices.split(','))
        assert -1 not in gpu_inds, \
            'Hiding GPU indices using the \'-1\' index is not supported'
    else:
        gpu_inds = reversed(range(cfg.NUM_GPUS))
    # Run the binary in cfg.NUM_GPUS subprocesses
    for i, gpu_ind in enumerate(gpu_inds):
        start = subinds[i][0]
        end = subinds[i][-1] + 1
        subprocess_env['CUDA_VISIBLE_DEVICES'] = str(gpu_ind)
        cmd = '{binary} --range {start} {end} --cfg {cfg_file} NUM_GPUS 1 {opts}'
        cmd = cmd.format(binary=shlex_quote(binary),
                         start=int(start),
                         end=int(end),
                         cfg_file=shlex_quote(cfg_file),
                         opts=' '.join([shlex_quote(opt) for opt in opts]))
        logger.info('{} range command {}: {}'.format(tag, i, cmd))
        if i == 0:
            subprocess_stdout = subprocess.PIPE
        else:
            filename = os.path.join(
                output_dir, '%s_range_%s_%s.stdout' % (tag, start, end))
            subprocess_stdout = open(filename, 'w')  # NOQA (close below)
        p = subprocess.Popen(cmd,
                             shell=True,
                             env=subprocess_env,
                             stdout=subprocess_stdout,
                             stderr=subprocess.STDOUT,
                             bufsize=1)
        processes.append((i, p, start, end, subprocess_stdout))
        print('Sleep 15s for gpu_id ', gpu_ind)
        time.sleep(15)
    # Log output from inference processes and collate their results
    outputs = []
    for i, p, start, end, subprocess_stdout in processes:
        log_subprocess_output(i, p, output_dir, tag, start, end)
        if i > 0:
            subprocess_stdout.close()
        range_file = os.path.join(output_dir,
                                  '%s_range_%s_%s.pkl' % (tag, start, end))
        range_data = load_object(range_file)
        outputs.append(range_data)
    return outputs
Exemplo n.º 6
0
def rrpn_loader(rpn_pkl_file):
    """
    Open, index and return a pickled proposals dictionary
    """

    pkl = load_object(rpn_pkl_file)
    proposals = {}
    for boxes, scores, id in zip(pkl['boxes'], pkl['scores'], pkl['ids']):
        proposals[id] = {'boxes': boxes, 'scores': scores}

    return proposals
def vis(dataset, detections_pkl, thresh, output_dir, limit=0):
    ds = JsonDataset(dataset)
    roidb = ds.get_roidb()

    dets = load_object(detections_pkl)

    assert all(k in dets for k in ['all_boxes', 'all_segms', 'all_keyps']), \
        'Expected detections pkl file in the format used by test_engine.py'

    all_boxes = dets['all_boxes']
    all_segms = dets['all_segms']
    all_keyps = dets['all_keyps']

    def id_or_index(ix, val):
        if len(val) == 0:
            return val
        else:
            return val[ix]

    for ix, entry in enumerate(roidb):
        if limit > 0 and ix >= limit:
            break
        if ix % 10 == 0:
            print('{:d}/{:d}'.format(ix + 1, len(roidb)))

        im = cv2.imread(entry['image'])
        im_name = os.path.splitext(os.path.basename(entry['image']))[0]

        cls_boxes_i = [
            id_or_index(ix, cls_k_boxes) for cls_k_boxes in all_boxes
        ]
        cls_segms_i = [
            id_or_index(ix, cls_k_segms) for cls_k_segms in all_segms
        ]
        cls_keyps_i = [
            id_or_index(ix, cls_k_keyps) for cls_k_keyps in all_keyps
        ]

        vis_utils.vis_one_image(
            im[:, :, ::-1],
            '{:d}_{:s}'.format(ix, im_name),
            os.path.join(output_dir, 'vis'),
            cls_boxes_i,
            segms=cls_segms_i,
            keypoints=cls_keyps_i,
            thresh=thresh,
            box_alpha=0.8,
            dataset=ds,
            show_class=True,
            ext = "jpg"
        )
Exemplo n.º 8
0
def do_reval(dataset_name, output_dir, args):
    dataset = JsonDataset(dataset_name)
    dets = load_object(os.path.join(output_dir, 'detections.pkl'))

    # Override config with the one saved in the detections file
    if args.cfg_file is not None:
        core_config.merge_cfg_from_cfg(core_config.load_cfg(dets['cfg']))
    else:
        core_config._merge_a_into_b(core_config.load_cfg(dets['cfg']), cfg)
    results = task_evaluation.evaluate_all(dataset,
                                           dets['all_boxes'],
                                           dets['all_segms'],
                                           dets['all_keyps'],
                                           output_dir,
                                           use_matlab=args.matlab_eval)
    task_evaluation.log_copy_paste_friendly_results(results)
Exemplo n.º 9
0
def convert_mask_net(args, mask_net):

    # Initialization net
    init_net = caffe2_pb2.NetDef()
    net = caffe2_pb2.NetDef()
    blobs = io_utils.load_object(args.wts)['blobs']
    externals = set(
        c2_utils.UnscopeName(inp) for inp in mask_net.external_input)
    for name in set(blobs.keys()).intersection(externals):
        blob = blobs[name]
        add_custom_op(init_net,
                      'GivenTensorFill', [], [name],
                      values=blob.flatten(),
                      shape=blob.shape)

    # Pre-process the ROIs
    add_custom_op(net, 'BBoxToRoi', [
        Constants.nms_outputs[1], Constants.im_info, Constants.nms_outputs[3]
    ], [Constants.mask_rois])
    # Group the ROIs based on their FPN level
    if cfg.FPN.MULTILEVEL_ROIS:
        outputs = [Constants.mask_rois + Constants.idx_restore_suffix]
        for level in range(cfg.FPN.ROI_MIN_LEVEL, cfg.FPN.ROI_MAX_LEVEL + 1):
            outputs.append(Constants.mask_rois +
                           Constants.fpn_level_suffix(level))
        add_custom_op(net,
                      'MultiLevelRoi', [Constants.mask_rois],
                      outputs,
                      min_level=cfg.FPN.ROI_MIN_LEVEL,
                      canon_scale=cfg.FPN.ROI_CANONICAL_SCALE,
                      canon_level=cfg.FPN.ROI_CANONICAL_LEVEL)

    # Generate the masks
    net.op.extend(mask_net.op)

    # Post-process the masks
    add_custom_op(net,
                  'SegmentMask',
                  Constants.nms_outputs[1:-1] +
                  [Constants.mask_pred, Constants.im_info],
                  [Constants.main_output, Constants.im_info],
                  thresh_bin=cfg.MRCNN.THRESH_BINARIZE)

    net.name = args.net_name + '_mask'
    init_net.name = args.net_name + '_mask_init'
    save_model(net, init_net, args.mask_dir)
Exemplo n.º 10
0
def do_reval(dataset_name, output_dir, args):
    dataset = JsonDataset(dataset_name)
    dets = load_object(os.path.join(output_dir, 'detections.pkl'))

    # Override config with the one saved in the detections file
    if args.cfg_file is not None:
        core_config.merge_cfg_from_cfg(core_config.load_cfg(dets['cfg']))
    else:
        core_config._merge_a_into_b(core_config.load_cfg(dets['cfg']), cfg)
    results = task_evaluation.evaluate_all(
        dataset,
        dets['all_boxes'],
        dets['all_segms'],
        dets['all_keyps'],
        output_dir,
        use_matlab=args.matlab_eval
    )
    task_evaluation.log_copy_paste_friendly_results(results)
Exemplo n.º 11
0
def _do_body_uv_eval(json_dataset, res_file, output_dir):
    ann_type = 'uv'
    imgIds = json_dataset.COCO.getImgIds()
    imgIds.sort()
    res = load_object(res_file)
    coco_dt = json_dataset.COCO.loadRes(res)
    # Non-standard params used by the modified COCO API version
    # from the DensePose fork
    # global normalization factor used in per-instance evaluation
    test_sigma = 0.255
    coco_eval = denseposeCOCOeval(json_dataset.COCO, coco_dt, ann_type,
                                  test_sigma)
    coco_eval.params.imgIds = imgIds
    coco_eval.evaluate()
    coco_eval.accumulate()
    eval_file = os.path.join(output_dir, 'body_uv_results.pkl')
    save_object(coco_eval, eval_file)
    logger.info('Wrote pickle eval results to: {}'.format(eval_file))
    coco_eval.summarize()
    return coco_eval
Exemplo n.º 12
0
def convert_mask_net(args, mask_net):

    # Initialization net
    init_net = caffe2_pb2.NetDef()
    net = caffe2_pb2.NetDef()
    blobs = io_utils.load_object(args.wts)['blobs']
    externals = set(c2_utils.UnscopeName(inp) for inp in mask_net.external_input)
    for name in set(blobs.keys()).intersection(externals):
        blob = blobs[name]
        add_custom_op(init_net, 'GivenTensorFill', [], [name],
                      values = blob.flatten(),
                      shape = blob.shape)

    # Pre-process the ROIs
    add_custom_op(net, 'BBoxToRoi',
                [Constants.nms_outputs[1], Constants.im_info, Constants.nms_outputs[3]],
                [Constants.mask_rois])
    # Group the ROIs based on their FPN level
    if cfg.FPN.MULTILEVEL_ROIS:
        outputs = [Constants.mask_rois + Constants.idx_restore_suffix]
        for level in range(cfg.FPN.ROI_MIN_LEVEL, cfg.FPN.ROI_MAX_LEVEL + 1):
            outputs.append(Constants.mask_rois + Constants.fpn_level_suffix(level))
        add_custom_op(net, 'MultiLevelRoi', [Constants.mask_rois], outputs,
                    min_level = cfg.FPN.ROI_MIN_LEVEL,
                    canon_scale = cfg.FPN.ROI_CANONICAL_SCALE,
                    canon_level = cfg.FPN.ROI_CANONICAL_LEVEL)

    # Generate the masks
    net.op.extend(mask_net.op)

    # Post-process the masks
    add_custom_op(net, 'SegmentMask',
                  Constants.nms_outputs[1:-1] + [Constants.mask_pred, Constants.im_info],
                  [Constants.main_output, Constants.im_info],
                  thresh_bin = cfg.MRCNN.THRESH_BINARIZE)

    net.name = args.net_name + '_mask'
    init_net.name = args.net_name + '_mask_init'
    save_model(net, init_net, args.mask_dir)
def load_and_convert_coco_model(args):
    model_dict = load_object(args.coco_model_file_name)
    remove_momentum(model_dict)
    convert_coco_blobs_to_cityscape_blobs(model_dict)
    return model_dict
Exemplo n.º 14
0
    
    parser.add_argument('--out_dir', dest='out_dir',
                        help='Test outputs directory',
                        default='../data/test')

    args = parser.parse_args()
    return args

##------------------------------------------------------------------------------
if __name__ == '__main__':
    args = parse_args()
    fig = plt.figure(figsize=(16, 9))

    # Load the dataset and proposals
    coco = COCO_PLUS(args.ann_file)
    proposals = load_object(args.proposals)
    num_imgs = len(coco.imgs)
    assert len(proposals['ids']) == num_imgs, \
        "Number of proposals do not match the number of images in the dataset"

    step = 1
    for i in tqdm(range(0, num_imgs, step)):
        img_id = proposals['ids'][i]
        points = coco.imgToPc[img_id]['points']
        img_path = os.path.join(args.imgs_dir, coco.imgs[img_id]["file_name"])
        img = np.array(plt.imread(img_path))
        boxes = proposals['boxes'][i]

        ## Plot proposals
        img = draw_xyxy_bbox(img, list(boxes), lineWidth=2)
        img = draw_points(img, points, color=(0,0,255), radius=5, thickness=-1, format='RGB')
Exemplo n.º 15
0
def visualize_ranking(dataset, detections_pkl, opts):

    # Load predictions and ground truths
    ds = JsonDataset(dataset)
    roidb = ds.get_roidb(gt=True)
    dets = load_object(detections_pkl)
    all_boxes = dets['all_boxes']

    def id_or_index(ix, val):
        if len(val) == 0:
            return val
        else:
            return val[ix]

    # Load coordinates
    with open(opts.coord_file) as json_file:
        coord_data = json.load(json_file)

    # Iterate through all images and note false positive and negatives, as well as entry scores
    false_positives = []
    false_negatives = []
    scores = []
    for ix, entry in enumerate(roidb):
        cls_boxes_i = [
            id_or_index(ix, cls_k_boxes) for cls_k_boxes in all_boxes
        ]
        preds = np.array(cls_boxes_i[opts.class_id])
        entry['preds'] = preds
        true_boxes = entry['boxes']
        if preds.shape[0] > 0 and np.max(preds[:, -1]) > opts.threshold:
            box_scores = preds[:, -1]
            box_scores = box_scores[np.where(box_scores > opts.threshold)]
            score = np.sum(
                box_scores[np.argsort(box_scores)[-opts.box_count:]])
            scores.append([entry, score])
            if true_boxes.shape[0] == 0:
                false_positives.append(entry)
        else:
            if true_boxes.shape[0] > 0:
                false_negatives = add_negative(false_negatives, entry,
                                               coord_data, opts.min_distance)

    # Find top rated entries
    scores = np.array(scores)
    scores = scores[np.argsort(scores[:, 1])[::-1]]

    for entry in scores[:, 0]:
        entry['coords'] = coord_data[os.path.split(entry['image'])[-1]]
    # Filter by proximity
    for i in range(scores.shape[0]):
        if scores[i][1] > 0:
            current_entry = scores[i][0]
            for j in range(i + 1, scores.shape[0]):
                second_entry = scores[j][0]
                dist = distance(
                    (current_entry['coords'][0], current_entry['coords'][1]),
                    (second_entry['coords'][0],
                     second_entry['coords'][1])).km * 1000
                if dist < opts.min_distance:
                    scores[j][1] = 0
    scores = scores[np.where(scores[:, 1] > 0)]
    top_entries = scores[np.argsort(scores[:, 1])[-opts.image_count:][::-1]]

    # Choose random negative samples
    false_samples = np.append(false_negatives, false_positives)
    np.random.shuffle(false_samples)

    # Visualize positive and negative samples
    rows_cols = (opts.image_count,
                 2) if opts.angle == 'ver' else (2, opts.image_count)
    plt_shape = (6., opts.image_count *
                 2.5) if opts.angle == 'ver' else (opts.image_count * 2.5, 6.)
    fig = plt.figure(1, plt_shape)

    grid = ImageGrid(
        fig,
        111,
        nrows_ncols=rows_cols,
        axes_pad=0.03,
        label_mode='L',
    )
    # Show top ranked images
    for i, result in enumerate(top_entries):
        entry = result[0]
        score = result[1]
        grid_idx = i
        if opts.angle == 'ver':
            grid_idx = i * 2
        # Load image and add bounding boxes
        im = cv2.imread(entry['image'])
        preds = entry['preds']
        true_boxes = entry['boxes']
        for bbox in true_boxes:
            im = vis_bbox(
                im, (bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]),
                _GT_COLOR, opts.box_thickness)
        count = 0
        for bbox in preds:
            if bbox[-1] > opts.threshold:
                count += 1
                print(
                    os.path.split(entry['image'])[-1] + ': ' + str(bbox[0:4]))
                im = vis_bbox(
                    im,
                    (bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]),
                    _PRED_COLOR, opts.box_thickness)
            if count >= opts.box_count:
                break
        # Adjust grid setting
        im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
        show_img(grid, im, grid_idx)
        t = grid[grid_idx].text(12,
                                42,
                                "Score: " + str(round(score, 3)),
                                fontsize=8,
                                bbox=dict(boxstyle='square',
                                          fc='white',
                                          ec='none',
                                          alpha=0.6))
        if i == 0:
            if opts.angle == 'ver':
                grid[grid_idx].set_title("Top\nPredictions", size=18)
            else:
                grid[grid_idx].set_ylabel("Top Predictions", fontsize=13)
    # Show random negative samples (false positive, false negative)
    for i, entry in enumerate(false_samples):
        if i >= opts.image_count:
            break
        grid_idx = opts.image_count + i
        if opts.angle == 'ver':
            grid_idx = 2 * i + 1
        # Load image and add bounding boxes
        im = cv2.imread(entry['image'])
        preds = entry['preds']
        true_boxes = entry['boxes']
        for bbox in true_boxes:
            im = vis_bbox(
                im, (bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]),
                _GT_COLOR, opts.box_thickness)
        for bbox in preds:
            if bbox[-1] > opts.threshold:
                im = vis_bbox(
                    im,
                    (bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]),
                    _PRED_COLOR, opts.box_thickness)
        # Adjust grid setting
        im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
        grid[grid_idx].imshow(im)
        grid[grid_idx].grid(False)
        grid[grid_idx].set_xticks([])
        grid[grid_idx].set_yticks([])
        if i == 0:
            if opts.angle == 'ver':
                grid[grid_idx].set_title("Errors", size=18)
            else:
                grid[grid_idx].set_ylabel("Errors", fontsize=13)
    plt.axis('off')
    plt.subplots_adjust(hspace=1)
    plt.savefig("ranking.png", dpi=300, bbox_inches='tight')
Exemplo n.º 16
0
# def plot_dist(dist,dist2=None):
#     fig,ax = plt.subplots()
#     plt_bars(dist, coco_classes, dist2, ax=ax)
#     plt.show()

if __name__ == '__main__':
    # workspace.GlobalInit(['caffe2', '--caffe2_log_level=0'])
    logger = setup_logging(__name__)
    args = parse_args()
    logger.info('Called with args:')
    logger.info(args)
    assert args.class_weights is not None, 'class_weights file required'
    print(str(args.class_weights[0]))

    coco_wts = load_object(args.class_weights[0])
    print(coco_wts.shape)
    coco_dist = get_dist(coco_wts)
    print("coco size: ", coco_wts.sum())

    assert args.voc_class_weights is not None, 'voc dist files needed'
    voc_files = args.voc_class_weights

    if args.do_val_set:
        voc_files = [
            'collecting/test/voc_2007_test/generalized_rcnn/class_weights.pkl',
            'collecting/test/voc_2012_val/generalized_rcnn/class_weights.pkl'
        ]
    voc_wts = np.concatenate([load_object(vocfile) for vocfile in voc_files],
                             axis=0)
Exemplo n.º 17
0
    def _add_proposals_from_file(self, roidb, proposal_file, min_proposal_size,
                                 top_k, crowd_thresh):
        """Add proposals from a proposals file to an roidb."""
        logger.info('Loading proposals from: {}'.format(proposal_file))
        proposals = load_object(proposal_file)

        id_field = 'indexes' if 'indexes' in proposals else 'ids'  # compat fix

        # _remove_proposals_not_in_roidb(proposals, roidb, id_field)
        _sort_proposals(proposals, id_field)
        box_list = []
        score_list = []
        total_roi = 0
        up_1024 = 0
        up_2048 = 0
        up_3072 = 0
        up_4096 = 0
        for i, entry in enumerate(roidb):
            if i % 2500 == 0:
                logger.info(' {:d}/{:d}'.format(i + 1, len(roidb)))
            boxes = proposals['boxes'][i]
            scores = proposals['scores'][i]
            # Sanity check that these boxes are for the correct image id
            assert entry['id'] == proposals[id_field][i]
            # Remove duplicate boxes and very small boxes and then take top k
            # boxes = box_utils.clip_boxes_to_image(
            # boxes, entry['height'], entry['width']
            # )
            assert (boxes[:, 0] >= 0).all()
            assert (boxes[:, 1] >= 0).all()
            assert (boxes[:, 2] >= boxes[:, 0]).all()
            assert (boxes[:, 3] >= boxes[:, 1]).all()
            assert (boxes[:, 2] < entry['width']).all(), entry['image']
            assert (boxes[:, 3] < entry['height']).all(), entry['image']

            keep = box_utils.unique_boxes(boxes)
            boxes = boxes[keep, :]
            scores = scores[keep]
            keep = box_utils.filter_small_boxes(boxes, min_proposal_size)
            boxes = boxes[keep, :]
            scores = scores[keep]

            # sort by confidence
            sorted_ind = np.argsort(-scores.flatten())
            boxes = boxes[sorted_ind, :]
            scores = scores[sorted_ind, :]

            if top_k > 0:
                boxes = boxes[:top_k, :]
                scores = scores[:top_k]

            total_roi += boxes.shape[0]
            if boxes.shape[0] > 1024:
                up_1024 += 1
            if boxes.shape[0] > 2048:
                up_2048 += 1
            if boxes.shape[0] > 3072:
                up_3072 += 1
            if boxes.shape[0] > 4096:
                up_4096 += 1

            box_list.append(boxes)
            score_list.append(scores)

        print('total_roi: ', total_roi, ' ave roi: ',
              total_roi / len(box_list))
        print('up_1024: ', up_1024)
        print('up_2048: ', up_2048)
        print('up_3072: ', up_3072)
        print('up_4096: ', up_4096)

        _merge_proposal_boxes_into_roidb(roidb, box_list, score_list)
        if crowd_thresh > 0:
            _filter_crowd_proposals(roidb, crowd_thresh)
Exemplo n.º 18
0
    def _add_pseudo_gt_annotations(self, roidb, gt_roidb):
        """
        Return the database of pseudo ground-truth regions of interest from detect result.

        This function loads/saves from/to a cache file to speed up future calls.
        """
        # gt_roidb = copy.deepcopy(roidb)
        # for entry in roidb:
        # self._add_gt_annotations(entry)

        assert 'train' in self.name or 'val' in self.name, 'Only trainval dataset has pseudo gt.'

        # detection.pkl is 0-based indices
        # the VOC result file is 1-based indices

        cache_files = cfg.PSEUDO_PATH
        if isinstance(cache_files, basestring):
            cache_files = (cache_files, )
        all_dets = None
        for cache_file in cache_files:
            if self.name not in cache_file:
                continue
            assert os.path.exists(cache_file), cache_file
            # with open(cache_file, 'rb') as fid:
            # res = cPickle.load(fid)
            res = load_object(cache_file)
            print('{} pseudo gt roidb loaded from {}'.format(
                self.name, cache_file))
            if all_dets is None:
                all_dets = res['all_boxes']
            else:
                for i in range(len(all_dets)):
                    all_dets[i].extend(res['all_boxes'][i])

        assert len(all_dets[1]) == len(roidb), len(all_dets[1])
        if len(all_dets) == self.num_classes:
            cls_offset = 0
        elif len(all_dets) + 1 == self.num_classes:
            cls_offset = -1
        else:
            raise Exception('Unknown mode.')

        threshold = 1.0

        for im_i, entry in enumerate(roidb):
            if im_i % 1000 == 0:
                print('{:d} / {:d}'.format(im_i + 1, len(roidb)))
            num_valid_objs = 0
            if len(gt_roidb[im_i]['gt_classes']) == 0:
                print(gt_roidb[im_i])
            if len(gt_roidb[im_i]['is_crowd']) == sum(
                    gt_roidb[im_i]['is_crowd']):
                print(gt_roidb[im_i])

            # when cfg.WSL = False, background class is in.
            # detection.pkl only has 20 classes
            # fast_rcnn need 21 classes
            for cls in range(1, self.num_classes):
                # TODO(YH): we need threshold the pseudo label
                # filter the pseudo label

                # self._gt_class has 21 classes
                # if self._gt_classes[ix][cls] == 0:
                if cls not in gt_roidb[im_i]['gt_classes']:
                    continue
                dets = all_dets[cls + cls_offset][im_i]
                if dets.shape[0] <= 0:
                    continue

                # TODO(YH): keep only one box
                # if dets.shape[0] > 0:
                # num_valid_objs += 1

                max_score = 0
                num_valid_objs_cls = 0
                for i in range(dets.shape[0]):
                    det = dets[i]

                    score = det[4]
                    if score > max_score:
                        max_score = score
                    if score < threshold:
                        continue
                    num_valid_objs += 1
                    num_valid_objs_cls += 1

                if num_valid_objs_cls == 0:
                    if max_score > 0:
                        num_valid_objs += 1

            boxes = np.zeros((num_valid_objs, 4), dtype=entry['boxes'].dtype)
            # obn_scores = np.zeros((num_valid_objs, 1), dtype=entry['obn_scores'].dtype)
            gt_classes = np.zeros((num_valid_objs),
                                  dtype=entry['gt_classes'].dtype)
            gt_overlaps = np.zeros((num_valid_objs, self.num_classes),
                                   dtype=entry['gt_overlaps'].dtype)
            seg_areas = np.zeros((num_valid_objs),
                                 dtype=entry['seg_areas'].dtype)
            is_crowd = np.zeros((num_valid_objs),
                                dtype=entry['is_crowd'].dtype)
            box_to_gt_ind_map = np.zeros(
                (num_valid_objs), dtype=entry['box_to_gt_ind_map'].dtype)

            obj_i = 0
            valid_segms = []
            for cls in range(1, self.num_classes):
                # filter the pseudo label
                # self._gt_class has 21 classes
                # if self._gt_classes[ix][cls] == 0:
                if cls not in gt_roidb[im_i]['gt_classes']:
                    continue
                dets = all_dets[cls + cls_offset][im_i]
                if dets.shape[0] <= 0:
                    continue

                max_score = 0
                max_score_bb = []
                num_valid_objs_cls = 0
                for i in range(dets.shape[0]):
                    det = dets[i]
                    x1 = det[0]
                    y1 = det[1]
                    x2 = det[2]
                    y2 = det[3]

                    score = det[4]
                    if score > max_score:
                        max_score = score
                        max_score_bb = [x1, y1, x2, y2]
                    if score < threshold:
                        continue

                    assert x1 >= 0
                    assert y1 >= 0
                    assert x2 >= x1
                    assert y2 >= y1
                    assert x2 < entry['width']
                    assert y2 < entry['height']

                    boxes[obj_i, :] = [x1, y1, x2, y2]
                    gt_classes[obj_i] = cls
                    seg_areas[obj_i] = (x2 - x1 + 1) * (y2 - y1 + 1)
                    is_crowd[obj_i] = 0
                    box_to_gt_ind_map[obj_i] = obj_i
                    gt_overlaps[obj_i, cls] = 1.0
                    valid_segms.append([])

                    obj_i += 1
                    num_valid_objs_cls += 1

                if num_valid_objs_cls == 0:
                    x1, y1, x2, y2 = max_score_bb[:]

                    assert x1 >= 0
                    assert y1 >= 0
                    assert x2 >= x1
                    assert y2 >= y1
                    assert x2 < entry['width']
                    assert y2 < entry['height']

                    boxes[obj_i, :] = [x1, y1, x2, y2]
                    gt_classes[obj_i] = cls
                    seg_areas[obj_i] = (x2 - x1 + 1) * (y2 - y1 + 1)
                    is_crowd[obj_i] = 0
                    box_to_gt_ind_map[obj_i] = obj_i
                    gt_overlaps[obj_i, cls] = 1.0
                    valid_segms.append([])

                    obj_i += 1

            assert obj_i == num_valid_objs

            # Show Pseudo GT boxes
            if True:
                # if False:
                import cv2
                im = cv2.imread(entry['image'])
                for obj_i in range(num_valid_objs):
                    cv2.rectangle(im, (boxes[obj_i][0], boxes[obj_i][1]),
                                  (boxes[obj_i][2], boxes[obj_i][3]),
                                  (255, 0, 0), 5)
                save_dir = os.path.join(cfg.OUTPUT_DIR, 'pgt')
                if not os.path.exists(save_dir):
                    os.makedirs(save_dir)
                save_path = os.path.join(save_dir, str(im_i) + '.png')
                # print(save_path)
                cv2.imwrite(save_path, im)

                # cv2.imshow('im', im)
                # cv2.waitKey()

            entry['boxes'] = np.append(entry['boxes'], boxes, axis=0)
            # entry['obn_scores'] = np.append(entry['obn_scores'], obn_scores, axis=0)
            entry['segms'].extend(valid_segms)
            # To match the original implementation:
            # entry['boxes'] = np.append(
            #     entry['boxes'], boxes.astype(np.int).astype(np.float), axis=0)
            entry['gt_classes'] = np.append(entry['gt_classes'], gt_classes)
            entry['seg_areas'] = np.append(entry['seg_areas'], seg_areas)
            entry['gt_overlaps'] = np.append(entry['gt_overlaps'].toarray(),
                                             gt_overlaps,
                                             axis=0)
            entry['gt_overlaps'] = scipy.sparse.csr_matrix(
                entry['gt_overlaps'])
            entry['is_crowd'] = np.append(entry['is_crowd'], is_crowd)
            entry['box_to_gt_ind_map'] = np.append(entry['box_to_gt_ind_map'],
                                                   box_to_gt_ind_map)
Exemplo n.º 19
0
                        help='Proposals file',
                        default='../output/temp_proposals_ss.pkl')


    args = parser.parse_args()
    args.image_file = os.path.abspath(args.image_file)
    args.proposals_file = os.path.abspath(args.proposals_file)
    return args


if __name__ == '__main__':
    args = parse_args()
    fig = plt.figure(figsize=(16, 6))

    # Load the proposals
    proposals = load_object(args.proposals_file)

    # print(len(proposals1['indexes']))
    # print(proposals2['ids'])

    # np.set_printoptions(threshold=np.nan)
    # for i in range(20):
    #     print(proposals1['boxes'][i][0:10,:])
    #     print('---------------------------')
    #     print(proposals2['boxes'][i][0:10,:])
    #     input('something')

    # print('Nucoco proposal keys:')
    # for key, value in proposals1.items() :
    #     print(key, value)
    #
def test_net(weights_file,
             dataset_name,
             proposal_file,
             output_dir,
             ind_range=None,
             gpu_id=0,
             subset_pointer=None):
    """Run inference on all images in a dataset or over an index range of images
    in a dataset using a single GPU.
    """
    assert not cfg.MODEL.RPN_ONLY, \
        'Use rpn_generate to generate proposals from RPN-only models'

    # determine file name
    if ind_range is not None:
        det_name = 'detection_range_%s_%s.pkl' % tuple(ind_range)
    else:
        det_name = 'detections.pkl'
    det_file = os.path.join(output_dir, det_name)

    # load results if already present
    if os.path.exists(det_file):
        res = load_object(det_file)
        all_boxes, all_segms, all_keyps = res['all_boxes'], res[
            'all_segms'], res['all_keyps']
    else:

        roidb, dataset, start_ind, end_ind, total_num_images = get_roidb_and_dataset(
            dataset_name, proposal_file, ind_range)

        if subset_pointer is not None:
            voc_subset = subset_pointer.subset
            this_sub = voc_subset[:len(roidb)]
            # subset_pointer.subset = voc_subset[len(roidb):]

            # filter roidb:
            roidb = [roi for taking, roi in zip(this_sub, roidb) if taking]

            total_num_images = len(roidb)
            end_ind = total_num_images

        model = initialize_model_from_cfg(weights_file, gpu_id=gpu_id)

        num_images = len(roidb)
        num_classes = cfg.MODEL.NUM_CLASSES

        all_boxes, all_segms, all_keyps = empty_results(
            num_classes, num_images)
        if cfg.TEST.COLLECT_ALL:
            all_feats = []
            all_class_weights = np.empty(shape=(num_images, num_classes),
                                         dtype=np.float32)

        timers = defaultdict(Timer)

        for i, entry in enumerate(roidb):
            if cfg.TEST.PRECOMPUTED_PROPOSALS:
                # The roidb may contain ground-truth rois (for example, if the roidb
                # comes from the training or val split). We only want to evaluate
                # detection on the *non*-ground-truth rois. We select only the rois
                # that have the gt_classes field set to 0, which means there's no
                # ground truth.
                box_proposals = entry['boxes'][entry['gt_classes'] == 0]
                if len(box_proposals) == 0:
                    continue
            else:
                # Faster R-CNN type models generate proposals on-the-fly with an
                # in-network RPN; 1-stage models don't require proposals.
                box_proposals = None

            im = cv2.imread(entry['image'])
            with c2_utils.NamedCudaScope(gpu_id):
                cls_boxes_i, cls_segms_i, cls_keyps_i, sum_softmax, topk_feats = im_detect_all(
                    model,
                    im,
                    box_proposals,
                    timers,
                    return_feats=cfg.TEST.COLLECT_ALL)

            # print('nfeats:', topk_feats.shape[0])
            # print(topk_feats)

            extend_results(i, all_boxes, cls_boxes_i)
            if cls_segms_i is not None:
                extend_results(i, all_segms, cls_segms_i)
            if cls_keyps_i is not None:
                extend_results(i, all_keyps, cls_keyps_i)

            if cfg.TEST.COLLECT_ALL:
                all_class_weights[i] = sum_softmax
                all_feats.append(
                    topk_feats
                )  # will accumulate about 9 Gb of feats on COCO train set (118K imgs)

            if i % 10 == 0:  # Reduce log file size
                ave_total_time = np.sum(
                    [t.average_time for t in timers.values()])
                eta_seconds = ave_total_time * (num_images - i - 1)
                eta = str(datetime.timedelta(seconds=int(eta_seconds)))
                det_time = (timers['im_detect_bbox'].average_time +
                            timers['im_detect_mask'].average_time +
                            timers['im_detect_keypoints'].average_time)
                misc_time = (timers['misc_bbox'].average_time +
                             timers['misc_mask'].average_time +
                             timers['misc_keypoints'].average_time)
                logger.info(('im_detect: range [{:d}, {:d}] of {:d}: '
                             '{:d}/{:d} {:.3f}s + {:.3f}s (eta: {})').format(
                                 start_ind + 1, end_ind, total_num_images,
                                 start_ind + i + 1, start_ind + num_images,
                                 det_time, misc_time, eta))

            if cfg.VIS:
                im_name = os.path.splitext(os.path.basename(entry['image']))[0]
                vis_utils.vis_one_image(im[:, :, ::-1],
                                        '{:d}_{:s}'.format(i, im_name),
                                        os.path.join(output_dir, 'vis'),
                                        cls_boxes_i,
                                        segms=cls_segms_i,
                                        keypoints=cls_keyps_i,
                                        thresh=cfg.VIS_TH,
                                        box_alpha=0.8,
                                        dataset=dataset,
                                        show_class=True)

        cfg_yaml = envu.yaml_dump(cfg)
        save_object(
            dict(all_boxes=all_boxes,
                 all_segms=all_segms,
                 all_keyps=all_keyps,
                 cfg=cfg_yaml), det_file)
        logger.info('Wrote detections to: {}'.format(
            os.path.abspath(det_file)))
        if cfg.TEST.COLLECT_ALL:
            save_object(all_class_weights,
                        os.path.join(output_dir, 'class_weights.pkl'))
            save_object(all_feats,
                        os.path.join(output_dir, 'feature_vectors.pkl'))
            logger.info(
                'Wrote class weights and feature vectors to output folder')

    return all_boxes, all_segms, all_keyps
Exemplo n.º 21
0
            fc6s = []
            fc7s = []
        max_classes = []
        gt_classes = []
        gt_classes_cnt = np.zeros(N, dtype=np.int32)
        cnt = 0
        cnt2 = 0
        for root, dirs, files in os.walk(dir_in, topdown=False):
            for name in files:
                if name.endswith('pkl'):
                    pass
                else:
                    continue
                print(cnt, os.path.join(root, name))
                path = os.path.join(root, name)
                pkl = load_object(path)

                roi_feat = pkl['roi_feats']
                if has_fc:
                    fc6 = pkl['fc6']
                    fc7 = pkl['fc7']

                gt_class = pkl['gt_classes']

                print(cnt, cnt2, 'roi_feat: ', roi_feat.shape)

                t = []
                for i in range(roi_feat.shape[0]):
                    if gt_class[i] in t:
                        # continue
                        pass
Exemplo n.º 22
0
def voc_eval_corloc(detpath,
                    annopath,
                    imagesetfile,
                    classname,
                    cachedir,
                    ovthresh=0.5,
                    use_07_metric=False):
    # assumes detections are in detpath.format(classname)
    # assumes annotations are in annopath.format(imagename)
    # assumes imagesetfile is a text file with each line an image name
    # cachedir caches the annotations in a pickle file

    # first load gt
    if not os.path.isdir(cachedir):
        os.mkdir(cachedir)
    imageset = os.path.splitext(os.path.basename(imagesetfile))[0]
    cachefile = os.path.join(cachedir, imageset + '_annots.pkl')
    # read list of images
    with open(imagesetfile, 'r') as f:
        lines = f.readlines()
    imagenames = [x.strip() for x in lines]

    if not os.path.isfile(cachefile):
        # load annots
        recs = {}
        for i, imagename in enumerate(imagenames):
            recs[imagename] = parse_rec(annopath.format(imagename))
            if i % 100 == 0:
                logger.info(
                    'Reading annotation for {:d}/{:d}'.format(
                        i + 1, len(imagenames)))
        # save
        logger.info('Saving cached annotations to {:s}'.format(cachefile))
        save_object(recs, cachefile)
    else:
        # load
        recs = load_object(cachefile)

    # extract gt objects for this class
    class_recs = {}
    npos = 0
    npos_im = 0
    for imagename in imagenames:
        R = [obj for obj in recs[imagename] if obj['name'] == classname]
        bbox = np.array([x['bbox'] for x in R])
        difficult = np.array([x['difficult'] for x in R]).astype(np.bool)
        det = [False] * len(R)
        npos = npos + sum(~difficult)
        class_recs[imagename] = {'bbox': bbox,
                                 'difficult': difficult,
                                 'det': det}
        if len(R) > 0:
            npos_im += min(1, sum(~difficult))

    # read dets
    detfile = detpath.format(classname)
    with open(detfile, 'r') as f:
        lines = f.readlines()
    if len(lines) == 0:
        return 0.0

    splitlines = [x.strip().split(' ') for x in lines]
    image_ids = [x[0] for x in splitlines]
    confidence = np.array([float(x[1]) for x in splitlines])
    BB = np.array([[float(z) for z in x[2:]] for x in splitlines])

    # sort by confidence
    sorted_ind = np.argsort(-confidence)
    sorted_scores = np.sort(-confidence)
    BB = BB[sorted_ind, :]
    image_ids = [image_ids[x] for x in sorted_ind]

    nd = len(image_ids)
    T = []
    F = []
    too_min = 0
    for d in range(nd):
        if image_ids[d] in T or image_ids[d] in F:
            continue
        R = class_recs[image_ids[d]]

        all_difficult = True
        for difficult in R['difficult']:
            if not difficult:
                all_difficult = False
        if all_difficult:
            continue

        bb = BB[d, :].astype(float)
        ovmax = -np.inf
        BBGT = R['bbox'].astype(float)

        if BBGT.size > 0:
            # compute overlaps
            # intersection
            ixmin = np.maximum(BBGT[:, 0], bb[0])
            iymin = np.maximum(BBGT[:, 1], bb[1])
            ixmax = np.minimum(BBGT[:, 2], bb[2])
            iymax = np.minimum(BBGT[:, 3], bb[3])
            iw = np.maximum(ixmax - ixmin + 1., 0.)
            ih = np.maximum(iymax - iymin + 1., 0.)
            inters = iw * ih

            # union
            uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                   (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                   (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

            overlaps = inters / uni
            ovmax = np.max(overlaps)
            jmax = np.argmax(overlaps)

        if ovmax > ovthresh:
            T.append(image_ids[d])
        else:
            F.append(image_ids[d])

            uni = (bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.)
            overlaps = inters / uni
            ovmax = np.max(overlaps)
            if ovmax > ovthresh:
                too_min += 1

    if len(F) == 0:
        too_min_rate = 0.0
    else:
        too_min_rate = 1.0 * too_min / len(F)
    print('npos_im: ', npos_im, '#F: ', len(F), ' too_min: ', too_min, ' rate: ', too_min_rate)

    return 1.0 * len(T) / npos_im, too_min_rate
Exemplo n.º 23
0
import numpy as np
import os
import sys

from detectron.utils.io import save_object
from detectron.utils.io import load_object

if __name__ == '__main__':
    original_weights_file = sys.argv[1]
    file_out = sys.argv[2]

    out_blobs = {}

    used_blobs = set()

    original_src_blobs = load_object(original_weights_file)

    print('====================================')
    print('get params in original weights')
    for blob_name in sorted(original_src_blobs.keys()):
        if 'bn_s' in blob_name:
            pass
        else:
            continue

        bn_name = blob_name.rsplit('_', 1)[0]
        conv_name = blob_name.rsplit('_', 2)[0]
        if 'res_conv1_bn_s' in blob_name:
            conv_name = 'conv1'

        bn_s_name = blob_name
Exemplo n.º 24
0
def grid_search():
    dataset_name, proposal_file = get_inference_dataset(0, is_parent=False)
    roidb, dataset, start_ind, end_ind, total_num_images = get_roidb_and_dataset(
        dataset_name, proposal_file, None 
    )
    num_images = len(roidb)
    num_classes = cfg.MODEL.NUM_CLASSES
    subinds = np.array_split(range(num_images), cfg.NUM_GPUS)

    tag = 'detection'
    output_dir = get_output_dir(cfg.TEST.DATASETS, training=False)

    det_file = os.path.join(output_dir, 'detections.pkl')
    outputs = load_object(det_file)

    print(len(outputs))
    all_dets_cache = outputs['all_boxes']
    print(len(all_dets_cache))

    all_boxes_cache = []
    all_scores_cache = []
    for i, entry in enumerate(roidb):
        print(i)
        max_det = all_dets_cache[1][i].shape[0]
        print(max_det, num_classes)
        
        boxes = np.zeros((max_det, 4), dtype=np.float32)
        scores = np.zeros((max_det, num_classes), dtype=np.float32)
        boxes[:] = -1
        scores[:] = -1
        for j in range(num_classes):
            if len(all_dets_cache[j]) > 0:
                pass
            else:
                continue
            scores[:, j] = all_dets_cache[j][i][:, 4]
        boxes[:, 0:4] = all_dets_cache[1][i][:, :4]
        boxes = np.tile(boxes, (1, scores.shape[1]))
        print(scores.shape, boxes.shape)
        all_boxes_cache.append(boxes)
        all_scores_cache.append(scores)

    timers = defaultdict(Timer)
    resultss = []
    nmses = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]
    threshs = [1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1]
    max_per_images = [10000, 1000, 100, 10, 1]

    for nms in nmses:
        for thresh in threshs:
            for max_per_image in max_per_images:
                print("----------------------------------------------------")
                print('NUM: ', nms, ' Thresh: ', thresh, ' MAX_PER_IM: ', max_per_image)
                cfg.immutable(False)
                cfg.TEST.NMS = nms
                cfg.TEST.SCORE_THRESH = thresh
                cfg.TEST.DETECTIONS_PER_IM = max_per_image
                cfg.immutable(True)

                all_boxes, all_segms, all_keyps = empty_results(num_classes, num_images)
                for i, entry in enumerate(roidb):
                    # print(i)
                    timers['im_detect_bbox'].tic()
                    scores = all_scores_cache[i]
                    boxes = all_boxes_cache[i]
                    # print(scores.shape, boxes.shape)

                    timers['im_detect_bbox'].toc()

                    timers['misc_bbox'].tic()
                    scores, boxes, cls_boxes_i = box_results_with_nms_and_limit(scores, boxes)
                    timers['misc_bbox'].toc()

                    extend_results(i, all_boxes, cls_boxes_i)

                results = task_evaluation.evaluate_all(
                    dataset, all_boxes, all_segms, all_keyps, output_dir
                )
                print(results)

    print(resultss)
    f = open('grid_search.csv', 'wb')
    wr = csv.writer(f, dialect='excel')
    wr.writerows(resultss)
Exemplo n.º 25
0
def process_in_parallel(
    tag, total_range_size, binary, output_dir, opts=''
):
    """Run the specified binary cfg.NUM_GPUS times in parallel, each time as a
    subprocess that uses one GPU. The binary must accept the command line
    arguments `--range {start} {end}` that specify a data processing range.
    """
    # Snapshot the current cfg state in order to pass to the inference
    # subprocesses
    cfg_file = os.path.join(output_dir, '{}_range_config.yaml'.format(tag))
    with open(cfg_file, 'w') as f:
        envu.yaml_dump(cfg, stream=f)
    subprocess_env = os.environ.copy()
    processes = []
    subinds = np.array_split(range(total_range_size), cfg.NUM_GPUS)
    # Determine GPUs to use
    cuda_visible_devices = os.environ.get('CUDA_VISIBLE_DEVICES')
    if cuda_visible_devices:
        gpu_inds = map(int, cuda_visible_devices.split(','))
        assert -1 not in gpu_inds, \
            'Hiding GPU indices using the \'-1\' index is not supported'
    else:
        gpu_inds = range(cfg.NUM_GPUS)
    # Run the binary in cfg.NUM_GPUS subprocesses
    for i, gpu_ind in enumerate(gpu_inds):
        start = subinds[i][0]
        end = subinds[i][-1] + 1
        subprocess_env['CUDA_VISIBLE_DEVICES'] = str(gpu_ind)
        cmd = '{binary} --range {start} {end} --cfg {cfg_file} NUM_GPUS 1 {opts}'
        cmd = cmd.format(
            binary=shlex_quote(binary),
            start=int(start),
            end=int(end),
            cfg_file=shlex_quote(cfg_file),
            opts=' '.join([shlex_quote(opt) for opt in opts])
        )
        logger.info('{} range command {}: {}'.format(tag, i, cmd))
        if i == 0:
            subprocess_stdout = subprocess.PIPE
        else:
            filename = os.path.join(
                output_dir, '%s_range_%s_%s.stdout' % (tag, start, end)
            )
            subprocess_stdout = open(filename, 'w')  # NOQA (close below)
        p = subprocess.Popen(
            cmd,
            shell=True,
            env=subprocess_env,
            stdout=subprocess_stdout,
            stderr=subprocess.STDOUT,
            bufsize=1
        )
        processes.append((i, p, start, end, subprocess_stdout))
    # Log output from inference processes and collate their results
    outputs = []
    for i, p, start, end, subprocess_stdout in processes:
        log_subprocess_output(i, p, output_dir, tag, start, end)
        if i > 0:
            subprocess_stdout.close()
        range_file = os.path.join(
            output_dir, '%s_range_%s_%s.pkl' % (tag, start, end)
        )
        range_data = load_object(range_file)
        outputs.append(range_data)
    return outputs
Exemplo n.º 26
0
def complete_stats(dataset, detections_pkl, threshold, box_idx, long_output=True):
	# Load predictions and ground truths
	ds = JsonDataset(dataset)
	roidb = ds.get_roidb(gt=True)
	dets = load_object(detections_pkl)
	all_boxes = dets['all_boxes']

	def id_or_index(ix, val):
		if len(val) == 0:
			return val
		else:
			return val[ix]

	true_positives = 0
	true_negatives = 0
	false_positives = 0
	false_negatives = 0
	total = len(roidb)
	# Iterate through all images
	for ix, entry in enumerate(roidb):
		cls_boxes_i = [
			id_or_index(ix, cls_k_boxes) for cls_k_boxes in all_boxes
		]
		preds = np.array(cls_boxes_i[box_idx])
		true_boxes = entry['boxes']
		# Check if the images resulted in a true/false positive/negative
		if (true_boxes.shape[0] == 0):
			if preds.shape[0] > 0 and np.max(preds[:,4]) > threshold:
				false_positives += 1
			else:
				true_negatives += 1
		else:
			if preds.shape[0] > 0 and np.max(preds[:,4]) > threshold:
				true_positives += 1			
			else:
				false_negatives += 1

	# Calculate the statistics
	prec = float('nan')
	if true_positives+false_positives > 0:
		prec = true_positives/float(true_positives+false_positives)
	elif false_negatives == 0:
		prec = 1.
	rec = float('nan')
	if true_positives+false_negatives > 0:
		rec = true_positives/float(true_positives+false_negatives)
	elif false_positives == 0:
		rec = 1.
	acc = float(true_positives+true_negatives)/total
	fm = 0
	if prec > 0 or rec > 0:
		fm = 2.0*prec*rec/(prec+rec)
	# Re-enable printing
	enablePrint()
	# Print results
	if (long_output):
		print("True positives: {}\tFalse positives: {}".format(true_positives, false_positives))
		print("True negatives: {}\tFalse negatives: {}".format(true_negatives, false_negatives))
		print("Total: {}".format(total))
		print("Precision: " + str(prec*100))
		print("Recall: " + str(rec*100))
		print("F-measure: " + str(fm*100))
		print("Accuracy: " + str(acc*100))
	else:
		print("{};{};{};{};".format(acc, prec, rec, fm))
	return acc
Exemplo n.º 27
0
import os
from time import strftime

from detectron.datasets.json_dataset_wsl import JsonDataset

import matplotlib as mpl
import matplotlib.pyplot as plt

from detectron.utils.io import save_object
from detectron.utils.io import load_object

if __name__ == '__main__':
    net_1 = sys.argv[1]
    net_2 = sys.argv[2]

    pkl_1 = load_object(net_1)
    pkl_2 = load_object(net_2)

    if 'blobs' in pkl_1.keys():
        pkl_1 = pkl_1['blobs']
    if 'blobs' in pkl_2.keys():
        pkl_2 = pkl_2['blobs']

    print(pkl_1.keys())
    print(pkl_2.keys())

    for key in sorted(pkl_1.keys()):
        if 'momentum' in key:
            continue

        if key.endswith('_b'):
def load_and_convert_PubLayNet_model(args):
    model_dict = load_object(args.PubLayNet_model_file_name)
    remove_momentum(model_dict)
    convert_PubLayNet_blobs_to_target_blobs(model_dict)
    return model_dict
Exemplo n.º 29
0
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import numpy as np
import os
import sys
from collections import OrderedDict

from six.moves import cPickle as pickle
from detectron.utils.io import save_object
from detectron.utils.io import load_object

if __name__ == '__main__':

    in_path = sys.argv[1]
    out_path = sys.argv[2]

    pkl_data = load_object(in_path)

    pkl_data = pkl_data['blobs']
    keys = pkl_data.keys()

    for k in list(keys):
        if 'momentum' in k:
            print('delete ', k)
            t = pkl_data.pop(k, None)

    save_object(pkl_data, out_path)
Exemplo n.º 30
0
        help='Proposals file 2',
        default='../output/proposals/nucoco_sw_f/eb/proposals_nucoco_train.pkl'
    )

    args = parser.parse_args()
    return args


if __name__ == '__main__':
    args = parse_args()
    fig = plt.figure(figsize=(16, 6))

    coco = COCO_PLUS(args.ann_file, args.imgs_dir)

    # Load the proposals
    proposals1 = load_object(args.proposals_file1)
    proposals2 = load_object(args.proposals_file2)
    num_imgs = len(proposals1['ids'])
    assert len(proposals1['ids']) == len(proposals2['ids']), \
        "Number of images are different in proposal files"

    # print(len(proposals1['indexes']))
    # print(proposals2['ids'])

    # np.set_printoptions(threshold=np.nan)
    # for i in range(20):
    #     print(proposals1['boxes'][i][0:10,:])
    #     print('---------------------------')
    #     print(proposals2['boxes'][i][0:10,:])
    #     input('something')
Exemplo n.º 31
0
def initialize_gpu_from_weights_file(model, weights_file, gpu_id=0):
    """Initialize a network with ops on a specific GPU.

    If you use CUDA_VISIBLE_DEVICES to target specific GPUs, Caffe2 will
    automatically map logical GPU ids (starting from 0) to the physical GPUs
    specified in CUDA_VISIBLE_DEVICES.
    """
    logger.info('Loading weights from: {}'.format(weights_file))
    ws_blobs = workspace.Blobs()
    src_blobs = load_object(weights_file)

    if 'cfg' in src_blobs:
        saved_cfg = load_cfg(src_blobs['cfg'])
        configure_bbox_reg_weights(model, saved_cfg)
    if 'blobs' in src_blobs:
        # Backwards compat--dictionary used to be only blobs, now they are
        # stored under the 'blobs' key
        src_blobs = src_blobs['blobs']
    # Initialize weights on GPU gpu_id only
    unscoped_param_names = OrderedDict()  # Print these out in model order
    for blob in model.params:
        unscoped_param_names[c2_utils.UnscopeName(str(blob))] = True
    with c2_utils.NamedCudaScope(gpu_id):
        for unscoped_param_name in unscoped_param_names.keys():
            if (unscoped_param_name.find(']_') >= 0
                    and unscoped_param_name not in src_blobs):
                # Special case for sharing initialization from a pretrained
                # model:
                # If a blob named '_[xyz]_foo' is in model.params and not in
                # the initialization blob dictionary, then load source blob
                # 'foo' into destination blob '_[xyz]_foo'
                src_name = unscoped_param_name[unscoped_param_name.find(']_') +
                                               2:]
            else:
                src_name = unscoped_param_name
            if src_name not in src_blobs:
                logger.info('{:s} not found'.format(src_name))
                continue
            dst_name = core.ScopedName(unscoped_param_name)
            has_momentum = src_name + '_momentum' in src_blobs
            has_momentum_str = ' [+ momentum]' if has_momentum else ''
            logger.info(
                '{:s}{:} loaded from weights file into {:s}: {}'.format(
                    src_name, has_momentum_str, dst_name,
                    src_blobs[src_name].shape))
            if dst_name in ws_blobs:
                # If the blob is already in the workspace, make sure that it
                # matches the shape of the loaded blob
                ws_blob = workspace.FetchBlob(dst_name)
                assert ws_blob.shape == src_blobs[src_name].shape, \
                    ('Workspace blob {} with shape {} does not match '
                     'weights file shape {}').format(
                        src_name,
                        ws_blob.shape,
                        src_blobs[src_name].shape)
            workspace.FeedBlob(
                dst_name, src_blobs[src_name].astype(np.float32, copy=False))
            if has_momentum:
                workspace.FeedBlob(
                    dst_name + '_momentum',
                    src_blobs[src_name + '_momentum'].astype(np.float32,
                                                             copy=False))

    # We preserve blobs that are in the weights file but not used by the current
    # model. We load these into CPU memory under the '__preserve__/' namescope.
    # These blobs will be stored when saving a model to a weights file. This
    # feature allows for alternating optimization of Faster R-CNN in which blobs
    # unused by one step can still be preserved forward and used to initialize
    # another step.
    for src_name in src_blobs.keys():
        if (src_name not in unscoped_param_names
                and not src_name.endswith('_momentum')
                and src_blobs[src_name] is not None):
            with c2_utils.CpuScope():
                workspace.FeedBlob('__preserve__/{:s}'.format(src_name),
                                   src_blobs[src_name])
                logger.info(
                    '{:s} preserved in workspace (unused)'.format(src_name))
def load_and_convert_coco_model(args):
    model_dict = load_object(args.coco_model_file_name)
    remove_momentum(model_dict)
    convert_coco_blobs_to_cityscape_blobs(model_dict)
    return model_dict
Exemplo n.º 33
0
def voc_eval(detpath,
             annopath,
             imagesetfile,
             classname,
             cachedir,
             ovthresh=0.5,
             use_07_metric=False,
             subset_pointer=None):
    """rec, prec, ap = voc_eval(detpath,
                                annopath,
                                imagesetfile,
                                classname,
                                [ovthresh],
                                [use_07_metric])

    Top level function that does the PASCAL VOC evaluation.

    detpath: Path to detections
        detpath.format(classname) should produce the detection results file.
    annopath: Path to annotations
        annopath.format(imagename) should be the xml annotations file.
    imagesetfile: Text file containing the list of images, one image per line.
    classname: Category name (duh)
    cachedir: Directory for caching the annotations
    [ovthresh]: Overlap threshold (default = 0.5)
    [use_07_metric]: Whether to use VOC07's 11 point AP computation
        (default False)
    """
    # assumes detections are in detpath.format(classname)
    # assumes annotations are in annopath.format(imagename)
    # assumes imagesetfile is a text file with each line an image name
    # cachedir caches the annotations in a pickle file
    
    this_sub = None
    if subset_pointer is not None:
        this_sub = subset_pointer.subset
    
    # first load gt
    if not os.path.isdir(cachedir):
        os.mkdir(cachedir)
    imageset = os.path.splitext(os.path.basename(imagesetfile))[0]
    cachefile = os.path.join(cachedir, imageset + '_annots.pkl')
    # read list of images
    with open(imagesetfile, 'r') as f:
        lines = f.readlines()
    imagenames = [x.strip() for x in lines]
    if subset_pointer is not None:
        imagenames = [n for n,taken in zip(imagenames,this_sub) if taken]

    if not os.path.isfile(cachefile):
        # load annots
        recs = {}
        for i, imagename in enumerate(imagenames):
            recs[imagename] = parse_rec(annopath.format(imagename))
            if i % 100 == 0:
                logger.info(
                    'Reading annotation for {:d}/{:d}'.format(
                        i + 1, len(imagenames)))
        # save
        logger.info('Saving cached annotations to {:s}'.format(cachefile))
        save_object(recs, cachefile)
    else:
        recs = load_object(cachefile)

    # extract gt objects for this class
    class_recs = {}
    npos = 0
    for imagename in imagenames:
        R = [obj for obj in recs[imagename] if obj['name'] == classname]
        bbox = np.array([x['bbox'] for x in R])
        difficult = np.array([x['difficult'] for x in R]).astype(np.bool)
        det = [False] * len(R)
        npos = npos + sum(~difficult)
        class_recs[imagename] = {'bbox': bbox,
                                 'difficult': difficult,
                                 'det': det}

    # read dets
    detfile = detpath.format(classname)
    with open(detfile, 'r') as f:
        lines = f.readlines()

    splitlines = [x.strip().split(' ') for x in lines]
    image_ids = [x[0] for x in splitlines]
    confidence = np.array([float(x[1]) for x in splitlines])
    BB = np.array([[float(z) for z in x[2:]] for x in splitlines])

    # sort by confidence
    sorted_ind = np.argsort(-confidence)
    BB = BB[sorted_ind, :]
    image_ids = [image_ids[x] for x in sorted_ind]

    # go down dets and mark TPs and FPs
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)
    for d in range(nd):
        R = class_recs[image_ids[d]]
        bb = BB[d, :].astype(float)
        ovmax = -np.inf
        BBGT = R['bbox'].astype(float)

        if BBGT.size > 0:
            # compute overlaps
            # intersection
            ixmin = np.maximum(BBGT[:, 0], bb[0])
            iymin = np.maximum(BBGT[:, 1], bb[1])
            ixmax = np.minimum(BBGT[:, 2], bb[2])
            iymax = np.minimum(BBGT[:, 3], bb[3])
            iw = np.maximum(ixmax - ixmin + 1., 0.)
            ih = np.maximum(iymax - iymin + 1., 0.)
            inters = iw * ih

            # union
            uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                   (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                   (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

            overlaps = inters / uni
            ovmax = np.max(overlaps)
            jmax = np.argmax(overlaps)

        if ovmax > ovthresh:
            if not R['difficult'][jmax]:
                if not R['det'][jmax]:
                    tp[d] = 1.
                    R['det'][jmax] = 1
                else:
                    fp[d] = 1.
        else:
            fp[d] = 1.

    # compute precision recall
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    rec = tp / float(npos)
    # avoid divide by zero in case the first detection matches a difficult
    # ground truth
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    ap = voc_ap(rec, prec, use_07_metric)

    return rec, prec, ap, npos
Exemplo n.º 34
0
def initialize_gpu_from_weights_file(model, weights_file, gup_id=0):
    logger.info('Loading weights from: {}'.format(weights_file))
    ws_blobs = workspace.Blobs()
    src_blobs = load_object(weights_file)

    if 'cfg' in src_blobs:
        saved_cfg = load_cfg(src_blobs['cfg'])
        configure_bbox_reg_weights(model, saved_cfg)
    if 'blobs' in src_blobs:
        src_blobs = src_blobs['blobs']

    unscoped_para_names = OrderedDict()
    for blob in model.params:
        unscoped_para_names[c2_utils.UnscopeName(str(blob))] = True
    with c2_utils.NamedCudaScope(gup_id):
        for unscoped_para_name in unscoped_para_names.keys():
            if (unscoped_para_name.find(']_') >= 0
                    and unscoped_para_name not in src_blobs):
                # Special case for sharing initialization from a pretrained
                # model:
                # If a blob named '_[xyz]_foo' is in model.params and not in
                # the initialization blob dictionary, then load source blob
                # 'foo' into destination blob '_[xyz]_foo'
                src_name = unscoped_para_name[unscoped_para_name.find((']_') +
                                                                      2)]
            else:
                src_name = unscoped_para_name
            if src_name not in src_blobs:
                logger.info('{:s} not found.'.format(src_name))
                continue
            dst_name = core.ScopedName(unscoped_para_name)
            has_momentum = src_name + '_momentum' in src_blobs
            has_momentum_str = ' [+ momentum] ' if has_momentum else ''
            logger.info(
                '{:s}{:} loaded form weights file into {:s}: {}'.format(
                    src_name, has_momentum_str, dst_name,
                    src_blobs[src_name].shape))
            if dst_name in ws_blobs:
                # if the blob is already in the workspace, make sure that it matches
                # the shape of the loaded blob
                ws_blob = workspace.FetchBlob(dst_name)
                assert ws_blob.shape == src_blobs[src_name].shape, \
                    ('Workspace blob {} with shape {} does not match '
                     'weights file shape {}').format(
                    src_name,
                    ws_blob.shape,
                    src_blobs[src_name].shape)
            workspace.FeedBlob(
                dst_name, src_blobs[src_name].astype(np.float32, copy=False))
            if has_momentum:
                workspace.FeedBlob(
                    dst_name + '_momentum',
                    src_blobs[src_name + '_momentum'].astype(np.float32,
                                                             copy=False))

    for src_name in src_blobs.keys():
        if (src_name not in unscoped_para_names
                and not src_name.endswith('_momentum')
                and src_blobs[src_name] is not None):
            with c2_utils.CpuScope():
                workspace.FeedBlob('__presever__/{:s}'.format(src_name),
                                   src_blobs[src_name])
                logger.info(
                    '{:s} preserved in workspace (unused)'.format(src_name))
Exemplo n.º 35
0
        dest='input_model',
        help='Trained model weights',
        default='../output/models/R_50_C4_2x_original/model_final.pkl')
    parser.add_argument(
        '--output_model',
        dest='output_model',
        help='Ouput model weights',
        default='../output/models/R_50_C4_2x_original_RW/model_final.pkl')

    args = parser.parse_args()
    args.input_model = os.path.abspath(args.input_model)
    args.output_model = os.path.abspath(args.output_model)

    return args


if __name__ == '__main__':
    args = parse_args()
    out_dir = os.path.dirname(args.output_model)
    os.makedirs(out_dir, exist_ok=True)

    wts = load_object(args.input_model)

    for blob in list(wts['blobs'].keys()):
        if blob.startswith('cls_score_') or blob.startswith('bbox_pred_'):
            del wts['blobs'][blob]

    save_object(wts, args.output_model)
    #with open(args.output_model, 'wb') as f:
    #    pkl.dump(wts, f)
Exemplo n.º 36
0
def voc_eval(detpath,
             annopath,
             imagesetfile,
             classname,
             cachedir,
             ovthresh=0.5,
             use_07_metric=False):
    """rec, prec, ap = voc_eval(detpath,
                                annopath,
                                imagesetfile,
                                classname,
                                [ovthresh],
                                [use_07_metric])

    Top level function that does the PASCAL VOC evaluation.

    detpath: Path to detections
        detpath.format(classname) should produce the detection results file.
    annopath: Path to annotations
        annopath.format(imagename) should be the xml annotations file.
    imagesetfile: Text file containing the list of images, one image per line.
    classname: Category name (duh)
    cachedir: Directory for caching the annotations
    [ovthresh]: Overlap threshold (default = 0.5)
    [use_07_metric]: Whether to use VOC07's 11 point AP computation
        (default False)
    """
    # assumes detections are in detpath.format(classname)
    # assumes annotations are in annopath.format(imagename)
    # assumes imagesetfile is a text file with each line an image name
    # cachedir caches the annotations in a pickle file

    # first load gt
    if not os.path.isdir(cachedir):
        os.mkdir(cachedir)
    imageset = os.path.splitext(os.path.basename(imagesetfile))[0]
    cachefile = os.path.join(cachedir, imageset + '_annots.pkl')
    # read list of images
    with open(imagesetfile, 'r') as f:
        lines = f.readlines()
    imagenames = [x.strip() for x in lines]

    if not os.path.isfile(cachefile):
        # load annots
        recs = {}
        for i, imagename in enumerate(imagenames):
            recs[imagename] = parse_rec(annopath.format(imagename))
            if i % 100 == 0:
                logger.info(
                    'Reading annotation for {:d}/{:d}'.format(
                        i + 1, len(imagenames)))
        # save
        logger.info('Saving cached annotations to {:s}'.format(cachefile))
        save_object(recs, cachefile)
    else:
        recs = load_object(cachefile)

    # extract gt objects for this class
    class_recs = {}
    npos = 0
    for imagename in imagenames:
        R = [obj for obj in recs[imagename] if obj['name'] == classname]
        bbox = np.array([x['bbox'] for x in R])
        difficult = np.array([x['difficult'] for x in R]).astype(np.bool)
        det = [False] * len(R)
        npos = npos + sum(~difficult)
        class_recs[imagename] = {'bbox': bbox,
                                 'difficult': difficult,
                                 'det': det}

    # read dets
    detfile = detpath.format(classname)
    with open(detfile, 'r') as f:
        lines = f.readlines()

    splitlines = [x.strip().split(' ') for x in lines]
    image_ids = [x[0] for x in splitlines]
    confidence = np.array([float(x[1]) for x in splitlines])
    BB = np.array([[float(z) for z in x[2:]] for x in splitlines])

    # sort by confidence
    sorted_ind = np.argsort(-confidence)
    BB = BB[sorted_ind, :]
    image_ids = [image_ids[x] for x in sorted_ind]

    # go down dets and mark TPs and FPs
    nd = len(image_ids)
    tp = np.zeros(nd)
    fp = np.zeros(nd)
    for d in range(nd):
        R = class_recs[image_ids[d]]
        bb = BB[d, :].astype(float)
        ovmax = -np.inf
        BBGT = R['bbox'].astype(float)

        if BBGT.size > 0:
            # compute overlaps
            # intersection
            ixmin = np.maximum(BBGT[:, 0], bb[0])
            iymin = np.maximum(BBGT[:, 1], bb[1])
            ixmax = np.minimum(BBGT[:, 2], bb[2])
            iymax = np.minimum(BBGT[:, 3], bb[3])
            iw = np.maximum(ixmax - ixmin + 1., 0.)
            ih = np.maximum(iymax - iymin + 1., 0.)
            inters = iw * ih

            # union
            uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                   (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                   (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)

            overlaps = inters / uni
            ovmax = np.max(overlaps)
            jmax = np.argmax(overlaps)

        if ovmax > ovthresh:
            if not R['difficult'][jmax]:
                if not R['det'][jmax]:
                    tp[d] = 1.
                    R['det'][jmax] = 1
                else:
                    fp[d] = 1.
        else:
            fp[d] = 1.

    # compute precision recall
    fp = np.cumsum(fp)
    tp = np.cumsum(tp)
    rec = tp / float(npos)
    # avoid divide by zero in case the first detection matches a difficult
    # ground truth
    prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
    ap = voc_ap(rec, prec, use_07_metric)

    return rec, prec, ap