def testTransformPoint(self): transform = transform_util.MakeCarToImageTransform( pixels_per_meter=10.0, image_ref_x=250, image_ref_y=750, flip_axes=False) tx, ty, tz = transform_util.TransformPoint(transform, 0.0, 1.0, 0.0) # X gets translated. self.assertEqual(250., tx) # Y gets translated and scaled by pixels_per_meter. self.assertEqual(760., ty) self.assertEqual(0., tz)
def testCopyTransform(self): # Same transform as above. transform = transform_util.MakeCarToImageTransform( pixels_per_meter=10.0, image_ref_x=250, image_ref_y=750, flip_axes=False) # Test that copying the transform yields the same result. copy_transform = transform_util.CopyTransform(transform) tx, ty, tz = transform_util.TransformPoint(copy_transform, 0.0, 1.0, 0.0) self.assertEqual(250., tx) self.assertEqual(760., ty) self.assertEqual(0., tz)
def DrawTopDown(lasers): """Draw the laser points in the top down car view.""" # For every laser point, convert the point to a top down image. # Lasers is a [r, b, s*6] tensor where b is the batch size. # Transpose back to batch major lasers = np.transpose(lasers, [1, 0, 2]) # Reshape data to get all points in the spin. lasers = np.reshape(lasers, [np.shape(lasers)[0], -1]) car_to_image_transform = _CarToImageTransform() # Create an empty image of the appropriate size. batch_size = min(8, np.shape(lasers)[0]) images = np.zeros(shape=(batch_size, 1000, 500, 3), dtype=np.uint8) # TODO(vrv): Slice the lasers into [b, x, y, z] matrix # and then do a batch_matmul on all points at once. max_npoints = np.shape(lasers)[1] // 6 for b in range(batch_size): for i in range(max_npoints): index = i * 6 x = lasers[b][index] y = lasers[b][index + 1] z = lasers[b][index + 2] # TODO(vrv): Use lasers_padding to filter out invalid points. # For now, just assume that all zeros means that the point # shouldn't be drawn. if x == 0 and y == 0 and z == 0: continue tx, ty, _ = transform_util.TransformPoint(car_to_image_transform, x, y, z) # Point outside image. if tx < 0 or ty < 0 or tx >= images.shape[2] or ty >= images.shape[ 1]: continue # Fill in that point in the image images[b, int(ty), int(tx), :] = (255, 255, 255) return images
def _DrawLasers(self, images, points_xyz, points_padding, transform): """Draw laser points.""" for batch_idx in range(images.shape[0]): for points_idx in range(points_xyz.shape[1]): if points_padding[batch_idx, points_idx] == 0: x, y, z = points_xyz[batch_idx, points_idx, :3] tx, ty, _ = transform_util.TransformPoint( transform, x, y, z) if tx < 0 or ty < 0 or tx >= images.shape[ 2] or ty >= images.shape[1]: continue # Drop ground points from visualization. if z < self._ground_removal_threshold: # Brown out the color for ground points. color = (64, 48, 48) else: color = (255, 255, 255) images[batch_idx, int(ty), int(tx), :] = color
def DrawTrajectory(image, bboxes, masks, labels, is_groundtruth): """Draw the trajectory of bounding boxes on 'image'. Args: image: The uint8 image array to draw on. Assumes [1000, 500, 3] input with RGB value ranges. bboxes: A [num_steps, num_objects, 5] float array containing the bounding box information over a sequence of steps. bboxes are expected to be in car coordinates. masks: A [num_steps, num_objects] integer array indicating whether the corresponding bbox entry in bboxes is present (1 = present). labels: A [num_steps, num_objects] integer label indicating which class is being predicted. Used for colorizing based on labels. is_groundtruth: True if the scene is the groundtruth vs. the predicted. Returns: The updated image array. """ image = Image.fromarray(np.uint8(image)).convert('RGB') draw = ImageDraw.Draw(image) try: font = ImageFont.truetype('arial.ttf', 20) except IOError: font = ImageFont.load_default() pixels_per_meter = 10. image_ref_x = 250. image_ref_y = 750. car_to_image_transform = transform_util.MakeCarToImageTransform( pixels_per_meter=pixels_per_meter, image_ref_x=image_ref_x, image_ref_y=image_ref_y, flip_axes=True) # Iterate over each object and produce the series of visualized trajectories # over time. for object_idx in range(bboxes.shape[1]): # Annotate the box with the class type label = labels[0, object_idx] # Choose a label_consistent color. color = PIL_COLOR_LIST[label % len(PIL_COLOR_LIST)] # Make predictions white. if not is_groundtruth: color = 'white' # Convert string color name to RGB so we can manipulate it. color_rgb = ImageColor.getrgb(color) # For each sample, extract the data, transform to image coordinates, and # store in centroids. centroids = [] for time in range(bboxes.shape[0]): if masks[time, object_idx] == 0: continue center_x, center_y, width, height, heading = bboxes[time, object_idx, :] # Compute the new heading. heading = transform_util.TransformHeading(car_to_image_transform, heading) # Transform from car to image coords. x, y, _ = transform_util.TransformPoint(car_to_image_transform, center_x, center_y, 0.0) # Hack to scale from meters to pixels. width *= pixels_per_meter height *= pixels_per_meter # Collect the centroids of all of the points. centroids.append((x, y, heading)) # Draw the groundtruth bounding box at the first timestep. if is_groundtruth and time == 0: # Draw a rectangle rect = MakeRectangle(height, width, heading, offset=(x, y)) rect += [rect[0]] draw.line(rect, fill=color_rgb, width=4) delta = 20 # Annotate the box with the object index draw.text((x + delta, y + delta), str(object_idx), fill='white', font=font) # Draw a callout draw.line([(x, y), (x + delta, y + delta)], fill='white', width=1) # Extract the point pairs from centroids and draw a line through them. point_pairs = [] for (x, y, heading) in centroids: point_pairs.append((x, y)) if point_pairs: draw.line(point_pairs, width=4, fill=color_rgb) # Draw the centroids. triangle_color_rgb = color_rgb for i, (x, y, heading) in enumerate(centroids): if i == 0: # Draw the heading for the first timestep. scale = 25 if is_groundtruth else 15 DrawHeadingTriangle(draw, x, y, heading, triangle_color_rgb, scale) else: # Draw a circle for the centroids of other timesteps. outline_color = color_rgb circle_size = 5 if is_groundtruth else 3 DrawCircle(draw, x, y, fill=triangle_color_rgb, outline=outline_color, circle_size=circle_size) # Desaturate the color with every timestep. increment = 45 # Allow this to be modified? triangle_color_rgb = (triangle_color_rgb[0] - increment, triangle_color_rgb[1] - increment, triangle_color_rgb[2] - increment) return np.array(image)