def _get_overlaps_and_scores_relation_tuples(self, detected_box_tuples, groundtruth_box_tuples): """Computes overlaps and scores between detected and groundtruth tuples. Both detections and groundtruth boxes have the same class tuples. Args: detected_box_tuples: A numpy array of structures with shape [N,], representing N tuples, each tuple containing the same number of named bounding boxes. Each box is of the format [y_min, x_min, y_max, x_max] groundtruth_box_tuples: A float numpy array of structures with the shape [M,], representing M tuples, each tuple containing the same number of named bounding boxes. Each box is of the format [y_min, x_min, y_max, x_max] Returns: result_iou: A float numpy array of size [num_detected_tuples, num_gt_box_tuples]. """ result_iou = np.ones( (detected_box_tuples.shape[0], groundtruth_box_tuples.shape[0]), dtype=float) for field in detected_box_tuples.dtype.fields: detected_boxlist_field = np_box_list.BoxList( detected_box_tuples[field]) gt_boxlist_field = np_box_list.BoxList( groundtruth_box_tuples[field]) iou_field = np_box_list_ops.iou(detected_boxlist_field, gt_boxlist_field) result_iou = np.minimum(iou_field, result_iou) return result_iou
def _compute_is_aclass_correctly_detected_in_image(self, detected_boxes, detected_scores, groundtruth_boxes): """Compute CorLoc score for a single class. Args: detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates detected_scores: A 1-d numpy array of length N representing classification score groundtruth_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates Returns: is_class_correctly_detected_in_image: An integer 1 or 0 denoting whether a class is correctly detected in the image or not """ if detected_boxes.size > 0: if groundtruth_boxes.size > 0: max_score_id = np.argmax(detected_scores) detected_boxlist = np_box_list.BoxList( np.expand_dims(detected_boxes[max_score_id, :], axis=0)) gt_boxlist = np_box_list.BoxList(groundtruth_boxes) iou = np_box_list_ops.iou(detected_boxlist, gt_boxlist) if np.max(iou) >= self.matching_iou_threshold: return 1 return 0
def _compute_tp_fp_for_single_class(self, detected_boxes, detected_scores, groundtruth_boxes, groundtruth_is_difficult_list): """Labels boxes detected with the same class from the same image as tp/fp. Args: detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates detected_scores: A 1-d numpy array of length N representing classification score groundtruth_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates groundtruth_is_difficult_list: A boolean numpy array of length M denoting whether a ground truth box is a difficult instance or not Returns: scores: A numpy array representing the detection scores tp_fp_labels: a boolean numpy array indicating whether a detection is a true positive. """ if groundtruth_boxes.size == 0: is_gt_box_detected = np.array([], dtype=bool) else: is_gt_box_detected = np.zeros(groundtruth_boxes.shape[0], dtype=bool) if detected_boxes.size == 0: return np.array([], dtype=float), np.array( [], dtype=bool), is_gt_box_detected detected_boxlist = np_box_list.BoxList(detected_boxes) detected_boxlist.add_field('scores', detected_scores) detected_boxlist = np_box_list_ops.non_max_suppression( detected_boxlist, self.nms_max_output_boxes, self.nms_iou_threshold) scores = detected_boxlist.get_field('scores') if groundtruth_boxes.size == 0: return scores, np.zeros(detected_boxlist.num_boxes(), dtype=bool), is_gt_box_detected gt_boxlist = np_box_list.BoxList(groundtruth_boxes) iou = np_box_list_ops.iou(detected_boxlist, gt_boxlist) max_overlap_gt_ids = np.argmax(iou, axis=1) tp_fp_labels = np.zeros(detected_boxlist.num_boxes(), dtype=bool) is_matched_to_difficult_box = np.zeros(detected_boxlist.num_boxes(), dtype=bool) for i in range(detected_boxlist.num_boxes()): gt_id = max_overlap_gt_ids[i] if iou[i, gt_id] >= self.matching_iou_threshold: if not groundtruth_is_difficult_list[gt_id]: if not is_gt_box_detected[gt_id]: tp_fp_labels[i] = True is_gt_box_detected[gt_id] = True else: is_matched_to_difficult_box[i] = True return scores[~is_matched_to_difficult_box], tp_fp_labels[ ~is_matched_to_difficult_box], is_gt_box_detected
def setUp(self): boxes1 = np.array([[4.0, 3.0, 7.0, 5.0], [5.0, 6.0, 10.0, 7.0]], dtype=float) boxes2 = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) self.boxlist1 = np_box_list.BoxList(boxes1) self.boxlist2 = np_box_list.BoxList(boxes2)
def test_change_coordinate_frame(self): boxlist = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype=np.float32)) boxlist_coord = np_box_list_ops.change_coordinate_frame( boxlist, np.array([0, 0, 0.5, 0.5], dtype=np.float32)) expected_boxlist_coord = np_box_list.BoxList( np.array([[0.5, 0.5, 1.5, 1.5], [0, 0, 1.0, 1.5]], dtype=np.float32)) self.assertAllClose(boxlist_coord.get(), expected_boxlist_coord.get())
def test_ioa(self): boxlist1 = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype=np.float32)) boxlist2 = np_box_list.BoxList( np.array([[0.5, 0.25, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0]], dtype=np.float32)) ioa21 = np_box_list_ops.ioa(boxlist2, boxlist1) expected_ioa21 = np.array([[0.5, 0.0], [1.0, 1.0]], dtype=np.float32) self.assertAllClose(ioa21, expected_ioa21)
def test_scale(self): boxlist = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype=np.float32)) boxlist_scaled = np_box_list_ops.scale(boxlist, 2.0, 3.0) expected_boxlist_scaled = np_box_list.BoxList( np.array([[0.5, 0.75, 1.5, 2.25], [0.0, 0.0, 1.0, 2.25]], dtype=np.float32)) self.assertAllClose(expected_boxlist_scaled.get(), boxlist_scaled.get())
def test_prune_outside_window(self): boxlist = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75], [-0.2, -0.3, 0.7, 1.5]], dtype=np.float32)) boxlist_pruned, _ = np_box_list_ops.prune_outside_window( boxlist, [0.0, 0.0, 1.0, 1.0]) expected_boxlist_pruned = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype=np.float32)) self.assertAllClose(expected_boxlist_pruned.get(), boxlist_pruned.get())
def test_filter_scores_greater_than(self): boxlist = np_box_list.BoxList( np.array( [[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype= np.float32)) boxlist.add_field('scores', np.array([0.8, 0.2], np.float32)) boxlist_greater = np_box_list_ops.filter_scores_greater_than(boxlist, 0.5) expected_boxlist_greater = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75]], dtype=np.float32)) self.assertAllClose(boxlist_greater.get(), expected_boxlist_greater.get())
def test_invalid_box_data(self): with self.assertRaises(ValueError): np_box_list.BoxList([0, 0, 1, 1]) with self.assertRaises(ValueError): np_box_list.BoxList(np.array([[0, 0, 1, 1]], dtype=int)) with self.assertRaises(ValueError): np_box_list.BoxList(np.array([0, 1, 1, 3, 4], dtype=float)) with self.assertRaises(ValueError): np_box_list.BoxList( np.array([[0, 1, 1, 3], [3, 1, 1, 5]], dtype=float))
def _compute_is_class_correctly_detected_in_image(self, detected_boxes, detected_scores, groundtruth_boxes, detected_masks=None, groundtruth_masks=None): """Compute CorLoc score for a single class. Args: detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates detected_scores: A 1-d numpy array of length N representing classification score groundtruth_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates detected_masks: (optional) A np.uint8 numpy array of shape [N, height, width]. If not None, the scores will be computed based on masks. groundtruth_masks: (optional) A np.uint8 numpy array of shape [M, height, width]. Returns: is_class_correctly_detected_in_image: An integer 1 or 0 denoting whether a class is correctly detected in the image or not """ if detected_boxes.size > 0: if groundtruth_boxes.size > 0: max_score_id = np.argmax(detected_scores) mask_mode = False if detected_masks is not None and groundtruth_masks is not None: mask_mode = True if mask_mode: detected_boxlist = np_box_mask_list.BoxMaskList( box_data=np.expand_dims(detected_boxes[max_score_id], axis=0), mask_data=np.expand_dims(detected_masks[max_score_id], axis=0)) gt_boxlist = np_box_mask_list.BoxMaskList( box_data=groundtruth_boxes, mask_data=groundtruth_masks) iou = np_box_mask_list_ops.iou(detected_boxlist, gt_boxlist) else: detected_boxlist = np_box_list.BoxList( np.expand_dims(detected_boxes[max_score_id, :], axis=0)) gt_boxlist = np_box_list.BoxList(groundtruth_boxes) iou = np_box_list_ops.iou(detected_boxlist, gt_boxlist) if np.max(iou) >= self.matching_iou_threshold: return 1 return 0
def test_concatenate(self): boxlist1 = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75]], dtype=np.float32)) boxlist2 = np_box_list.BoxList( np.array([[0.5, 0.25, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0]], dtype=np.float32)) boxlists = [boxlist1, boxlist2] boxlist_concatenated = np_box_list_ops.concatenate(boxlists) boxlist_concatenated_expected = np_box_list.BoxList( np.array([[0.25, 0.25, 0.75, 0.75], [0.0, 0.0, 0.5, 0.75], [0.5, 0.25, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0]], dtype=np.float32)) self.assertAllClose(boxlist_concatenated_expected.get(), boxlist_concatenated.get())
def test_different_iou_threshold(self): boxes = np.array([[0, 0, 20, 100], [0, 0, 20, 80], [200, 200, 210, 300], [200, 200, 210, 250]], dtype=float) boxlist = np_box_list.BoxList(boxes) boxlist.add_field('scores', np.array([0.9, 0.8, 0.7, 0.6])) max_output_size = 4 iou_threshold = .4 expected_boxes = np.array([ [0, 0, 20, 100], [200, 200, 210, 300], ], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes) iou_threshold = .5 expected_boxes = np.array( [[0, 0, 20, 100], [200, 200, 210, 300], [200, 200, 210, 250]], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes) iou_threshold = .8 expected_boxes = np.array([[0, 0, 20, 100], [0, 0, 20, 80], [200, 200, 210, 300], [200, 200, 210, 250]], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes)
def test_multiclass_nms(self): boxlist = np_box_list.BoxList( np.array( [[0.2, 0.4, 0.8, 0.8], [0.4, 0.2, 0.8, 0.8], [0.6, 0.0, 1.0, 1.0]], dtype=np.float32)) scores = np.array([[-0.2, 0.1, 0.5, -0.4, 0.3], [0.7, -0.7, 0.6, 0.2, -0.9], [0.4, 0.34, -0.9, 0.2, 0.31]], dtype=np.float32) boxlist.add_field('scores', scores) boxlist_clean = np_box_list_ops.multi_class_non_max_suppression( boxlist, score_thresh=0.25, iou_thresh=0.1, max_output_size=3) scores_clean = boxlist_clean.get_field('scores') classes_clean = boxlist_clean.get_field('classes') boxes = boxlist_clean.get() expected_scores = np.array([0.7, 0.6, 0.34, 0.31]) expected_classes = np.array([0, 2, 1, 4]) expected_boxes = np.array([[0.4, 0.2, 0.8, 0.8], [0.4, 0.2, 0.8, 0.8], [0.6, 0.0, 1.0, 1.0], [0.6, 0.0, 1.0, 1.0]], dtype=np.float32) self.assertAllClose(scores_clean, expected_scores) self.assertAllClose(classes_clean, expected_classes) self.assertAllClose(boxes, expected_boxes)
def gather(boxlist, indices, fields=None): """Gather boxes from BoxList according to indices and return new BoxList. By default, gather returns boxes corresponding to the input index list, as well as all additional fields stored in the boxlist (indexing into the first dimension). However one can optionally only gather from a subset of fields. Args: boxlist: BoxList holding N boxes indices: a 1-d numpy array of type int_ fields: (optional) list of fields to also gather from. If None (default), all fields are gathered from. Pass an empty fields list to only gather the box coordinates. Returns: subboxlist: a BoxList corresponding to the subset of the input BoxList specified by indices Raises: ValueError: if specified field is not contained in boxlist or if the indices are not of type int_ """ if indices.size: if np.amax(indices) >= boxlist.num_boxes() or np.amin(indices) < 0: raise ValueError('indices are out of valid range.') subboxlist = np_box_list.BoxList(boxlist.get()[indices, :]) if fields is None: fields = boxlist.get_extra_fields() for field in fields: extra_field_data = boxlist.get_field(field) subboxlist.add_field(field, extra_field_data[indices, ...]) return subboxlist
def test_get_field_with_nonexited_field(self): boxes = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) boxlist = np_box_list.BoxList(boxes) with self.assertRaises(ValueError): boxlist.get_field('scores')
def change_coordinate_frame(boxlist, window): """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 size 4 1-D numpy array. Returns: Returns a BoxList object with N boxes. """ win_height = window[2] - window[0] win_width = window[3] - window[1] boxlist_new = scale( np_box_list.BoxList(boxlist.get() - [window[0], window[1], window[0], window[1]]), 1.0 / win_height, 1.0 / win_width) _copy_extra_fields(boxlist_new, boxlist) return boxlist_new
def scale(boxlist, y_scale, x_scale): """Scale box coordinates in x and y dimensions. Args: boxlist: BoxList holding N boxes y_scale: float x_scale: float Returns: boxlist: BoxList holding N boxes """ y_min, x_min, y_max, x_max = np.array_split(boxlist.get(), 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 = np_box_list.BoxList( np.hstack([y_min, x_min, y_max, x_max])) fields = boxlist.get_extra_fields() for field in fields: extra_field_data = boxlist.get_field(field) scaled_boxlist.add_field(field, extra_field_data) return scaled_boxlist
def clip_to_window(boxlist, window): """Clip bounding boxes to a window. This op clips input bounding boxes (represented by bounding box corners) to a window, optionally filtering out boxes that do not overlap at all with the window. Args: boxlist: BoxList holding M_in boxes window: a numpy array of shape [4] representing the [y_min, x_min, y_max, x_max] window to which the op should clip boxes. Returns: a BoxList holding M_out boxes where M_out <= M_in """ y_min, x_min, y_max, x_max = np.array_split(boxlist.get(), 4, axis=1) win_y_min = window[0] win_x_min = window[1] win_y_max = window[2] win_x_max = window[3] y_min_clipped = np.fmax(np.fmin(y_min, win_y_max), win_y_min) y_max_clipped = np.fmax(np.fmin(y_max, win_y_max), win_y_min) x_min_clipped = np.fmax(np.fmin(x_min, win_x_max), win_x_min) x_max_clipped = np.fmax(np.fmin(x_max, win_x_max), win_x_min) clipped = np_box_list.BoxList( np.hstack([y_min_clipped, x_min_clipped, y_max_clipped, x_max_clipped])) clipped = _copy_extra_fields(clipped, boxlist) areas = area(clipped) nonzero_area_indices = np.reshape(np.nonzero(np.greater(areas, 0.0)), [-1]).astype(np.int32) return gather(clipped, nonzero_area_indices)
def test_with_no_scores_field(self): boxlist = np_box_list.BoxList(self._boxes) max_output_size = 3 iou_threshold = 0.5 with self.assertRaises(ValueError): np_box_list_ops.non_max_suppression(boxlist, max_output_size, iou_threshold)
def setUp(self): self._boxes = np.array([[0, 0, 1, 1], [0, 0.1, 1, 1.1], [0, -0.1, 1, 0.9], [0, 10, 1, 11], [0, 10.1, 1, 11.1], [0, 100, 1, 101]], dtype=float) self._boxlist = np_box_list.BoxList(self._boxes)
def test_select_from_ten_indentical_boxes(self): boxes = np.array(10 * [[0, 0, 1, 1]], dtype=float) boxlist = np_box_list.BoxList(boxes) boxlist.add_field('scores', np.array(10 * [0.8])) iou_threshold = .5 max_output_size = 3 expected_boxes = np.array([[0, 0, 1, 1]], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes)
def setUp(self): boxes = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) self.boxlist = np_box_list.BoxList(boxes) self.boxlist.add_field('scores', np.array([0.5, 0.9, 0.4], dtype=float)) self.boxlist.add_field('labels', np.array([[0, 0, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 1]], dtype=int))
def test_select_at_most_two_from_three_clusters(self): boxlist = np_box_list.BoxList(self._boxes) boxlist.add_field('scores', np.array([.9, .75, .6, .95, .5, .3], dtype=float)) max_output_size = 2 iou_threshold = 0.5 expected_boxes = np.array([[0, 10, 1, 11], [0, 0, 1, 1]], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes)
def test_nms_disabled_max_output_size_equals_three(self): boxlist = np_box_list.BoxList(self._boxes) boxlist.add_field('scores', np.array([.9, .75, .6, .95, .2, .3], dtype=float)) max_output_size = 3 iou_threshold = 1. # No NMS expected_boxes = np.array( [[0, 10, 1, 11], [0, 0, 1, 1], [0, 0.1, 1, 1.1]], dtype=float) nms_boxlist = np_box_list_ops.non_max_suppression( boxlist, max_output_size, iou_threshold) self.assertAllClose(nms_boxlist.get(), expected_boxes)
def _get_overlaps_and_scores_box_mode(self, detected_boxes, detected_scores, groundtruth_boxes, groundtruth_is_group_of_list): """Computes overlaps and scores between detected and groudntruth boxes. Args: detected_boxes: A numpy array of shape [N, 4] representing detected box coordinates detected_scores: A 1-d numpy array of length N representing classification score groundtruth_boxes: A numpy array of shape [M, 4] representing ground truth box coordinates groundtruth_is_group_of_list: A boolean numpy array of length M denoting whether a ground truth box has group-of tag. If a groundtruth box is group-of box, every detection matching this box is ignored. Returns: iou: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If gt_non_group_of_boxlist.num_boxes() == 0 it will be None. ioa: A float numpy array of size [num_detected_boxes, num_gt_boxes]. If gt_group_of_boxlist.num_boxes() == 0 it will be None. scores: The score of the detected boxlist. num_boxes: Number of non-maximum suppressed detected boxes. """ detected_boxlist = np_box_list.BoxList(detected_boxes) detected_boxlist.add_field('scores', detected_scores) detected_boxlist = np_box_list_ops.non_max_suppression( detected_boxlist, self.nms_max_output_boxes, self.nms_iou_threshold) gt_non_group_of_boxlist = np_box_list.BoxList( groundtruth_boxes[~groundtruth_is_group_of_list]) gt_group_of_boxlist = np_box_list.BoxList( groundtruth_boxes[groundtruth_is_group_of_list]) iou = np_box_list_ops.iou(detected_boxlist, gt_non_group_of_boxlist) ioa = np.transpose( np_box_list_ops.ioa(gt_group_of_boxlist, detected_boxlist)) scores = detected_boxlist.get_field('scores') num_boxes = detected_boxlist.num_boxes() return iou, ioa, scores, num_boxes
def concatenate(boxlists, fields=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. 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 """ 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, np_box_list.BoxList): raise ValueError( 'all elements of boxlists should be BoxList objects') concatenated = np_box_list.BoxList( np.vstack([boxlist.get() for boxlist in boxlists])) if fields is None: fields = boxlists[0].get_extra_fields() for field in fields: first_field_shape = boxlists[0].get_field(field).shape first_field_shape = first_field_shape[1:] for boxlist in boxlists: if not boxlist.has_field(field): raise ValueError('boxlist must contain all requested fields') field_shape = boxlist.get_field(field).shape field_shape = field_shape[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 = np.concatenate( [boxlist.get_field(field) for boxlist in boxlists], axis=0) concatenated.add_field(field, concatenated_field) return concatenated
def setUp(self): boxes = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) self.boxlist = np_box_list.BoxList(boxes)
def test_get_field_with_existed_field(self): boxes = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) boxlist = np_box_list.BoxList(boxes) self.assertTrue(np.allclose(boxlist.get_field('boxes'), boxes))
def test_has_field_with_nonexisted_field(self): boxes = np.array([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0], [0.0, 0.0, 20.0, 20.0]], dtype=float) boxlist = np_box_list.BoxList(boxes) self.assertFalse(boxlist.has_field('scores'))