示例#1
0
def loss_clc(truth_box,gt_lables):
    true_box, non_ze = utils.trim_zeros_graph(truth_box)
    gt_lables = tf.boolean_mask(gt_lables, non_ze)
    priors = utils.get_prio_box()
    priors_xywh = tf.concat((priors[:, :2] - priors[:, 2:] / 2,
               priors[:, :2] + priors[:, 2:] / 2), axis=1)
    ops = utils.overlaps_graph(true_box,priors_xywh)
    # 获取prior box 最佳匹配index size = trueth
    best_prior_idx = tf.argmax(ops,axis=1)
    # 获取truth box 最佳匹配index size = prior
    best_truth_idx = tf.argmax(ops,axis=0)
    best_truth_overlab = tf.reduce_max(ops,axis=0)
    matches = tf.gather(truth_box,best_truth_idx)
    conf = tf.gather(gt_lables,best_truth_idx)
    conf = tf.cast(conf,tf.float32)
    zer = tf.zeros(shape=(tf.shape(conf)),dtype=tf.float32)
    conf = tf.where(tf.less(best_truth_overlab,0.5),zer,conf)
    loc = utils.encode_box(matched=matches,prios=priors)
    return conf,loc
示例#2
0
def detect_target(proposals, gt_class_ids, gt_boxes, gt_masks, config):
    """
	Generates detection targets for one image. Subsamples proposals and
	generates target class IDs, bounding box deltas, and masks for each.

	Inputs:
	proposals: [POST_NMS_ROIS_TRAINING, (y1, x1, y2, x2)] in normalized coordinates. Might
	           be zero padded if there are not enough proposals.
	gt_class_ids: [MAX_GT_INSTANCES] int class IDs
	gt_boxes: [MAX_GT_INSTANCES, (y1, x1, y2, x2)] in normalized coordinates.
	gt_masks: [MAX_GT_INSTANCES, height, width] of boolean type.

	Returns: Target ROIs and corresponding class IDs, bounding box shifts,
	and masks.
	rois: [TRAIN_ROIS_PER_IMAGE, (y1, x1, y2, x2)] in normalized coordinates
	class_ids: [TRAIN_ROIS_PER_IMAGE]. Integer class IDs. Zero padded.
	deltas: [TRAIN_ROIS_PER_IMAGE, (dy, dx, log(dh), log(dw))]
	masks: [TRAIN_ROIS_PER_IMAGE, height, width]. Masks cropped to bbox
	       boundaries and resized to neural network output size.

	Note: Returned arrays might be zero padded if not enough target ROIs.
	"""
    # Assertions
    asserts = [tf.Assert(tf.greater(tf.shape(proposals)[0], 0), [proposals],\
       name = 'roi_assertion')]
    with tf.control_dependencies(asserts):
        proposals = tf.identity(proposals)

    # Remove zero padding
    proposals, _ = utils.trim_zeros_graph(proposals, name='trim_proposals')
    gt_boxes, non_zeros = utils.trim_zeros_graph(gt_boxes,
                                                 name='trim_gt_boxes')
    gt_class_ids = tf.boolean_mask(gt_class_ids, non_zeros,\
            name='trim_gt_class_ids')
    gt_masks = tf.gather(gt_masks, tf.where(non_zeros)[:,0], axis=2,\
          name='trim_gt_masks')
    # Compute overlaps matrix [proposals, gt_boxes]
    overlaps = utils.overlaps_graph(proposals, gt_boxes)

    # Determin positive and negative ROIs
    roi_iou_max = tf.reduce_max(overlaps, axis=1)

    # 1. Positive ROIs are those with >= 0.5 IoU with a GT box
    positive_roi_bool = (roi_iou_max >= 0.5)
    positive_indices = tf.where(positive_roi_bool)[:, 0]
    # 2. Negative ROIs are those with < 0.5 with every GT box.
    negative_indices = tf.where(roi_iou_max < 0.5)[:, 0]
    # Subsample ROIs, Aim for 33% positive
    # Positive ROIs
    positive_count = int(config.TRAIN_ROIS_PER_IMAGE *
                         config.ROI_POSITIVE_RATIO)
    positive_indices = tf.random_shuffle(positive_indices)[:positive_count]
    positive_count = tf.shape(positive_indices)[0]
    # Negative ROIs. Add enough to maintain positive:negative ratio
    r = 1.0 / config.ROI_POSITIVE_RATIO
    negative_count = tf.cast(r * tf.cast(positive_count, tf.float32), tf.int32)\
         - positive_count
    negative_indices = tf.random_shuffle(negative_indices)[:negative_count]
    # Gather selected ROIs
    positive_rois = tf.gather(proposals, positive_indices)
    negative_rois = tf.gather(proposals, negative_indices)

    # Assign positive ROIs to GT boxes
    positive_overlaps = tf.gather(overlaps, positive_indices)
    roi_gt_box_assignment = tf.cond(\
         tf.greater(tf.shape(positive_overlaps)[1], 0),\
         true_fn = lambda : tf.argmax(positive_overlaps, axis=1),\
         false_fn = lambda: tf.cast(tf.constant([]),tf.int64)
         )
    roi_gt_boxes = tf.gather(gt_boxes, roi_gt_box_assignment)
    roi_gt_class_ids = tf.gather(gt_class_ids, roi_gt_box_assignment)
    # Compute bbox refinement for positive ROIs
    deltas = utils.box_refinement_graph(positive_rois, roi_gt_boxes)
    deltas /= config.BBOX_STD_DEV

    # Assign positive ROIs to GT masks
    # Permute masks to [N, height, width, 1]
    transposed_masks = tf.expand_dims(tf.transpose(gt_masks, [2, 0, 1]), -1)
    # Pick the right mask for each ROI
    roi_masks = tf.gather(transposed_masks, roi_gt_box_assignment)

    # Compute mask targets
    boxes = positive_rois
    if config.USE_MINI_MASK:
        # Transform ROI coordinates from normalized image space
        # to normalized mini_mask space
        y1, x1, y2, x2 = tf.split(positive_rois, 4, axis=1)
        gt_y1, gt_x1, gt_y2, gt_x2 = tf.split(roi_gt_boxes, 4, axis=1)
        gt_h = gt_y2 - gt_y1
        gt_w = gt_x2 - gt_x1
        y1 = (y1 - gt_y1) / gt_h
        x1 = (x1 - gt_x1) / gt_w
        y2 = (y2 - gt_y2) / gt_h
        x2 = (x2 - gt_x2) / gt_w
        boxes = tf.concat([y1, x1, y2, x2], 1)
    box_ids = tf.range(0, tf.shape(roi_masks)[0])
    masks = tf.image.crop_and_resize(tf.cast(roi_masks, tf.float32), boxes,\
             box_ids,\
             config.MASK_SHAPE)
    # Remove the extra dimension from masks
    masks = tf.squeeze(masks, axis=3)

    # Threshold mask pixels at 0.5 to have GT masks be 0 or 1\
    # to use with binary cross entropy loss
    masks = tf.round(masks)

    # Append negative ROIs and pad bbox deltas and masks that
    # are not used for negative ROIs with zeros.
    # positive_rois = tf.Print(positive_rois, ['positive_rois: ', tf.shape(positive_rois), "negative_rois: ", tf.shape(negative_rois)])
    rois = tf.concat([positive_rois, negative_rois], axis=0)
    N = tf.shape(negative_rois)[0]
    P = tf.maximum(config.TRAIN_ROIS_PER_IMAGE - tf.shape(rois)[0], 0)
    rois = tf.pad(rois, [(0, P), (0, 0)])
    roi_gt_boxes = tf.pad(roi_gt_boxes, [(0, N + P), (0, 0)])
    roi_gt_class_ids = tf.pad(roi_gt_class_ids, [(0, N + P)])
    deltas = tf.pad(deltas, [(0, N + P), (0, 0)])
    masks = tf.pad(masks, [(0, N + P), (0, 0), (0, 0)])

    return rois, roi_gt_class_ids, deltas, masks
示例#3
0
def target_detection(proposals, gt_class_ids, gt_boxes, gt_masks):

    # assert_ = tf.Assert(tf.greater(tf.shape(proposals)[0], 0), [proposals], name='roi_assert')

    # with tf.control_dependencies(assert_):
    #     proposals = tf.identity(proposals)

    proposals, _ = utils.trim_zeros_graph(proposals, name="trim_proposals")
    gt_boxes, non_zeros = utils.trim_zeros_graph(gt_boxes, name="trim_gt_boxes")
    gt_class_ids = tf.boolean_mask(gt_class_ids, non_zeros,
                                   name="trim_gt_class_ids")
    gt_masks = tf.gather(gt_masks, tf.where(non_zeros)[:, 0], axis=2,
                         name="trim_gt_masks")

    crowd_ix = tf.where(gt_class_ids < 0)[:, 0]
    non_crowd_ix = tf.where(gt_class_ids > 0)[:, 0]
    crowd_boxes = tf.gather(gt_boxes, crowd_ix)
    # crowd_masks = tf.gather(gt_masks, crowd_ix, axis=2)
    gt_class_ids = tf.gather(gt_class_ids, non_crowd_ix)
    gt_boxes = tf.gather(gt_boxes, non_crowd_ix)
    gt_masks = tf.gather(gt_masks, non_crowd_ix, axis=2)

    ious = ops.iou(proposals, gt_boxes)

    crowd_ious = ops.iou(proposals, crowd_boxes)
    crowd_iou_max = tf.reduce_max(crowd_ious, axis=1)
    no_crowd_bool = (crowd_iou_max < 0.001)

    roi_iou_max = tf.reduce_max(ious, axis=1)

    positive_roi_bool = (roi_iou_max >= 0.5)
    positive_indices = tf.where(positive_roi_bool)[:, 0]

    negative_indices = tf.where(tf.logical_and(roi_iou_max < 0.5, no_crowd_bool))[:, 0]

    positive_count = int(hyper_parameters.FLAGS.TRAIN_ROIS_PER_IMAGE *
                         hyper_parameters.FLAGS.ROI_POSITIVE_RATIO)
    positive_indices = tf.random_shuffle(positive_indices)[:positive_count]
    positive_count = tf.shape(positive_indices)[0]

    r = 1.0 / hyper_parameters.FLAGS.ROI_POSITIVE_RATIO
    negative_count = tf.cast(r * tf.cast(positive_count, tf.float32), tf.int32) - positive_count
    negative_indices = tf.random_shuffle(negative_indices)[:negative_count]

    positive_rois = tf.gather(proposals, positive_indices)
    negative_rois = tf.gather(proposals, negative_indices)

    positive_ious = tf.gather(ious, positive_indices)
    roi_gt_box_assignment = tf.cond(
        tf.greater(tf.shape(positive_ious)[1], 0),
        true_fn=lambda: tf.argmax(positive_ious, axis=1),
        false_fn=lambda: tf.cast(tf.constant([]), tf.int64)
    )

    roi_gt_boxes = tf.gather(gt_boxes, roi_gt_box_assignment)
    roi_gt_class_ids = tf.gather(gt_class_ids, roi_gt_box_assignment)

    deltas = utils.box_refinement_graph(positive_rois, roi_gt_boxes)
    deltas /= np.array(hyper_parameters.FLAGS.BBOX_STD_DEV)

    transposed_masks = tf.expand_dims(tf.transpose(gt_masks, [2, 0, 1]), -1)
    roi_masks = tf.gather(transposed_masks, roi_gt_box_assignment)

    boxes = positive_rois
    if hyper_parameters.FLAGS.USE_MINI_MASK:
        y1, x1, y2, x2 = tf.split(positive_rois, 4, axis=1)
        gt_y1, gt_x1, gt_y2, gt_x2 = tf.split(roi_gt_boxes, 4, axis=1)
        gt_h = gt_y2 - gt_y1
        gt_w = gt_x2 - gt_x1
        y1 = (y1 - gt_y1) / gt_h
        x1 = (x1 - gt_x1) / gt_w
        y2 = (y2 - gt_y1) / gt_h
        x2 = (x2 - gt_x1) / gt_w
        boxes = tf.concat([y1, x1, y2, x2], 1)

    box_ids = tf.range(0, tf.shape(roi_masks)[0])
    masks = tf.image.crop_and_resize(tf.cast(roi_masks, tf.float32), boxes,
                                     box_ids,
                                     hyper_parameters.FLAGS.MASK_SHAPE)

    masks = tf.squeeze(masks, axis=3)
    masks = tf.round(masks)

    rois = tf.concat([positive_rois, negative_rois], axis=0)
    n = tf.shape(negative_rois)[0]
    p = tf.maximum(hyper_parameters.FLAGS.TRAIN_ROIS_PER_IMAGE - tf.shape(rois)[0], 0)
    rois = tf.pad(rois, [(0, p), (0, 0)])
    # roi_gt_boxes = tf.pad(roi_gt_boxes, [(0, n + p), (0, 0)])
    roi_gt_class_ids = tf.pad(roi_gt_class_ids, [(0, n + p)])
    deltas = tf.pad(deltas, [(0, n + p), (0, 0)])
    masks = tf.pad(masks, [[0, n + p], (0, 0), (0, 0)])

    return rois, roi_gt_class_ids, deltas, masks
示例#4
0
def level_select(cls_pred, regr_pred, gt_boxes, feature_shapes, strides, pos_scale=0.2):
    MAX_NUM_GT_BOXES = gt_boxes.shape[0]
    gt_boxes = gt_boxes[gt_boxes[:, 4] != -1]
    gt_labels = gt_boxes[:, 4].int()
    gt_boxes = gt_boxes[:, :4]
    focal_loss = FocalLoss(alpha=0.25)
    iou_loss = IoULoss()

    gt_boxes, non_zeros = trim_zeros_graph(gt_boxes)
    num_gt_boxes = gt_boxes.shape[0]
    gt_labels = gt_labels[non_zeros]
    level_losses = []
    total_loss = 0
    for level_id in range(len(strides)):
        stride = strides[level_id]
        fh = math.ceil(feature_shapes[level_id][0])
        fw = math.ceil(feature_shapes[level_id][1])
        fa = torch.prod(torch.ceil(feature_shapes), dim=1)
        start_index = torch.sum(fa[:level_id]).int()
        start_index = start_index.item()
        end_index = start_index + fh * fw
        cls_pred_i = cls_pred[start_index:end_index, :].reshape(fh, fw, -1)
        regr_pred_i = regr_pred[start_index:end_index, :].reshape(fh, fw, -1)
        proj_boxes = gt_boxes / stride
        x1, y1, x2, y2 = prop_box_graph(proj_boxes, pos_scale, fw, fh)
        level_loss = []
        for i in range(num_gt_boxes):
            x1_ = x1[i]
            y1_ = y1[i]
            x2_ = x2[i]
            y2_ = y2[i]
            gt_box = gt_boxes[i]
            gt_label = gt_labels[i]
            locs_cls_pred_i = cls_pred_i[y1_:y2_, x1_:x2_, :].reshape(-1, cls_pred_i.shape[2])
            locs_a, num_class = locs_cls_pred_i.shape
            locs_cls_true_i = torch.zeros(num_class).cuda()
            locs_cls_true_i[gt_label] = 1
            locs_cls_true_i = locs_cls_true_i.repeat(locs_a, 1)
            loss_cls = focal_loss(locs_cls_pred_i, locs_cls_true_i)
            locs_regr_pred_i = regr_pred_i[y1_:y2_, x1_:x2_, :].reshape(-1, 4)
            shift_x = (np.arange(x1_.cpu(), x2_.cpu()) + 0.5) * stride
            shift_y = (np.arange(y1_.cpu(), y2_.cpu()) + 0.5) * stride

            shift_x, shift_y = np.meshgrid(shift_x, shift_y)
            shifts = np.vstack((
                shift_x.ravel(), shift_y.ravel(),
                shift_x.ravel(), shift_y.ravel()
            )).transpose()

            shifts = torch.from_numpy(shifts).cuda()
            l = shifts[:, 0] - gt_box[0]
            t = shifts[:, 1] - gt_box[1]
            r = gt_box[2] - shifts[:, 2]
            b = gt_box[3] - shifts[:, 3]
            locs_regr_true_i = torch.stack([l, t, r, b], dim=1)
            locs_regr_true_i /= 4.0
            loss_regr = iou_loss(locs_regr_pred_i, locs_regr_true_i)
            level_loss.append(loss_cls + loss_regr)
            #print(loss_cls.item(), loss_regr.item())
            total_loss += (loss_cls + loss_regr)
        level_losses.append(level_loss)
    level_losses = torch.FloatTensor(level_losses)
    if level_losses.shape[1] != 0:
        gt_box_levels = torch.argmin(level_losses, dim=0).int()
    else:
        gt_box_levels = torch.zeros(0).int()
    padding_gt_box_levels = torch.ones((MAX_NUM_GT_BOXES - num_gt_boxes), dtype=torch.int32) * -1
    gt_box_levels = torch.cat((gt_box_levels, padding_gt_box_levels))
    if total_loss != 0:
        total_loss /= 1.0 * (num_gt_boxes * len(strides))
    return gt_box_levels, total_loss
def detection_targets_graph(proposals, gt_class_ids, gt_boxes, gt_masks,
                            config):
    """Generates detection targets for one image. Subsamples proposals and
    generates target class IDs, bounding box deltas, and masks for each.
    Inputs:
    proposals: [POST_NMS_ROIS_TRAINING, (y1, x1, y2, x2)] in normalized coordinates. Might
               be zero padded if there are not enough proposals.
    gt_class_ids: [MAX_GT_INSTANCES] int class IDs
    gt_boxes: [MAX_GT_INSTANCES, (y1, x1, y2, x2)] in normalized coordinates.
    gt_masks: [height, width, MAX_GT_INSTANCES] of boolean type.
    Returns: Target ROIs and corresponding class IDs, bounding box shifts,
    and masks.
    rois: [TRAIN_ROIS_PER_IMAGE, (y1, x1, y2, x2)] in normalized coordinates
    class_ids: [TRAIN_ROIS_PER_IMAGE]. Integer class IDs. Zero padded.
    deltas: [TRAIN_ROIS_PER_IMAGE, (dy, dx, log(dh), log(dw))]
    masks: [TRAIN_ROIS_PER_IMAGE, height, width]. Masks cropped to bbox
           boundaries and resized to neural network output size.
    Note: Returned arrays might be zero padded if not enough target ROIs.
    """

    # Assertions
    asserts = [
        tf.Assert(tf.greater(tf.shape(proposals)[0], 0), [proposals],
                  name='roi_assertion'),
    ]

    with tf.control_dependencies(asserts):
        proposals = tf.identity(proposals)

    # Remove zero padding
    proposals, _ = trim_zeros_graph(proposals, name='trim_proposals')
    gt_boxes, non_zeros = trim_zeros_graph(gt_boxes, name='trim_gt_boxes')
    gt_class_ids = tf.boolean_mask(gt_class_ids,
                                   non_zeros,
                                   name='trim_gt_class_ids')

    gt_masks = tf.gather(gt_masks,
                         tf.where(non_zeros)[:, 0],
                         axis=2,
                         name='trim_gt_masks')

    crowd_ix = tf.where(gt_class_ids < 0)[:, 0]
    non_crowd_ix = tf.where(gt_class_ids > 0)[:, 0]

    crowd_boxes = tf.gather(gt_boxes, crowd_ix)
    gt_class_ids = tf.gather(gt_class_ids, non_crowd_ix)
    gt_boxes = tf.gather(gt_boxes, non_crowd_ix)
    gt_masks = tf.gather(gt_masks, non_crowd_ix, axis=2)

    overlaps = overlaps_graph(proposals, gt_boxes)

    crowd_overlaps = overlaps_graph(proposals, crowd_boxes)
    crowd_iou_max = tf.reduce_max(crowd_overlaps, axis=1)
    no_crowd_bool = (crowd_iou_max < 0.001)

    roi_iou_max = tf.reduce_max(overlaps, axis=1)

    positive_roi_bool = (roi_iou_max >= 0.5)
    positive_indices = tf.where(positive_roi_bool)[:, 0]
    negative_indices = tf.where(
        tf.logical_and(roi_iou_max < 0.5, no_crowd_bool))[:, 0]

    positive_count = int(config.TRAIN_ROIS_PER_IMAGE *
                         config.ROI_POSITIVE_RATIO)

    positive_indices = tf.random.shuffle(positive_indices)[:positive_count]
    positive_count = tf.shape(positive_indices)[0]

    r = 1.0 / config.ROI_POSITIVE_RATIO

    negative_count = tf.cast(r * tf.cast(positive_count, tf.float32),
                             tf.int32) - positive_count
    negative_indices = tf.random.shuffle(negative_indices)[:negative_count]

    positive_rois = tf.gather(proposals, positive_indices)
    negative_rois = tf.gather(proposals, negative_indices)

    positive_overlaps = tf.gather(overlaps, positive_indices)

    roi_gt_box_assignment = tf.cond(
        tf.greater(tf.shape(positive_overlaps)[1], 0),
        true_fn=lambda: tf.argmax(positive_overlaps, axis=1),
        false_fn=lambda: tf.cast(tf.constant([]), tf.int64))

    roi_gt_boxes = tf.gather(gt_boxes, roi_gt_box_assignment)
    roi_gt_class_ids = tf.gather(gt_class_ids, roi_gt_box_assignment)

    deltas = utils.box_refinement_graph(positive_rois, roi_gt_boxes)
    deltas /= config.BBOX_STD_DEV

    transposed_masks = tf.expand_dims(tf.transpose(gt_masks, [2, 0, 1]), -1)

    roi_masks = tf.gather(transposed_masks, roi_gt_box_assignment)

    boxes = positive_rois

    if config.USE_MINI_MASK:
        # Transform ROI coordinates from normalized image space
        # to normalized mini-mask space.
        y1, x1, y2, x2 = tf.split(positive_rois, 4, axis=1)
        gt_y1, gt_x1, gt_y2, gt_x2 = tf.split(roi_gt_boxes, 4, axis=1)
        gt_h = gt_y2 - gt_y1
        gt_w = gt_x2 - gt_x1
        y1 = (y1 - gt_y1) / gt_h
        x1 = (x1 - gt_x1) / gt_w
        y2 = (y2 - gt_y1) / gt_h
        x2 = (x2 - gt_x1) / gt_w
        boxes = tf.concat([y1, x1, y2, x2], 1)

    box_ids = tf.range(0, tf.shape(roi_masks)[0])
    masks = tf.image.crop_and_resize(tf.cast(roi_masks, tf.float32), boxes,
                                     box_ids, config.MASK_SHAPE)

    masks = tf.squeeze(masks, axis=3)

    masks = tf.round(masks)

    rois = tf.concat([positive_rois, negative_rois], axis=0)
    N = tf.shape(negative_rois)[0]
    P = tf.maximum(config.TRAIN_ROIS_PER_IMAGE - tf.shape(rois)[0], 0)
    rois = tf.pad(rois, [(0, P), (0, 0)])
    roi_gt_boxes = tf.pad(roi_gt_boxes, [(0, N + P), (0, 0)])
    roi_gt_class_ids = tf.pad(roi_gt_class_ids, [(0, N + P)])
    deltas = tf.pad(deltas, [(0, N + P), (0, 0)])
    masks = tf.pad(masks, [[0, N + P], (0, 0), (0, 0)])

    return rois, roi_gt_class_ids, deltas, masks
示例#6
0
def detection_target(input_proposals, input_gt_class_ids, input_gt_boxes):
    roiss = []
    roi_gt_class_idss = []
    deltass = []
    for b in range(cfg.batch_size):
        proposals = input_proposals[b, :, :]
        gt_class_ids = input_gt_class_ids[b, :]
        gt_boxes = input_gt_boxes[b, :, :]

        proposals, _ = utils.trim_zeros_graph(proposals, name="trim_proposals")
        gt_boxes, non_zeros = utils.trim_zeros(gt_boxes, name="trim_gt_boxes")
        gt_class_ids = tf.boolean_mask(gt_class_ids,
                                       non_zeros,
                                       name="trim_gt_class_ids")

        crowd_ix = tf.where(gt_class_ids < 0)[:, 0]
        non_crowd_ix = tf.where(gt_class_ids > 0)[:, 0]
        crowd_boxes = tf.gather(gt_boxes, crowd_ix)

        gt_class_ids = tf.gather(gt_class_ids, non_crowd_ix)
        gt_boxes = tf.gather(gt_boxes, non_crowd_ix)

        overlaps = utils.overlaps_graph(proposals, gt_boxes)

        crowd_overlaps = utils.overlaps_graph(proposals, crowd_boxes)
        crowd_iou_max = tf.reduce_max(crowd_overlaps, axis=1)
        no_crowd_bool = (crowd_iou_max < 0.001)

        roi_iou_max = tf.reduce_max(overlaps, axis=1)

        positive_roi_bool = (roi_iou_max >= 0.5)
        positive_indices = tf.where(positive_roi_bool)[:, 0]

        negative_indices = tf.where(
            tf.logical_and(roi_iou_max < 0.5, no_crowd_bool))[:, 0]

        positive_count = int(cfg.TRAIN_ROIS_PER_IMAGE * cfg.ROI_POSITIVE_RATIO)
        positive_indices = tf.random_shuffle(positive_indices)[:positive_count]
        positive_count = tf.shape(positive_indices)[0]

        r = 1.0 / cfg.ROI_POSITIVE_RATIO
        negative_count = tf.cast(r * tf.cast(positive_count, tf.float32),
                                 tf.int32) - positive_count
        negative_indices = tf.random_shuffle(negative_indices)[:negative_count]

        positive_rois = tf.gather(proposals, positive_indices)
        negative_rois = tf.gather(proposals, negative_indices)

        # Assign positive ROIs to GT boxes.
        positive_overlaps = tf.gather(overlaps, positive_indices)

        roi_gt_box_assignment = tf.argmax(positive_overlaps, axis=1)

        roi_gt_boxes = tf.gather(gt_boxes, roi_gt_box_assignment)
        roi_gt_class_ids = tf.gather(gt_class_ids, roi_gt_box_assignment)

        deltas = utils.box_refinement_graph(positive_rois, roi_gt_boxes)
        deltas /= cfg.BBOX_STD_DEV

        rois = tf.concat([positive_rois, negative_rois], axis=0)
        N = tf.shape(negative_rois)[0]
        P = tf.maximum(cfg.TRAIN_ROIS_PER_IMAGE - tf.shape(rois)[0], 0)
        rois = tf.pad(rois, [(0, P), (0, 0)])
        roi_gt_boxes = tf.pad(roi_gt_boxes, [(0, N + P), (0, 0)])
        roi_gt_class_ids = tf.pad(roi_gt_class_ids, [(0, N + P)])
        deltas = tf.pad(deltas, [(0, N + P), (0, 0)])

        roiss.append(rois)
        roi_gt_class_idss.append(roi_gt_class_ids)
        deltass.append(deltas)
    return tf.stack(roiss, axis=0), tf.stack(roi_gt_class_idss,
                                             axis=0), tf.stack(deltass, axis=0)