def _EvaluateIfNecessary(self, name):
        """Create a camera image summary if not already created."""
        if self._summary is not None:
            return

        ret = tf.Summary()

        for sample_idx, sample in enumerate(self._sampler.samples):
            batch_size = sample.camera_images.shape[0]

            for batch_idx in range(batch_size):
                image = sample.camera_images[batch_idx]

                # [num bboxes, 8, 2].
                bbox_corners = sample.bbox_corners[batch_idx]

                # [num_bboxes]
                bbox_scores = sample.bbox_scores[batch_idx]

                def Draw3DBoxes(fig,
                                axes,
                                bbox_corners=bbox_corners,
                                bbox_scores=bbox_scores):
                    """Draw 3d bounding boxes."""
                    del fig
                    for bbox_id in range(bbox_corners.shape[0]):
                        # Skip visualizing low-scoring boxes.
                        bbox_score = bbox_scores[bbox_id]
                        if bbox_score < self._bbox_score_threshold:
                            continue
                        bbox_data = bbox_corners[bbox_id]

                        # Draw the score of each box.
                        #
                        # Turn score into an integer for better display.
                        center_x = np.mean(bbox_data[:, 0])
                        center_y = np.mean(bbox_data[:, 1])
                        bbox_score = int(bbox_score * 100)
                        text = axes.text(center_x,
                                         center_y,
                                         bbox_score,
                                         fontsize=12,
                                         color='red',
                                         fontweight='bold')
                        text.set_bbox(dict(facecolor='yellow', alpha=0.4))

                        # The BBoxToCorners function produces the points
                        # in a deterministic order, which we use to draw
                        # the faces of the polygon.
                        #
                        # The first 4 points are the "top" of the bounding box.
                        # The second 4 points are the "bottom" of the bounding box.
                        #
                        # We then draw the last 4 connecting points by choosing
                        # two of the connecting faces in the right order.
                        face_points = []
                        face_points += [[
                            bbox_data[0, :], bbox_data[1, :], bbox_data[2, :],
                            bbox_data[3, :]
                        ]]
                        face_points += [[
                            bbox_data[4, :], bbox_data[5, :], bbox_data[6, :],
                            bbox_data[7, :]
                        ]]
                        face_points += [[
                            bbox_data[1, :], bbox_data[2, :], bbox_data[6, :],
                            bbox_data[5, :]
                        ]]
                        face_points += [[
                            bbox_data[0, :], bbox_data[3, :], bbox_data[7, :],
                            bbox_data[4, :]
                        ]]
                        for face in face_points:
                            # Each face is a list of 4 x,y points
                            face_xy = np.array(face)
                            axes.add_patch(
                                matplotlib_patches.Polygon(face_xy,
                                                           closed=True,
                                                           edgecolor='red',
                                                           facecolor='none'))

                def Draw2DBoxes(fig,
                                axes,
                                bbox_corners=bbox_corners,
                                bbox_scores=bbox_scores):
                    """Draw 2d boxes on the figure."""
                    del fig
                    # Extract the 2D extrema of each bbox and the max score
                    for bbox_id in range(bbox_corners.shape[0]):
                        # Skip visualizing low-scoring boxes.
                        bbox_score = bbox_scores[bbox_id]
                        if bbox_score < self._bbox_score_threshold:
                            continue
                        bbox_data = bbox_corners[bbox_id]

                        ymin = np.min(bbox_data[:, 1])
                        xmin = np.min(bbox_data[:, 0])
                        ymax = np.max(bbox_data[:, 1])
                        xmax = np.max(bbox_data[:, 0])
                        height = ymax - ymin
                        width = xmax - xmin
                        # Turn score into an integer for better display.
                        bbox_score = int(bbox_score * 100)
                        text = axes.text(xmin,
                                         ymin,
                                         bbox_score,
                                         fontsize=12,
                                         color='red',
                                         fontweight='bold')
                        text.set_bbox(dict(facecolor='yellow', alpha=0.4))
                        axes.add_patch(
                            matplotlib_patches.Rectangle((xmin, ymin),
                                                         width,
                                                         height,
                                                         edgecolor='red',
                                                         facecolor='none'))

                # For each image, draw the boxes on that image.
                draw_fn = Draw3DBoxes if self._draw_3d_boxes else Draw2DBoxes
                image_summary = plot.Image(name='{}/{}/{}'.format(
                    name, sample_idx, batch_idx),
                                           aspect='equal',
                                           figsize=self._figsize,
                                           image=image,
                                           setter=draw_fn)
                ret.value.extend(image_summary.value)
        self._summary = ret
    def _EvaluateIfNecessary(self, name):
        """Create a top down image summary, if not already created."""
        if self._summary is not None:
            return

        tf.logging.info('Generating top down summary.')
        ret = tf.Summary()

        transform = self._top_down_transform

        for batch_idx, batch_sample in enumerate(self._sampler.samples):
            batch_size = batch_sample.labels.shape[0]
            visualization_labels = batch_sample.visualization_labels
            predicted_bboxes = batch_sample.predicted_bboxes
            visualization_weights = batch_sample.visualization_weights
            points_xyz = batch_sample.points_xyz
            points_padding = batch_sample.points_padding
            gt_bboxes_2d = batch_sample.gt_bboxes_2d
            gt_bboxes_2d_weights = batch_sample.gt_bboxes_2d_weights
            labels = batch_sample.labels
            difficulties = batch_sample.difficulties
            source_ids = batch_sample.source_ids

            # Create base images for entire batch that we will update.
            images = np.zeros(
                [batch_size, self._image_height, self._image_width, 3],
                dtype=np.uint8)

            # Draw lasers first, so that bboxes can be on top.
            self._DrawLasers(images, points_xyz, points_padding, transform)

            # Draw ground-truth bboxes.
            gt_bboxes_2d = np.where(
                np.expand_dims(gt_bboxes_2d_weights > 0, -1), gt_bboxes_2d,
                np.zeros_like(gt_bboxes_2d))
            transformed_gt_bboxes_2d = summary.TransformBBoxesToTopDown(
                gt_bboxes_2d, transform)

            summary.DrawBBoxesOnImages(images,
                                       transformed_gt_bboxes_2d,
                                       gt_bboxes_2d_weights,
                                       labels,
                                       self._class_id_to_name,
                                       groundtruth=True)

            # Draw predicted bboxes.
            predicted_bboxes = np.where(
                np.expand_dims(visualization_weights > 0, -1),
                predicted_bboxes, np.zeros_like(predicted_bboxes))
            transformed_predicted_bboxes = summary.TransformBBoxesToTopDown(
                predicted_bboxes, transform)

            summary.DrawBBoxesOnImages(images,
                                       transformed_predicted_bboxes,
                                       visualization_weights,
                                       visualization_labels,
                                       self._class_id_to_name,
                                       groundtruth=False)

            # Draw the difficulties on the image.
            self.DrawDifficulty(images, transformed_gt_bboxes_2d,
                                gt_bboxes_2d_weights, difficulties)

            for idx in range(batch_size):
                source_id = source_ids[idx]

                def AnnotateImage(fig, axes, source_id=source_id):
                    """Add source_id to image."""
                    del fig
                    # Draw in top middle of image.
                    text = axes.text(500,
                                     15,
                                     source_id,
                                     fontsize=16,
                                     color='blue',
                                     fontweight='bold',
                                     horizontalalignment='center')
                    text.set_path_effects([
                        path_effects.Stroke(linewidth=3,
                                            foreground='lightblue'),
                        path_effects.Normal()
                    ])

                image_summary = plot.Image(name='{}/{}/{}'.format(
                    name, batch_idx, idx),
                                           aspect='equal',
                                           figsize=self._figsize,
                                           image=images[idx, ...],
                                           setter=AnnotateImage)
                ret.value.extend(image_summary.value)

        tf.logging.info('Done generating top down summary.')
        self._summary = ret