Exemplo n.º 1
0
    def set_objects(self, object_labels, colour_scheme=None,
                    show_orientations=True):
        """
        Parses a list of ObjectLabel to set boxes and their colours

        :param object_labels: list of ObjectLabel to visualize
        :param colour_scheme: colours for each class (e.g. COLOUR_SCHEME_KITTI)
        :param show_orientations: (optional) if True, show box orientations
        """
        box_corners = []
        box_colours = []

        pyramid_tips = None
        if show_orientations:
            pyramid_tips = []

        for obj in object_labels:

            # Ignore DontCare boxes since they are at (-1000, -1000, -1000)
            if obj.type == 'DontCare':
                continue

            # Get box corners
            corners = np.array(obj_utils.compute_box_corners_3d(obj))
            if corners.size != 0:
                box_corners.append(corners.transpose())

                # Get colours
                if colour_scheme is not None:
                    if obj.type in colour_scheme:
                        box_colours.append(colour_scheme[obj.type])
                    else:
                        # Default (White)
                        box_colours.append((255, 255, 255))

                if show_orientations:
                    # Overwrite self.vtk_actor to contain both actors
                    vtk_boxes_actor = self.vtk_actor
                    self.vtk_actor = vtk.vtkAssembly()

                    self.vtk_actor.AddPart(vtk_boxes_actor)
                    self.vtk_actor.AddPart(self.vtk_pyramid_actor)

                    # Distance off the ground
                    arrow_height = obj.h / 2.0
                    pyramid_tip_length = obj.l * 0.2
                    half_obj_l = obj.l / 2.0
                    # Distance from centroid
                    pyramid_tip_dist = half_obj_l + pyramid_tip_length

                    # Start and end points
                    # arrow_start = np.add(obj.t, [0, -arrow_height, 0])
                    pyramid_tip =\
                        np.add(obj.t, [pyramid_tip_dist * np.cos(obj.ry),
                                       -arrow_height,
                                       pyramid_tip_dist * -np.sin(obj.ry)])
                    pyramid_tips.append(pyramid_tip)

        self._set_boxes(box_corners, box_colours, pyramid_tips)
Exemplo n.º 2
0
    def set_objects(self,
                    object_labels,
                    colour_scheme=None,
                    show_orientations=False):
        """
        Parses a list of ObjectLabel to set boxes and their colours

        :param object_labels: list of ObjectLabel to visualize
        :param colour_scheme: colours for each class (e.g. COLOUR_SCHEME_KITTI)
        :param show_orientations: (optional) if True, self.vtk_lines_actor
            can be used to display the orientations of each box
        """
        box_corners = []
        box_colours = []

        orientation_vectors = None
        if show_orientations:
            orientation_vectors = []

        for obj in object_labels:

            # Ignore DontCare boxes since they are at (-1000, -1000, -1000)
            if obj.type == 'DontCare':
                continue

            # Get box corners
            corners = np.array(obj_utils.compute_box_corners_3d(obj))
            if corners.size != 0:
                box_corners.append(corners.transpose())

                # Get colours
                if colour_scheme is not None:
                    if obj.type in colour_scheme:
                        box_colours.append(colour_scheme[obj.type])
                    else:
                        # Default (White)
                        box_colours.append((255, 255, 255))

                if show_orientations:
                    # Overwrite self.vtk_actor to contain both actors
                    vtk_boxes_actor = self.vtk_actor
                    self.vtk_actor = vtk.vtkAssembly()
                    self.vtk_actor.AddPart(vtk_boxes_actor)
                    self.vtk_actor.AddPart(self.vtk_lines_actor)

                    # Distance off the ground
                    arrow_height = obj.h / 2.0

                    # Start and end points
                    arrow_start = np.add(obj.t, [0, -arrow_height, 0])
                    arrow_end = np.add(obj.t, [
                        obj.l * np.cos(obj.ry), -arrow_height,
                        obj.l * -np.sin(obj.ry)
                    ])
                    orientation_vectors.append([arrow_start, arrow_end])

        self._set_boxes(box_corners, box_colours, orientation_vectors)
Exemplo n.º 3
0
    def test_compute_box_3d(self):
        # read in calib file and label file and mat file
        calib_frame = calib.read_calibration(self.test_data_calib_dir, 724513)
        objects = obj_utils.read_labels(self.test_data_label_dir, 5258)
        label_true = scipy.io.loadmat(self.test_data_dir + '/compute3d.mat')

        # compute
        corners_3d = obj_utils.compute_box_corners_3d(objects[0])
        corners, face_idx = obj_utils.project_box3d_to_image(
            corners_3d, calib_frame.p2)
        # compare data
        np.testing.assert_almost_equal(corners, label_true['corners'])

        orientation = obj_utils.compute_orientation_3d(objects[0], calib_frame.p2)

        # -1 for index in python vs matlab
        self.assertTrue((face_idx == label_true['face_idx']-1).all())

        # Test orientation
        self.assertAlmostEqual(orientation.all(),
                               label_true['orientation'].all())

        return
Exemplo n.º 4
0
def draw_box_3d(ax,
                obj,
                p,
                show_orientation=True,
                color_table=None,
                line_width=3,
                double_line=True,
                box_color=None):
    """Draws the 3D boxes given the subplot, object label,
    and frame transformation matrix

    :param ax: subplot handle
    :param obj: object file to draw bounding box
    :param p:stereo frame transformation matrix

    :param show_orientation: optional, draw a line showing orientaion
    :param color_table: optional, a custom table for coloring the boxes,
        should have 4 values to match the 4 truncation values. This color
        scheme is used to display boxes colored based on difficulty.
    :param line_width: optional, custom line width to draw the box
    :param double_line: optional, overlays a thinner line inside the box lines
    :param box_color: optional, use a custom color for box (instead of
        the default color_table.
    """

    corners3d = obj_utils.compute_box_corners_3d(obj)
    corners, face_idx = obj_utils.project_box3d_to_image(corners3d, p)

    # define colors
    if color_table:
        if len(color_table) != 4:
            raise ValueError('Invalid color table length, must be 4')
    else:
        color_table = ["#00cc00", 'y', 'r', 'w']

    trun_style = ['solid', 'dashed']
    trc = int(obj.truncation > 0.1)

    if len(corners) > 0:
        for i in range(4):
            x = np.append(corners[0, face_idx[i, ]], corners[0, face_idx[i,
                                                                         0]])
            y = np.append(corners[1, face_idx[i, ]], corners[1, face_idx[i,
                                                                         0]])

            # Draw the boxes
            if box_color is None:
                box_color = color_table[int(obj.occlusion)]

            ax.plot(x,
                    y,
                    linewidth=line_width,
                    color=box_color,
                    linestyle=trun_style[trc])

            # Draw a thinner second line inside
            if double_line:
                ax.plot(x, y, linewidth=line_width / 3.0, color='b')

    if show_orientation:
        # Compute orientation 3D
        orientation = obj_utils.compute_orientation_3d(obj, p)

        if orientation is not None:
            x = np.append(orientation[0, ], orientation[0, ])
            y = np.append(orientation[1, ], orientation[1, ])

            # draw the boxes
            ax.plot(x, y, linewidth=4, color='w')
            ax.plot(x, y, linewidth=2, color='k')
Exemplo n.º 5
0
def generate_negative_3d_bb(obj_label, boxes3d, iou_threshold_min,
                            iou_threshold_max, samples):
    """Generates negative 3D bounding boxes.

    This is the 3D version of generate_negative_3d_bb.

    Keyword arguments:
        obj_label: single label for a detected 3D object
        boxes3d: a list of numpy array representing all
                 3D bounding boxes in the image
        iou_threshold_min: determines the min variation
            between the original iou and the negative samples
        iou_threshold_max: determines the max variation
            between the original iou and the negative samples
        samples: number of negative samples per detected object

    Returns: a list of generated ObjectLabels
    """
    box_corners = od.compute_box_corners_3d(obj_label)
    # make sure this is not empty
    assert (len(box_corners) > 0)
    P1 = box_corners[:, 0]
    P2 = box_corners[:, 1]
    P4 = box_corners[:, 3]

    current_samples = 0
    new_objects = []

    while current_samples < samples:
        # Generate random 3D point inside the box
        # we keep the same y, only generate x and z
        new_xp = float(np.random.uniform(P1[0], P4[0], 1))
        new_zp = float(np.random.uniform(P1[2], P2[2], 1))

        # create a new ObjectLabel
        new_obj = copy.copy(obj_label)
        # update the new obj.t
        # everything else is the same, only changing the
        # centroid point t which remains the same along
        # the y direction
        new_obj.t = (new_xp, obj_label.t[1], new_zp)

        _, box_to_test, _ = od.build_bbs_from_objects([new_obj], 'All')

        assert (len(box_to_test) == 1)
        # we are dealing with one box here so its the first element
        iou_3d = evaluation.three_d_iou(box_to_test[0], boxes3d)

        # check if iou_3d is a list, take the largest
        # this compares to all the boxes
        if isinstance(iou_3d, np.ndarray):
            iou_max = np.max(iou_3d)
        else:
            iou_max = iou_3d

        if iou_threshold_min < iou_max < iou_threshold_max:
            # keep the new object label
            new_objects.append(new_obj)
            current_samples += 1

    return new_objects
Exemplo n.º 6
0
def project_to_image_space(box_3d,
                           calib_p2,
                           truncate=False,
                           image_size=None,
                           discard_before_truncation=True):
    """ Projects a box_3d into image space

    Args:
        box_3d: single box_3d to project
        calib_p2: stereo calibration p2 matrix
        truncate: if True, 2D projections are truncated to be inside the image
        image_size: [w, h] must be provided if truncate is True,
            used for truncation
        discard_before_truncation: If True, discard boxes that are larger than
            80% of the image in width OR height BEFORE truncation. If False,
            discard boxes that are larger than 80% of the width AND
            height AFTER truncation.

    Returns:
        Projected box in image space [x1, y1, x2, y2]
            Returns None if box is not inside the image
    """

    format_checker.check_box_3d_format(box_3d)

    obj_label = box_3d_encoder.box_3d_to_object_label(box_3d)
    corners_3d = obj_utils.compute_box_corners_3d(obj_label)

    projected = calib_utils.project_to_image(corners_3d, calib_p2)

    x1 = np.amin(projected[0])
    y1 = np.amin(projected[1])
    x2 = np.amax(projected[0])
    y2 = np.amax(projected[1])

    img_box = np.array([x1, y1, x2, y2])

    if truncate:
        if not image_size:
            raise ValueError('Image size must be provided')

        image_w = image_size[0]
        image_h = image_size[1]

        # Discard invalid boxes (outside image space)
        if img_box[0] > image_w or \
                img_box[1] > image_h or \
                img_box[2] < 0 or \
                img_box[3] < 0:
            return None

        # Discard boxes that are larger than 80% of the image width OR height
        if discard_before_truncation:
            img_box_w = img_box[2] - img_box[0]
            img_box_h = img_box[3] - img_box[1]
            if img_box_w > (image_w * 0.8) or img_box_h > (image_h * 0.8):
                return None

        # Truncate remaining boxes into image space
        if img_box[0] < 0:
            img_box[0] = 0
        if img_box[1] < 0:
            img_box[1] = 0
        if img_box[2] > image_w:
            img_box[2] = image_w
        if img_box[3] > image_h:
            img_box[3] = image_h

        # Discard boxes that are covering the the whole image after truncation
        if not discard_before_truncation:
            img_box_w = img_box[2] - img_box[0]
            img_box_h = img_box[3] - img_box[1]
            if img_box_w > (image_w * 0.8) and img_box_h > (image_h * 0.8):
                return None

    return img_box