Skip to content

Commit

Permalink
unit test added
Browse files Browse the repository at this point in the history
  • Loading branch information
DerrickXuNu committed Jun 23, 2021
1 parent ab9912b commit 676273e
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 7 deletions.
17 changes: 10 additions & 7 deletions opencda/core/sensing/perception/sensor_transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,17 @@ def bbx_to_world(cords, vehicle):
"""
Convert bounding box coordinate at vehicle reference to world reference.
Args:
cords (np.ndarray): Bounding box coordinates with 8 vertices.
cords (np.ndarray): Bounding box coordinates with 8 vertices, shape (n, 4)
vehicle (carla.vehicle or ObstacleVehicle): vehicle object.
Returns:
bb_world_cords: np.ndarray
Bounding box coordinates under word reference.
"""
bb_transform = carla.Transform(vehicle.bounding_box.location)
if hasattr(vehicle.bounding_box, 'transform'):
bb_transform = vehicle.bounding_box.transform
else:
bb_transform = carla.Transform(vehicle.bounding_box.location)
# bounding box to vehicle transformation matrix
bb_vehicle_matrix = x_to_world_transformation(bb_transform)

Expand Down Expand Up @@ -169,31 +172,31 @@ def vehicle_to_sensor(cords, vehicle, sensor_transform):
"""
Transform coordinates from vehicle reference to sensor reference
Args:
cords (np.ndarray): Coordinates under vehicle reference, shape (4, n)
cords (np.ndarray): Coordinates under vehicle reference, shape (n, 4)
vehicle (carla.vehicle or ObstacleVehicle): vehicle object.
sensor_transform (carla.Transform): sensor position in the world, shape(3, 1)
Returns:
(np.ndarray): Coordinates in sensor reference.
(np.ndarray): Coordinates in sensor reference, shape(4, n).
"""
world_cord = bbx_to_world(cords, vehicle)
sensor_cord = world_to_sensor(world_cord, sensor_transform)

return sensor_cord


def get_bounding_box(vehicle, sensor, sensor_transform):
def get_bounding_box(vehicle, camera, sensor_transform):
"""
Get vehicle bounding box and project to sensor image
Args:
vehicle (carla.vehicle or ObstacleVehicle): vehicle object.
sensor (carla.sensor.camera.rgb): The CARLA sensor object.
camera (carla.sensor.camera.rgb): The CARLA sensor object.
sensor_transform (carla.Transform): sensor position in the world
Returns:
(np.ndarray): Bounding box coordinates in sensor image.
"""
camera_k_matrix = get_camera_intrinsic(sensor)
camera_k_matrix = get_camera_intrinsic(camera)
# bb_cords is relative to bbx center(approximate the vehicle center)
bb_cords = create_bb_points(vehicle)

Expand Down
Empty file added test/__init__.py
Empty file.
102 changes: 102 additions & 0 deletions test/mocked_carla.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
"""
Mock Carla for unit tests.
"""

# Author: Runsheng Xu <[email protected]>
# License: MIT

import numpy as np


class Location(object):
""" A mock class for Location. """

def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z


class Transform(object):
"""A mock class for transform"""

def __init__(self, x, y, z, pitch=0, yaw=0, roll=0):
self.location = Location(x, y, z)
self.rotation = Rotation(pitch, yaw, roll)


class Rotation(object):
""" A mock class for Rotation. """

def __init__(self, pitch, yaw, roll):
self.pitch = pitch
self.yaw = yaw
self.roll = roll


class Vector3D(object):
""" A mock class for Vector3D. """

def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z


class Camera(object):
"""A mock class for camera. """

def __init__(self, attributes: dict):
self.attributes = attributes
self.transform = Transform(x=10, y=10, z=10)

def get_transform(self):
return self.transform


class Lidar(object):
"""A mock class for lidar."""

def __init__(self, attributes: dict):
self.attributes = attributes
self.transform = Transform(x=11, y=11, z=11)

def get_transform(self):
return self.transform


class BoundingBox(object):
"""
A mock class for bounding box.
"""

def __init__(self, corners):
"""
Construct class.
Args:
corners (nd.nparray): Eight corners of the bounding box. shape:(8, 3)
"""
center_x = np.mean(corners[:, 0])
center_y = np.mean(corners[:, 1])
center_z = np.mean(corners[:, 2])

extent_x = (np.max(corners[:, 0]) - np.min(corners[:, 0])) / 2
extent_y = (np.max(corners[:, 1]) - np.min(corners[:, 1])) / 2
extent_z = (np.max(corners[:, 2]) - np.min(corners[:, 2])) / 2

self.location = Location(x=center_x, y=center_y, z=center_z)
self.transform = Transform(x=center_x, y=center_y, z=center_z)
self.extent = Vector3D(x=extent_x, y=extent_y, z=extent_z)


class Vehicle(object):
"""A mock class for vehicle"""

def __init__(self):
corner = np.random.random((8, 3))
self.transform = Transform(x=12, y=12, z=12)
self.bounding_box = BoundingBox(corner)

def get_transform(self):
return self.transform
76 changes: 76 additions & 0 deletions test/test_sensor_transformation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
"""
Unit test for sensor transformation
"""
# Author: Runsheng Xu <[email protected]>
# License: MIT

import os
import sys
import unittest

# temporary solution for relative imports in case opencda is not installed
# if opencda is installed, no need to use the following line
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../opencda')))
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '.')))

import mocked_carla as mcarla
from opencda.core.sensing.perception.sensor_transformation import *


class TestSensorTransformation(unittest.TestCase):
def setUp(self):
# random cords, [(x, y, z, 1), n]
self.cords = np.random.random(size=(4, 10))
self.vehicle = mcarla.Vehicle()
self.camera = mcarla.Camera({'image_size_x': 600,
'image_size_y': 800,
'fov': 90})
self.lidar = mcarla.Lidar({'channels': 32,
'range': 50})

self.camera_transform = mcarla.Transform(x=11, y=11, z=11)
self.lidar_transform = mcarla.Transform(x=10, y=10, z=10)

self.rgb_image = np.random.randint(0, 255, size=(800, 600, 3)).astype('uint8')
self.point_cloud = np.random.random(size=(100, 4))

def test_x_to_world_transformation(self):
assert x_to_world_transformation(self.lidar_transform).shape == (4, 4)
assert x_to_world_transformation(self.lidar_transform)[3, 3] == 1

def test_world_to_sensor(self):
assert world_to_sensor(self.cords, self.lidar_transform).shape == (4, self.cords.shape[1])

def test_sensor_to_world(self):
assert sensor_to_world(self.cords, self.lidar_transform).shape == (4, self.cords.shape[1])

def test_get_camera_intrinsic(self):
assert get_camera_intrinsic(self.camera).shape == (3, 3)
assert get_camera_intrinsic(self.camera)[2, 2] == 1

def test_create_bb_points(self):
assert create_bb_points(self.vehicle).shape == (8, 4)
assert create_bb_points(self.vehicle)[:, 3].all() == 1

def test_bbx_to_world(self):
assert bbx_to_world(self.cords.T, self.vehicle).shape == (4, self.cords.shape[1])

def test_vehicle_to_sensor(self):
assert vehicle_to_sensor(self.cords.T, self.vehicle, self.camera_transform).shape == (4, self.cords.shape[1])

def test_get_bounding_box(self):
assert get_bounding_box(self.vehicle, self.camera, self.camera_transform).shape == (8, 3)

def test_get_2d_bb(self):
assert get_2d_bb(self.vehicle, self.camera, self.camera_transform).shape == (2, 2)

def test_project_lidar_to_camera(self):
assert project_lidar_to_camera(self.lidar, self.camera, self.point_cloud, self.rgb_image)[1].shape == \
(self.point_cloud.shape[0], 3)
assert project_lidar_to_camera(self.lidar, self.camera, self.point_cloud, self.rgb_image)[0].shape == \
self.rgb_image.shape


if __name__ == '__main__':
unittest.main()

0 comments on commit 676273e

Please sign in to comment.