def test_create_target_assigner(self): """Tests that named constructor gives working target assigners. TODO(rathodv): Make this test more general. """ corners = [[0.0, 0.0, 1.0, 1.0]] groundtruth = box_list.BoxList(tf.constant(corners)) priors = box_list.BoxList(tf.constant(corners)) multibox_ta = (targetassigner.create_target_assigner('Multibox', stage='proposal')) multibox_ta.assign(priors, groundtruth) # No tests on output, as that may vary arbitrarily as new target assigners # are added. As long as it is constructed correctly and runs without errors, # tests on the individual assigners cover correctness of the assignments. anchors = box_list.BoxList(tf.constant(corners)) faster_rcnn_proposals_ta = (targetassigner.create_target_assigner( 'FasterRCNN', stage='proposal')) faster_rcnn_proposals_ta.assign(anchors, groundtruth) fast_rcnn_ta = (targetassigner.create_target_assigner('FastRCNN')) fast_rcnn_ta.assign(anchors, groundtruth) faster_rcnn_detection_ta = (targetassigner.create_target_assigner( 'FasterRCNN', stage='detection')) faster_rcnn_detection_ta.assign(anchors, groundtruth) with self.assertRaises(ValueError): targetassigner.create_target_assigner('InvalidDetector', stage='invalid_stage')
def test_very_small_Width_nan_after_encoding(self): boxes = [[10.0, 10.0, 10.0000001, 20.0]] anchors = [[15.0, 12.0, 30.0, 18.0]] expected_rel_codes = [[-0.833333, 0., -21.128731, 0.510826]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = faster_rcnn_box_coder.FasterRcnnBoxCoder() rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: rel_codes_out, = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def test_box_list_invalid_inputs(self): data0 = tf.constant([[[0, 0, 1, 1], [3, 4, 5, 5]]], tf.float32) data1 = tf.constant([[0, 0, 1], [1, 1, 2], [3, 4, 5]], tf.float32) data2 = tf.constant([[0, 0, 1], [1, 1, 2], [3, 4, 5]], tf.int32) with self.assertRaises(ValueError): _ = box_list.BoxList(data0) with self.assertRaises(ValueError): _ = box_list.BoxList(data1) with self.assertRaises(ValueError): _ = box_list.BoxList(data2)
def test_get_correct_relative_codes_after_encoding(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] anchors = [[15.0, 12.0, 30.0, 18.0], [0.1, 0.0, 0.7, 0.9]] expected_rel_codes = [[-0.5, -0.416666, -0.405465, -0.182321], [-0.083333, -0.222222, -0.693147, -1.098612]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = faster_rcnn_box_coder.FasterRcnnBoxCoder() rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: rel_codes_out, = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def test_get_correct_pairwise_similarity_based_on_iou(self): corners1 = tf.constant([[4.0, 3.0, 7.0, 5.0], [5.0, 6.0, 10.0, 7.0]]) corners2 = tf.constant([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]]) exp_output = [[2.0 / 16.0, 0, 6.0 / 400.0], [1.0 / 16.0, 0.0, 5.0 / 400.0]] boxes1 = box_list.BoxList(corners1) boxes2 = box_list.BoxList(corners2) iou_similarity_calculator = region_similarity_calculator.IouSimilarity() iou_similarity = iou_similarity_calculator.compare(boxes1, boxes2) with self.test_session() as sess: iou_output = sess.run(iou_similarity) self.assertAllClose(iou_output, exp_output)
def test_correct_relative_codes_with_small_width(self): boxes = [[10.0, 10.0, 10.0000001, 20.0]] anchors = [[15.0, 12.0, 30.0, 18.0]] scale_factors = None expected_rel_codes = [[-1.317616, 0., -20.670586]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = square_box_coder.SquareBoxCoder(scale_factors=scale_factors) rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: (rel_codes_out, ) = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def testGetCorrectRelativeCodesAfterEncoding(self): box_corners = [[0.0, 0.0, 0.5, 0.5], [0.0, 0.0, 0.5, 0.5]] boxes = box_list.BoxList(tf.constant(box_corners)) expected_rel_codes = [[0.0, 0.0, 0.0, 0.0], [-5.0, -5.0, -5.0, -3.0]] prior_means = tf.constant([[0.0, 0.0, 0.5, 0.5], [0.5, 0.5, 1.0, 0.8]]) priors = box_list.BoxList(prior_means) coder = mean_stddev_box_coder.MeanStddevBoxCoder(stddev=0.1) rel_codes = coder.encode(boxes, priors) with self.test_session() as sess: rel_codes_out = sess.run(rel_codes) self.assertAllClose(rel_codes_out, expected_rel_codes)
def test_correct_relative_codes_with_non_default_scale(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] anchors = [[15.0, 12.0, 30.0, 18.0], [0.1, 0.0, 0.7, 0.9]] scale_factors = [2, 3, 4] expected_rel_codes = [[-1.581139, -0.790569, -1.175573], [-0.136083, -0.816497, -3.583519]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = square_box_coder.SquareBoxCoder(scale_factors=scale_factors) rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: (rel_codes_out, ) = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def graph_fn(anchor_means, groundtruth_boxlist1, groundtruth_boxlist2): box_list1 = box_list.BoxList(groundtruth_boxlist1) box_list2 = box_list.BoxList(groundtruth_boxlist2) gt_box_batch = [box_list1, box_list2] gt_class_targets = [None, None] anchors_boxlist = box_list.BoxList(anchor_means) agnostic_target_assigner = self._get_target_assigner() (cls_targets, cls_weights, reg_targets, reg_weights, _) = targetassigner.batch_assign_targets(agnostic_target_assigner, anchors_boxlist, gt_box_batch, gt_class_targets) return (cls_targets, cls_weights, reg_targets, reg_weights)
def test_get_correct_relative_codes_after_encoding_with_scaling(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] anchors = [[15.0, 12.0, 30.0, 18.0], [0.1, 0.0, 0.7, 0.9]] scale_factors = [2, 3, 4, 5] expected_rel_codes = [[-1., -1.25, -1.62186, -0.911608], [-0.166667, -0.666667, -2.772588, -5.493062]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = faster_rcnn_box_coder.FasterRcnnBoxCoder( scale_factors=scale_factors) rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: rel_codes_out, = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def test_get_correct_pairwise_similarity_based_on_squared_distances(self): corners1 = tf.constant([[0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.0, 2.0]]) corners2 = tf.constant([[3.0, 4.0, 1.0, 0.0], [-4.0, 0.0, 0.0, 3.0], [0.0, 0.0, 0.0, 0.0]]) exp_output = [[-26, -25, 0], [-18, -27, -6]] boxes1 = box_list.BoxList(corners1) boxes2 = box_list.BoxList(corners2) dist_similarity_calc = region_similarity_calculator.NegSqDistSimilarity() dist_similarity = dist_similarity_calc.compare(boxes1, boxes2) with self.test_session() as sess: dist_output = sess.run(dist_similarity) self.assertAllClose(dist_output, exp_output)
def graph_fn(anchor_means, groundtruth_box_corners): similarity_calc = region_similarity_calculator.IouSimilarity() matcher = argmax_matcher.ArgMaxMatcher(matched_threshold=0.5, unmatched_threshold=0.3) box_coder = mean_stddev_box_coder.MeanStddevBoxCoder(stddev=0.1) target_assigner = targetassigner.TargetAssigner( similarity_calc, matcher, box_coder) anchors_boxlist = box_list.BoxList(anchor_means) groundtruth_boxlist = box_list.BoxList(groundtruth_box_corners) result = target_assigner.assign(anchors_boxlist, groundtruth_boxlist, unmatched_class_label=None) (cls_targets, cls_weights, reg_targets, reg_weights, _) = result return (cls_targets, cls_weights, reg_targets, reg_weights)
def test_correct_relative_codes_with_default_scale(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] anchors = [[15.0, 12.0, 30.0, 18.0], [0.1, 0.0, 0.7, 0.9]] scale_factors = None expected_rel_codes = [[-0.790569, -0.263523, -0.293893], [-0.068041, -0.272166, -0.89588]] boxes = box_list.BoxList(tf.constant(boxes)) anchors = box_list.BoxList(tf.constant(anchors)) coder = square_box_coder.SquareBoxCoder(scale_factors=scale_factors) rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: (rel_codes_out, ) = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def graph_fn(anchor_means, groundtruth_box_corners, gt_class_targets): groundtruth_boxlist = box_list.BoxList(groundtruth_box_corners) gt_box_batch = [groundtruth_boxlist] gt_class_targets_batch = [gt_class_targets] anchors_boxlist = box_list.BoxList(anchor_means) multiclass_target_assigner = self._get_target_assigner() num_classes = 3 unmatched_class_label = tf.constant([1] + num_classes * [0], tf.float32) (cls_targets, cls_weights, reg_targets, reg_weights, _) = targetassigner.batch_assign_targets( multiclass_target_assigner, anchors_boxlist, gt_box_batch, gt_class_targets_batch, unmatched_class_label) return (cls_targets, cls_weights, reg_targets, reg_weights)
def graph_fn(anchor_means, groundtruth_boxlist1, groundtruth_boxlist2, class_targets1, class_targets2): box_list1 = box_list.BoxList(groundtruth_boxlist1) box_list2 = box_list.BoxList(groundtruth_boxlist2) gt_box_batch = [box_list1, box_list2] gt_class_targets = [class_targets1, class_targets2] anchors_boxlist = box_list.BoxList(anchor_means) multiclass_target_assigner = self._get_target_assigner() target_dimensions = (2, 3) unmatched_class_label = tf.constant(np.zeros(target_dimensions), tf.float32) (cls_targets, cls_weights, reg_targets, reg_weights, _) = targetassigner.batch_assign_targets( multiclass_target_assigner, anchors_boxlist, gt_box_batch, gt_class_targets, unmatched_class_label) return (cls_targets, cls_weights, reg_targets, reg_weights)
def test_as_tensor_dict_missing_field(self): boxlist = box_list.BoxList( tf.constant([[0.1, 0.1, 0.4, 0.4], [0.1, 0.1, 0.5, 0.5]], tf.float32)) boxlist.add_field('classes', tf.constant([0, 1])) boxlist.add_field('scores', tf.constant([0.75, 0.2])) with self.assertRaises(ValueError): boxlist.as_tensor_dict(['foo', 'bar'])
def _decode(self, rel_codes, anchors): """Decode relative codes to boxes. Args: rel_codes: a tensor representing N anchor-encoded boxes. anchors: BoxList of anchors. Returns: boxes: BoxList holding N bounding boxes. """ ycenter_a, xcenter_a, ha, wa = anchors.get_center_coordinates_and_sizes( ) ty, tx, th, tw = tf.unstack(tf.transpose(rel_codes)) if self._scale_factors: ty /= self._scale_factors[0] tx /= self._scale_factors[1] th /= self._scale_factors[2] tw /= self._scale_factors[3] w = tf.exp(tw) * wa h = tf.exp(th) * ha ycenter = ty * ha + ycenter_a xcenter = tx * wa + xcenter_a ymin = ycenter - h / 2. xmin = xcenter - w / 2. ymax = ycenter + h / 2. xmax = xcenter + w / 2. return box_list.BoxList( tf.transpose(tf.stack([ymin, xmin, ymax, xmax])))
def _decode(self, rel_codes, anchors): """Decodes relative codes to boxes. Args: rel_codes: a tensor representing N anchor-encoded boxes. anchors: BoxList of anchors. Returns: boxes: BoxList holding N bounding boxes. """ ycenter_a, xcenter_a, ha, wa = anchors.get_center_coordinates_and_sizes( ) la = tf.sqrt(ha * wa) ty, tx, tl = tf.unstack(tf.transpose(rel_codes)) if self._scale_factors: ty /= self._scale_factors[0] tx /= self._scale_factors[1] tl /= self._scale_factors[2] l = tf.exp(tl) * la ycenter = ty * la + ycenter_a xcenter = tx * la + xcenter_a ymin = ycenter - l / 2. xmin = xcenter - l / 2. ymax = ycenter + l / 2. xmax = xcenter + l / 2. return box_list.BoxList( tf.transpose(tf.stack([ymin, xmin, ymax, xmax])))
def test_very_small_width_nan_after_encoding(self): boxes = [[10., 10., 10.0000001, 20.]] keypoints = [[[10., 10.], [10.0000001, 20.]]] anchors = [[15., 12., 30., 18.]] expected_rel_codes = [[ -0.833333, 0., -21.128731, 0.510826, -0.833333, -0.833333, -0.833333, 0.833333 ]] boxes = box_list.BoxList(tf.constant(boxes)) boxes.add_field(fields.BoxListFields.keypoints, tf.constant(keypoints)) anchors = box_list.BoxList(tf.constant(anchors)) coder = keypoint_box_coder.KeypointBoxCoder(2) rel_codes = coder.encode(boxes, anchors) with self.test_session() as sess: rel_codes_out, = sess.run([rel_codes]) self.assertAllClose(rel_codes_out, expected_rel_codes)
def scale(boxlist, y_scale, x_scale, scope=None): """scale box coordinates in x and y dimensions. Args: boxlist: BoxList holding N boxes y_scale: (float) scalar tensor x_scale: (float) scalar tensor scope: name scope. Returns: boxlist: BoxList holding N boxes """ with tf.name_scope(scope, 'Scale'): y_scale = tf.cast(y_scale, tf.float32) x_scale = tf.cast(x_scale, tf.float32) y_min, x_min, y_max, x_max = tf.split(value=boxlist.get(), num_or_size_splits=4, axis=1) y_min = y_scale * y_min y_max = y_scale * y_max x_min = x_scale * x_min x_max = x_scale * x_max scaled_boxlist = box_list.BoxList( tf.concat([y_min, x_min, y_max, x_max], 1)) return _copy_extra_fields(scaled_boxlist, boxlist)
def change_coordinate_frame(boxlist, window, scope=None): """Change coordinate frame of the boxlist to be relative to window's frame. Given a window of the form [ymin, xmin, ymax, xmax], changes bounding box coordinates from boxlist to be relative to this window (e.g., the min corner maps to (0,0) and the max corner maps to (1,1)). An example use case is data augmentation: where we are given groundtruth boxes (boxlist) and would like to randomly crop the image to some window (window). In this case we need to change the coordinate frame of each groundtruth box to be relative to this new window. Args: boxlist: A BoxList object holding N boxes. window: A rank 1 tensor [4]. scope: name scope. Returns: Returns a BoxList object with N boxes. """ with tf.name_scope(scope, 'ChangeCoordinateFrame'): win_height = window[2] - window[0] win_width = window[3] - window[1] boxlist_new = scale( box_list.BoxList(boxlist.get() - [window[0], window[1], window[0], window[1]]), 1.0 / win_height, 1.0 / win_width) boxlist_new = _copy_extra_fields(boxlist_new, boxlist) return boxlist_new
def test_transpose_coordinates(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] boxes = box_list.BoxList(tf.constant(boxes)) boxes.transpose_coordinates() expected_corners = [[10.0, 10.0, 15.0, 20.0], [0.1, 0.2, 0.4, 0.5]] with self.test_session() as sess: corners_out = sess.run(boxes.get()) self.assertAllClose(corners_out, expected_corners)
def test_get_correct_center_coordinates_and_sizes(self): boxes = [[10.0, 10.0, 20.0, 15.0], [0.2, 0.1, 0.5, 0.4]] boxes = box_list.BoxList(tf.constant(boxes)) centers_sizes = boxes.get_center_coordinates_and_sizes() expected_centers_sizes = [[15, 0.35], [12.5, 0.25], [10, 0.3], [5, 0.3]] with self.test_session() as sess: centers_sizes_out = sess.run(centers_sizes) self.assertAllClose(centers_sizes_out, expected_centers_sizes)
def test_num_boxes(self): data = tf.constant([[0, 0, 1, 1], [1, 1, 2, 3], [3, 4, 5, 5]], tf.float32) expected_num_boxes = 3 boxes = box_list.BoxList(data) with self.test_session() as sess: num_boxes_output = sess.run(boxes.num_boxes()) self.assertEquals(num_boxes_output, expected_num_boxes)
def graph_fn(anchor_means, groundtruth_box_corners, groundtruth_keypoints): similarity_calc = region_similarity_calculator.IouSimilarity() matcher = argmax_matcher.ArgMaxMatcher(matched_threshold=0.5, unmatched_threshold=0.5) box_coder = keypoint_box_coder.KeypointBoxCoder( num_keypoints=6, scale_factors=[10.0, 10.0, 5.0, 5.0]) target_assigner = targetassigner.TargetAssigner( similarity_calc, matcher, box_coder) anchors_boxlist = box_list.BoxList(anchor_means) groundtruth_boxlist = box_list.BoxList(groundtruth_box_corners) groundtruth_boxlist.add_field(fields.BoxListFields.keypoints, groundtruth_keypoints) result = target_assigner.assign(anchors_boxlist, groundtruth_boxlist, unmatched_class_label=None) (cls_targets, cls_weights, reg_targets, reg_weights, _) = result return (cls_targets, cls_weights, reg_targets, reg_weights)
def graph_fn(anchor_means, groundtruth_boxlist1, groundtruth_boxlist2, class_targets1, class_targets2, groundtruth_weights1, groundtruth_weights2): box_list1 = box_list.BoxList(groundtruth_boxlist1) box_list2 = box_list.BoxList(groundtruth_boxlist2) gt_box_batch = [box_list1, box_list2] gt_class_targets = [class_targets1, class_targets2] gt_weights = [groundtruth_weights1, groundtruth_weights2] anchors_boxlist = box_list.BoxList(anchor_means) multiclass_target_assigner = self._get_target_assigner() num_classes = 3 unmatched_class_label = tf.constant([1] + num_classes * [0], tf.float32) (cls_targets, cls_weights, reg_targets, reg_weights, _) = targetassigner.batch_assign_targets( multiclass_target_assigner, anchors_boxlist, gt_box_batch, gt_class_targets, unmatched_class_label, gt_weights) return (cls_targets, cls_weights, reg_targets, reg_weights)
def concatenate(boxlists, fields=None, scope=None): """Concatenate list of BoxLists. This op concatenates a list of input BoxLists into a larger BoxList. It also handles concatenation of BoxList fields as long as the field tensor shapes are equal except for the first dimension. Args: boxlists: list of BoxList objects fields: optional list of fields to also concatenate. By default, all fields from the first BoxList in the list are included in the concatenation. scope: name scope. Returns: a BoxList with number of boxes equal to sum([boxlist.num_boxes() for boxlist in BoxList]) Raises: ValueError: if boxlists is invalid (i.e., is not a list, is empty, or contains non BoxList objects), or if requested fields are not contained in all boxlists """ with tf.name_scope(scope, 'Concatenate'): if not isinstance(boxlists, list): raise ValueError('boxlists should be a list') if not boxlists: raise ValueError('boxlists should have nonzero length') for boxlist in boxlists: if not isinstance(boxlist, box_list.BoxList): raise ValueError( 'all elements of boxlists should be BoxList objects') concatenated = box_list.BoxList( tf.concat([boxlist.get() for boxlist in boxlists], 0)) if fields is None: fields = boxlists[0].get_extra_fields() for field in fields: first_field_shape = boxlists[0].get_field( field).get_shape().as_list() first_field_shape[0] = -1 if None in first_field_shape: raise ValueError( 'field %s must have fully defined shape except for the' ' 0th dimension.' % field) for boxlist in boxlists: if not boxlist.has_field(field): raise ValueError( 'boxlist must contain all requested fields') field_shape = boxlist.get_field(field).get_shape().as_list() field_shape[0] = -1 if field_shape != first_field_shape: raise ValueError( 'field %s must have same shape for all boxlists ' 'except for the 0th dimension.' % field) concatenated_field = tf.concat( [boxlist.get_field(field) for boxlist in boxlists], 0) concatenated.add_field(field, concatenated_field) return concatenated
def test_get_correct_pairwise_similarity_based_on_thresholded_iou(self): corners1 = tf.constant([[4.0, 3.0, 7.0, 5.0], [5.0, 6.0, 10.0, 7.0]]) corners2 = tf.constant([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]]) scores = tf.constant([.3, .6]) iou_threshold = .013 exp_output = tf.constant([[0.3, 0., 0.3], [0.6, 0., 0.]]) boxes1 = box_list.BoxList(corners1) boxes1.add_field(fields.BoxListFields.scores, scores) boxes2 = box_list.BoxList(corners2) iou_similarity_calculator = ( region_similarity_calculator.ThresholdedIouSimilarity( iou_threshold=iou_threshold)) iou_similarity = iou_similarity_calculator.compare(boxes1, boxes2) with self.test_session() as sess: iou_output = sess.run(iou_similarity) self.assertAllClose(iou_output, exp_output)
def test_get_correct_pairwise_similarity_based_on_ioa(self): corners1 = tf.constant([[4.0, 3.0, 7.0, 5.0], [5.0, 6.0, 10.0, 7.0]]) corners2 = tf.constant([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]]) exp_output_1 = [[2.0 / 12.0, 0, 6.0 / 400.0], [1.0 / 12.0, 0.0, 5.0 / 400.0]] exp_output_2 = [[2.0 / 6.0, 1.0 / 5.0], [0, 0], [6.0 / 6.0, 5.0 / 5.0]] boxes1 = box_list.BoxList(corners1) boxes2 = box_list.BoxList(corners2) ioa_similarity_calculator = region_similarity_calculator.IoaSimilarity() ioa_similarity_1 = ioa_similarity_calculator.compare(boxes1, boxes2) ioa_similarity_2 = ioa_similarity_calculator.compare(boxes2, boxes1) with self.test_session() as sess: iou_output_1, iou_output_2 = sess.run( [ioa_similarity_1, ioa_similarity_2]) self.assertAllClose(iou_output_1, exp_output_1) self.assertAllClose(iou_output_2, exp_output_2)
def tile_anchors(grid_height, grid_width, scales, aspect_ratios, base_anchor_size, anchor_stride, anchor_offset): """Create a tiled set of anchors strided along a grid in image space. This op creates a set of anchor boxes by placing a "basis" collection of boxes with user-specified scales and aspect ratios centered at evenly distributed points along a grid. The basis collection is specified via the scale and aspect_ratios arguments. For example, setting scales=[.1, .2, .2] and aspect ratios = [2,2,1/2] means that we create three boxes: one with scale .1, aspect ratio 2, one with scale .2, aspect ratio 2, and one with scale .2 and aspect ratio 1/2. Each box is multiplied by "base_anchor_size" before placing it over its respective center. Grid points are specified via grid_height, grid_width parameters as well as the anchor_stride and anchor_offset parameters. Args: grid_height: size of the grid in the y direction (int or int scalar tensor) grid_width: size of the grid in the x direction (int or int scalar tensor) scales: a 1-d (float) tensor representing the scale of each box in the basis set. aspect_ratios: a 1-d (float) tensor representing the aspect ratio of each box in the basis set. The length of the scales and aspect_ratios tensors must be equal. base_anchor_size: base anchor size as [height, width] (float tensor of shape [2]) anchor_stride: difference in centers between base anchors for adjacent grid positions (float tensor of shape [2]) anchor_offset: center of the anchor with scale and aspect ratio 1 for the upper left element of the grid, this should be zero for feature networks with only VALID padding and even receptive field size, but may need some additional calculation if other padding is used (float tensor of shape [2]) Returns: a BoxList holding a collection of N anchor boxes """ ratio_sqrts = tf.sqrt(aspect_ratios) heights = scales / ratio_sqrts * base_anchor_size[0] widths = scales * ratio_sqrts * base_anchor_size[1] # Get a grid of box centers y_centers = tf.to_float(tf.range(grid_height)) y_centers = y_centers * anchor_stride[0] + anchor_offset[0] x_centers = tf.to_float(tf.range(grid_width)) x_centers = x_centers * anchor_stride[1] + anchor_offset[1] x_centers, y_centers = ops.meshgrid(x_centers, y_centers) widths_grid, x_centers_grid = ops.meshgrid(widths, x_centers) heights_grid, y_centers_grid = ops.meshgrid(heights, y_centers) bbox_centers = tf.stack([y_centers_grid, x_centers_grid], axis=3) bbox_sizes = tf.stack([heights_grid, widths_grid], axis=3) bbox_centers = tf.reshape(bbox_centers, [-1, 2]) bbox_sizes = tf.reshape(bbox_sizes, [-1, 2]) bbox_corners = _center_size_bbox_to_corners_bbox(bbox_centers, bbox_sizes) return box_list.BoxList(bbox_corners)