Commit c9b69f5a authored by ZwwWayne's avatar ZwwWayne Committed by ChaimZhu
Browse files

Clean unit tests

parent a34823dc
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
import pytest
import torch
from mmdet3d.datasets import SUNRGBDDataset
def _generate_sunrgbd_dataset_config():
root_path = './tests/data/sunrgbd'
# in coordinate system refactor, this test file is modified
ann_file = './tests/data/sunrgbd/sunrgbd_infos.pkl'
class_names = ('bed', 'table', 'sofa', 'chair', 'toilet', 'desk',
'dresser', 'night_stand', 'bookshelf', 'bathtub')
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='LoadAnnotations3D'),
dict(
type='RandomFlip3D',
sync_2d=False,
flip_ratio_bev_horizontal=0.5,
),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.523599, 0.523599],
scale_ratio_range=[0.85, 1.15],
shift_height=True),
dict(type='PointSample', num_points=5),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D',
keys=['points', 'gt_bboxes_3d', 'gt_labels_3d'],
meta_keys=[
'file_name', 'pcd_horizontal_flip', 'sample_idx',
'pcd_scale_factor', 'pcd_rotation'
]),
]
modality = dict(use_lidar=True, use_camera=False)
return root_path, ann_file, class_names, pipelines, modality
def _generate_sunrgbd_multi_modality_dataset_config():
root_path = './tests/data/sunrgbd'
ann_file = './tests/data/sunrgbd/sunrgbd_infos.pkl'
class_names = ('bed', 'table', 'sofa', 'chair', 'toilet', 'desk',
'dresser', 'night_stand', 'bookshelf', 'bathtub')
img_norm_cfg = dict(
mean=[103.530, 116.280, 123.675], std=[1.0, 1.0, 1.0], to_rgb=False)
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='LoadImageFromFile'),
dict(type='LoadAnnotations3D'),
dict(type='LoadAnnotations', with_bbox=True),
dict(type='Resize', img_scale=(1333, 600), keep_ratio=True),
dict(type='RandomFlip', flip_ratio=0.0),
dict(type='Normalize', **img_norm_cfg),
dict(type='Pad', size_divisor=32),
dict(
type='RandomFlip3D',
sync_2d=False,
flip_ratio_bev_horizontal=0.5,
),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.523599, 0.523599],
scale_ratio_range=[0.85, 1.15],
shift_height=True),
dict(type='PointSample', num_points=5),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D',
keys=[
'img', 'gt_bboxes', 'gt_labels', 'points', 'gt_bboxes_3d',
'gt_labels_3d'
])
]
modality = dict(use_lidar=True, use_camera=True)
return root_path, ann_file, class_names, pipelines, modality
def test_getitem():
from os import path as osp
np.random.seed(0)
root_path, ann_file, class_names, pipelines, modality = \
_generate_sunrgbd_dataset_config()
sunrgbd_dataset = SUNRGBDDataset(
root_path, ann_file, pipelines, modality=modality)
data = sunrgbd_dataset[0]
points = data['points']._data
gt_bboxes_3d = data['gt_bboxes_3d']._data
gt_labels_3d = data['gt_labels_3d']._data
file_name = data['img_metas']._data['file_name']
pcd_horizontal_flip = data['img_metas']._data['pcd_horizontal_flip']
pcd_scale_factor = data['img_metas']._data['pcd_scale_factor']
pcd_rotation = data['img_metas']._data['pcd_rotation']
sample_idx = data['img_metas']._data['sample_idx']
pcd_rotation_expected = np.array([[0.99889565, 0.04698427, 0.],
[-0.04698427, 0.99889565, 0.],
[0., 0., 1.]])
expected_file_name = osp.join('./tests/data/sunrgbd', 'points/000001.bin')
assert file_name == expected_file_name
assert pcd_horizontal_flip is False
assert abs(pcd_scale_factor - 0.9770964398016714) < 1e-5
assert np.allclose(pcd_rotation, pcd_rotation_expected, 1e-3)
assert sample_idx == 1
expected_points = torch.tensor([[-0.9904, 1.2596, 0.1105, 0.0905],
[-0.9948, 1.2758, 0.0437, 0.0238],
[-0.9866, 1.2641, 0.0504, 0.0304],
[-0.9915, 1.2586, 0.1265, 0.1065],
[-0.9890, 1.2561, 0.1216, 0.1017]])
expected_gt_bboxes_3d = torch.tensor(
[[0.8308, 4.1168, -1.2035, 2.2493, 1.8444, 1.9245, 1.6486],
[2.3002, 4.8149, -1.2442, 0.5718, 0.8629, 0.9510, 1.6030],
[-1.1477, 1.8090, -1.1725, 0.6965, 1.5273, 2.0563, 0.0552]])
# coord sys refactor (rotation is correct but yaw has to be reversed)
expected_gt_bboxes_3d[:, 6:] = -expected_gt_bboxes_3d[:, 6:]
expected_gt_labels = np.array([0, 7, 6])
original_classes = sunrgbd_dataset.CLASSES
assert torch.allclose(points, expected_points, 1e-2)
assert torch.allclose(gt_bboxes_3d.tensor, expected_gt_bboxes_3d, 1e-3)
assert np.all(gt_labels_3d.numpy() == expected_gt_labels)
assert original_classes == class_names
SUNRGBD_dataset = SUNRGBDDataset(
root_path, ann_file, pipeline=None, classes=['bed', 'table'])
assert SUNRGBD_dataset.CLASSES != original_classes
assert SUNRGBD_dataset.CLASSES == ['bed', 'table']
SUNRGBD_dataset = SUNRGBDDataset(
root_path, ann_file, pipeline=None, classes=('bed', 'table'))
assert SUNRGBD_dataset.CLASSES != original_classes
assert SUNRGBD_dataset.CLASSES == ('bed', 'table')
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
path = tmpdir + 'classes.txt'
with open(path, 'w') as f:
f.write('bed\ntable\n')
SUNRGBD_dataset = SUNRGBDDataset(
root_path, ann_file, pipeline=None, classes=path)
assert SUNRGBD_dataset.CLASSES != original_classes
assert SUNRGBD_dataset.CLASSES == ['bed', 'table']
# test multi-modality SUN RGB-D dataset
np.random.seed(0)
root_path, ann_file, class_names, multi_modality_pipelines, modality = \
_generate_sunrgbd_multi_modality_dataset_config()
sunrgbd_dataset = SUNRGBDDataset(
root_path, ann_file, multi_modality_pipelines, modality=modality)
data = sunrgbd_dataset[0]
points = data['points']._data
gt_bboxes_3d = data['gt_bboxes_3d']._data
gt_labels_3d = data['gt_labels_3d']._data
img = data['img']._data
depth2img = data['img_metas']._data['depth2img']
expected_rt_mat = np.array([[0.97959, 0.012593, -0.20061],
[0.012593, 0.99223, 0.12377],
[0.20061, -0.12377, 0.97182]])
expected_k_mat = np.array([[529.5, 0., 0.], [0., 529.5, 0.],
[365., 265., 1.]])
rt_mat = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]
]) @ expected_rt_mat.transpose(1, 0)
expected_depth2img = expected_k_mat @ rt_mat
assert torch.allclose(points, expected_points, 1e-2)
assert torch.allclose(gt_bboxes_3d.tensor, expected_gt_bboxes_3d, 1e-3)
assert np.all(gt_labels_3d.numpy() == expected_gt_labels)
assert img.shape[:] == (3, 608, 832)
assert np.allclose(depth2img, expected_depth2img)
def test_evaluate():
if not torch.cuda.is_available():
pytest.skip()
from mmdet3d.core.bbox.structures import DepthInstance3DBoxes
root_path, ann_file, _, pipelines, modality = \
_generate_sunrgbd_dataset_config()
sunrgbd_dataset = SUNRGBDDataset(
root_path, ann_file, pipelines, modality=modality)
results = []
pred_boxes = dict()
pred_boxes['boxes_3d'] = DepthInstance3DBoxes(
torch.tensor(
[[1.0473, 4.1687, -1.2317, 2.3021, 1.8876, 1.9696, 1.6956],
[2.5831, 4.8117, -1.2733, 0.5852, 0.8832, 0.9733, 1.6500],
[-1.0864, 1.9045, -1.2000, 0.7128, 1.5631, 2.1045, 0.1022]]))
pred_boxes['labels_3d'] = torch.tensor([0, 7, 6])
pred_boxes['scores_3d'] = torch.tensor([0.5, 1.0, 1.0])
results.append(pred_boxes)
metric = [0.25, 0.5]
ap_dict = sunrgbd_dataset.evaluate(results, metric)
bed_precision_25 = ap_dict['bed_AP_0.25']
dresser_precision_25 = ap_dict['dresser_AP_0.25']
night_stand_precision_25 = ap_dict['night_stand_AP_0.25']
assert abs(bed_precision_25 - 1) < 0.01
assert abs(dresser_precision_25 - 1) < 0.01
assert abs(night_stand_precision_25 - 1) < 0.01
def test_show():
import tempfile
from os import path as osp
import mmcv
from mmdet3d.core.bbox import DepthInstance3DBoxes
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
root_path, ann_file, class_names, pipelines, modality = \
_generate_sunrgbd_dataset_config()
sunrgbd_dataset = SUNRGBDDataset(
root_path, ann_file, pipelines, modality=modality)
boxes_3d = DepthInstance3DBoxes(
torch.tensor(
[[1.1500, 4.2614, -1.0669, 1.3219, 2.1593, 1.0267, 1.6473],
[-0.9583, 2.1916, -1.0881, 0.6213, 1.3022, 1.6275, -3.0720],
[2.5697, 4.8152, -1.1157, 0.5421, 0.7019, 0.7896, 1.6712],
[0.7283, 2.5448, -1.0356, 0.7691, 0.9056, 0.5771, 1.7121],
[-0.9860, 3.2413, -1.2349, 0.5110, 0.9940, 1.1245, 0.3295]]))
scores_3d = torch.tensor(
[1.5280e-01, 1.6682e-03, 6.2811e-04, 1.2860e-03, 9.4229e-06])
labels_3d = torch.tensor([0, 0, 0, 0, 0])
result = dict(boxes_3d=boxes_3d, scores_3d=scores_3d, labels_3d=labels_3d)
results = [result]
sunrgbd_dataset.show(results, temp_dir, show=False)
pts_file_path = osp.join(temp_dir, '000001', '000001_points.obj')
gt_file_path = osp.join(temp_dir, '000001', '000001_gt.obj')
pred_file_path = osp.join(temp_dir, '000001', '000001_pred.obj')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
tmp_dir.cleanup()
# test show with pipeline
eval_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='DefaultFormatBundle3D',
class_names=class_names,
with_label=False),
dict(type='Collect3D', keys=['points'])
]
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
sunrgbd_dataset.show(results, temp_dir, show=False, pipeline=eval_pipeline)
pts_file_path = osp.join(temp_dir, '000001', '000001_points.obj')
gt_file_path = osp.join(temp_dir, '000001', '000001_gt.obj')
pred_file_path = osp.join(temp_dir, '000001', '000001_pred.obj')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
tmp_dir.cleanup()
# test multi-modality show
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
root_path, ann_file, class_names, multi_modality_pipelines, modality = \
_generate_sunrgbd_multi_modality_dataset_config()
sunrgbd_dataset = SUNRGBDDataset(
root_path, ann_file, multi_modality_pipelines, modality=modality)
sunrgbd_dataset.show(results, temp_dir, False, multi_modality_pipelines)
pts_file_path = osp.join(temp_dir, '000001', '000001_points.obj')
gt_file_path = osp.join(temp_dir, '000001', '000001_gt.obj')
pred_file_path = osp.join(temp_dir, '000001', '000001_pred.obj')
img_file_path = osp.join(temp_dir, '000001', '000001_img.png')
img_pred_path = osp.join(temp_dir, '000001', '000001_pred.png')
img_gt_file = osp.join(temp_dir, '000001', '000001_gt.png')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
mmcv.check_file_exist(img_file_path)
mmcv.check_file_exist(img_pred_path)
mmcv.check_file_exist(img_gt_file)
tmp_dir.cleanup()
# test multi-modality show with pipeline
eval_pipeline = [
dict(type='LoadImageFromFile'),
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='DefaultFormatBundle3D',
class_names=class_names,
with_label=False),
dict(type='Collect3D', keys=['points', 'img'])
]
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
sunrgbd_dataset.show(results, temp_dir, show=False, pipeline=eval_pipeline)
pts_file_path = osp.join(temp_dir, '000001', '000001_points.obj')
gt_file_path = osp.join(temp_dir, '000001', '000001_gt.obj')
pred_file_path = osp.join(temp_dir, '000001', '000001_pred.obj')
img_file_path = osp.join(temp_dir, '000001', '000001_img.png')
img_pred_path = osp.join(temp_dir, '000001', '000001_pred.png')
img_gt_file = osp.join(temp_dir, '000001', '000001_gt.png')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
mmcv.check_file_exist(img_file_path)
mmcv.check_file_exist(img_pred_path)
mmcv.check_file_exist(img_gt_file)
tmp_dir.cleanup()
# Copyright (c) OpenMMLab. All rights reserved.
import tempfile
import numpy as np
import pytest
import torch
from mmdet3d.datasets import WaymoDataset
def _generate_waymo_train_dataset_config():
data_root = 'tests/data/waymo/kitti_format/'
ann_file = 'tests/data/waymo/kitti_format/waymo_infos_train.pkl'
classes = ['Car', 'Pedestrian', 'Cyclist']
pts_prefix = 'velodyne'
point_cloud_range = [-74.88, -74.88, -2, 74.88, 74.88, 4]
file_client_args = dict(backend='disk')
db_sampler = dict(
data_root=data_root,
# in coordinate system refactor, this test file is modified
info_path=data_root + 'waymo_dbinfos_train.pkl',
rate=1.0,
prepare=dict(
filter_by_difficulty=[-1], filter_by_min_points=dict(Car=5)),
classes=classes,
sample_groups=dict(Car=15),
points_loader=dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=6,
use_dim=[0, 1, 2, 3, 4],
file_client_args=file_client_args))
pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=6,
use_dim=5,
file_client_args=file_client_args),
dict(
type='LoadAnnotations3D',
with_bbox_3d=True,
with_label_3d=True,
file_client_args=file_client_args),
dict(type='ObjectSample', db_sampler=db_sampler),
dict(
type='RandomFlip3D',
sync_2d=False,
flip_ratio_bev_horizontal=0.5,
flip_ratio_bev_vertical=0.5),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.78539816, 0.78539816],
scale_ratio_range=[0.95, 1.05]),
dict(type='PointsRangeFilter', point_cloud_range=point_cloud_range),
dict(type='ObjectRangeFilter', point_cloud_range=point_cloud_range),
dict(type='PointShuffle'),
dict(type='DefaultFormatBundle3D', class_names=classes),
dict(
type='Collect3D', keys=['points', 'gt_bboxes_3d', 'gt_labels_3d'])
]
modality = dict(use_lidar=True, use_camera=False)
split = 'training'
return data_root, ann_file, classes, pts_prefix, pipeline, modality, split
def _generate_waymo_val_dataset_config():
data_root = 'tests/data/waymo/kitti_format/'
ann_file = 'tests/data/waymo/kitti_format/waymo_infos_val.pkl'
classes = ['Car', 'Pedestrian', 'Cyclist']
pts_prefix = 'velodyne'
point_cloud_range = [-74.88, -74.88, -2, 74.88, 74.88, 4]
file_client_args = dict(backend='disk')
pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=6,
use_dim=5,
file_client_args=file_client_args),
dict(
type='MultiScaleFlipAug3D',
img_scale=(1333, 800),
pts_scale_ratio=1,
flip=False,
transforms=[
dict(
type='GlobalRotScaleTrans',
rot_range=[0, 0],
scale_ratio_range=[1., 1.],
translation_std=[0, 0, 0]),
dict(type='RandomFlip3D'),
dict(
type='PointsRangeFilter',
point_cloud_range=point_cloud_range),
dict(
type='DefaultFormatBundle3D',
class_names=classes,
with_label=False),
dict(type='Collect3D', keys=['points'])
])
]
modality = dict(use_lidar=True, use_camera=False)
split = 'training'
return data_root, ann_file, classes, pts_prefix, pipeline, modality, split
def test_getitem():
np.random.seed(0)
data_root, ann_file, classes, pts_prefix, pipeline, \
modality, split = _generate_waymo_train_dataset_config()
waymo_dataset = WaymoDataset(data_root, ann_file, split, pts_prefix,
pipeline, classes, modality)
data = waymo_dataset[0]
points = data['points']._data
gt_bboxes_3d = data['gt_bboxes_3d']._data
gt_labels_3d = data['gt_labels_3d']._data
expected_gt_bboxes_3d = torch.tensor(
[[31.8048, -0.1002, 2.1857, 6.0931, 2.3519, 3.1756, -0.1403]])
expected_gt_labels_3d = torch.tensor([0])
assert points.shape == (765, 5)
assert torch.allclose(
gt_bboxes_3d.tensor, expected_gt_bboxes_3d, atol=1e-4)
assert torch.all(gt_labels_3d == expected_gt_labels_3d)
def test_evaluate():
if not torch.cuda.is_available():
pytest.skip('test requires GPU and torch+cuda')
from mmdet3d.core.bbox import LiDARInstance3DBoxes
data_root, ann_file, classes, pts_prefix, pipeline, \
modality, split = _generate_waymo_val_dataset_config()
waymo_dataset = WaymoDataset(data_root, ann_file, split, pts_prefix,
pipeline, classes, modality)
boxes_3d = LiDARInstance3DBoxes(
torch.tensor([[
6.9684e+01, 3.3335e+01, 4.1465e-02, 4.3600e+00, 2.0100e+00,
1.4600e+00, 9.0000e-02 - np.pi / 2
]]))
labels_3d = torch.tensor([0])
scores_3d = torch.tensor([0.5])
result = dict(boxes_3d=boxes_3d, labels_3d=labels_3d, scores_3d=scores_3d)
# kitti protocol
metric = ['kitti']
ap_dict = waymo_dataset.evaluate([result], metric=metric)
assert np.isclose(ap_dict['KITTI/Overall_3D_AP11_easy'],
3.0303030303030307)
assert np.isclose(ap_dict['KITTI/Overall_3D_AP11_moderate'],
3.0303030303030307)
assert np.isclose(ap_dict['KITTI/Overall_3D_AP11_hard'],
3.0303030303030307)
# waymo protocol
metric = ['waymo']
boxes_3d = LiDARInstance3DBoxes(
torch.tensor([[
6.9684e+01, 3.3335e+01, 4.1465e-02, 4.3600e+00, 2.0100e+00,
1.4600e+00, 9.0000e-02 - np.pi / 2
]]))
labels_3d = torch.tensor([0])
scores_3d = torch.tensor([0.8])
result = dict(boxes_3d=boxes_3d, labels_3d=labels_3d, scores_3d=scores_3d)
ap_dict = waymo_dataset.evaluate([result], metric=metric)
assert np.isclose(ap_dict['Overall/L1 mAP'], 0.3333333333333333)
assert np.isclose(ap_dict['Overall/L2 mAP'], 0.3333333333333333)
assert np.isclose(ap_dict['Overall/L1 mAPH'], 0.3333333333333333)
assert np.isclose(ap_dict['Overall/L2 mAPH'], 0.3333333333333333)
def test_show():
from os import path as osp
import mmcv
from mmdet3d.core.bbox import LiDARInstance3DBoxes
# Waymo shares show function with KITTI so I just copy it here
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
data_root, ann_file, classes, pts_prefix, pipeline, \
modality, split = _generate_waymo_val_dataset_config()
waymo_dataset = WaymoDataset(
data_root, ann_file, split=split, modality=modality, pipeline=pipeline)
boxes_3d = LiDARInstance3DBoxes(
torch.tensor(
[[46.1218, -4.6496, -0.9275, 1.4442, 0.5316, 1.7450, 1.1749],
[33.3189, 0.1981, 0.3136, 1.2301, 0.5656, 1.7985, 1.5723],
[46.1366, -4.6404, -0.9510, 1.6501, 0.5162, 1.7540, 1.3778],
[33.2646, 0.2297, 0.3446, 1.3365, 0.5746, 1.7947, 1.5430],
[58.9079, 16.6272, -1.5829, 3.9313, 1.5656, 1.4899, 1.5505]]))
scores_3d = torch.tensor([0.1815, 0.1663, 0.5792, 0.2194, 0.2780])
labels_3d = torch.tensor([0, 0, 1, 1, 2])
result = dict(boxes_3d=boxes_3d, scores_3d=scores_3d, labels_3d=labels_3d)
results = [result]
waymo_dataset.show(results, temp_dir, show=False)
pts_file_path = osp.join(temp_dir, '1000000', '1000000_points.obj')
gt_file_path = osp.join(temp_dir, '1000000', '1000000_gt.obj')
pred_file_path = osp.join(temp_dir, '1000000', '1000000_pred.obj')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
tmp_dir.cleanup()
# test show with pipeline
tmp_dir = tempfile.TemporaryDirectory()
temp_dir = tmp_dir.name
eval_pipeline = [
dict(
type='LoadPointsFromFile',
coord_type='LIDAR',
load_dim=6,
use_dim=5),
dict(
type='DefaultFormatBundle3D',
class_names=classes,
with_label=False),
dict(type='Collect3D', keys=['points'])
]
waymo_dataset.show(results, temp_dir, show=False, pipeline=eval_pipeline)
pts_file_path = osp.join(temp_dir, '1000000', '1000000_points.obj')
gt_file_path = osp.join(temp_dir, '1000000', '1000000_gt.obj')
pred_file_path = osp.join(temp_dir, '1000000', '1000000_pred.obj')
mmcv.check_file_exist(pts_file_path)
mmcv.check_file_exist(gt_file_path)
mmcv.check_file_exist(pred_file_path)
tmp_dir.cleanup()
def test_format_results():
if not torch.cuda.is_available():
pytest.skip('test requires GPU and torch+cuda')
from mmdet3d.core.bbox import LiDARInstance3DBoxes
data_root, ann_file, classes, pts_prefix, pipeline, \
modality, split = _generate_waymo_val_dataset_config()
waymo_dataset = WaymoDataset(data_root, ann_file, split, pts_prefix,
pipeline, classes, modality)
boxes_3d = LiDARInstance3DBoxes(
torch.tensor([[
6.9684e+01, 3.3335e+01, 4.1465e-02, 4.3600e+00, 2.0100e+00,
1.4600e+00, 9.0000e-02 - np.pi / 2
]]))
labels_3d = torch.tensor([0])
scores_3d = torch.tensor([0.5])
result = dict(boxes_3d=boxes_3d, labels_3d=labels_3d, scores_3d=scores_3d)
result_files, tmp_dir = waymo_dataset.format_results([result],
data_format='waymo')
expected_name = np.array(['Car'])
expected_truncated = np.array([0.])
expected_occluded = np.array([0])
expected_alpha = np.array([0.35619745])
expected_bbox = np.array([[0., 673.59814, 37.07779, 719.7537]])
expected_dimensions = np.array([[4.36, 1.46, 2.01]])
expected_location = np.array([[-33.000042, 2.4999967, 68.29972]])
expected_rotation_y = np.array([-0.09])
expected_score = np.array([0.5])
expected_sample_idx = np.array([1000000])
assert np.all(result_files[0]['name'] == expected_name)
assert np.allclose(result_files[0]['truncated'], expected_truncated)
assert np.all(result_files[0]['occluded'] == expected_occluded)
assert np.allclose(result_files[0]['bbox'], expected_bbox, 1e-3)
assert np.allclose(result_files[0]['dimensions'], expected_dimensions)
assert np.allclose(result_files[0]['location'], expected_location)
assert np.allclose(result_files[0]['rotation_y'], expected_rotation_y)
assert np.allclose(result_files[0]['score'], expected_score)
assert np.allclose(result_files[0]['sample_idx'], expected_sample_idx)
assert np.allclose(result_files[0]['alpha'], expected_alpha)
tmp_dir.cleanup()
# Copyright (c) OpenMMLab. All rights reserved.
import mmcv
import numpy as np
from mmdet3d.datasets.pipelines.data_augment_utils import (
noise_per_object_v3_, points_transform_)
def test_noise_per_object_v3_():
np.random.seed(0)
points = np.fromfile(
'./tests/data/kitti/training/velodyne_reduced/000000.bin',
np.float32).reshape(-1, 4)
annos = mmcv.load('./tests/data/kitti/kitti_infos_train.pkl')
info = annos[0]
annos = info['annos']
loc = annos['location']
dims = annos['dimensions']
rots = annos['rotation_y']
gt_bboxes_3d = np.concatenate([loc, dims, rots[..., np.newaxis]],
axis=1).astype(np.float32)
noise_per_object_v3_(gt_boxes=gt_bboxes_3d, points=points)
expected_gt_bboxes_3d = np.array(
[[3.3430212, 2.1475432, 9.388738, 1.2, 1.89, 0.48, 0.05056486]])
assert points.shape == (800, 4)
assert np.allclose(gt_bboxes_3d, expected_gt_bboxes_3d)
def test_points_transform():
points = np.array([[46.5090, 6.1140, -0.7790, 0.0000],
[42.9490, 6.4050, -0.7050, 0.0000],
[42.9010, 6.5360, -0.7050, 0.0000],
[46.1960, 6.0960, -1.0100, 0.0000],
[43.3080, 6.2680, -0.9360, 0.0000]])
gt_boxes = np.array([[
1.5340e+01, 8.4691e+00, -1.6855e+00, 1.6400e+00, 3.7000e+00,
1.4900e+00, 3.1300e+00
],
[
1.7999e+01, 8.2386e+00, -1.5802e+00, 1.5500e+00,
4.0200e+00, 1.5200e+00, 3.1300e+00
],
[
2.9620e+01, 8.2617e+00, -1.6185e+00, 1.7800e+00,
4.2500e+00, 1.9000e+00, -3.1200e+00
],
[
4.8218e+01, 7.8035e+00, -1.3790e+00, 1.6400e+00,
3.7000e+00, 1.5200e+00, -1.0000e-02
],
[
3.3079e+01, -8.4817e+00, -1.3092e+00, 4.3000e-01,
1.7000e+00, 1.6200e+00, -1.5700e+00
]])
point_masks = np.array([[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, False, False]])
loc_transforms = np.array([[-1.8635, -0.2774, -0.1774],
[-1.0297, -1.0302, -0.3062],
[1.6680, 0.2597, 0.0551],
[0.2230, 0.7257, -0.0097],
[-0.1403, 0.8300, 0.3431]])
rot_transforms = np.array([0.6888, -0.3858, 0.1910, -0.0044, -0.0036])
valid_mask = np.array([True, True, True, True, True])
points_transform_(points, gt_boxes[:, :3], point_masks, loc_transforms,
rot_transforms, valid_mask)
assert points.shape == (5, 4)
assert gt_boxes.shape == (5, 7)
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
import torch
from mmdet3d.core.points import DepthPoints
from mmdet3d.datasets.pipelines import MultiScaleFlipAug3D
def test_multi_scale_flip_aug_3D():
np.random.seed(0)
transforms = [{
'type': 'GlobalRotScaleTrans',
'rot_range': [-0.1, 0.1],
'scale_ratio_range': [0.9, 1.1],
'translation_std': [0, 0, 0]
}, {
'type': 'RandomFlip3D',
'sync_2d': False,
'flip_ratio_bev_horizontal': 0.5
}, {
'type': 'PointSample',
'num_points': 5
}, {
'type':
'DefaultFormatBundle3D',
'class_names': ('bed', 'table', 'sofa', 'chair', 'toilet', 'desk',
'dresser', 'night_stand', 'bookshelf', 'bathtub'),
'with_label':
False
}, {
'type': 'Collect3D',
'keys': ['points']
}]
img_scale = (1333, 800)
pts_scale_ratio = 1
multi_scale_flip_aug_3D = MultiScaleFlipAug3D(transforms, img_scale,
pts_scale_ratio)
pts_file_name = 'tests/data/sunrgbd/points/000001.bin'
sample_idx = 4
file_name = 'tests/data/sunrgbd/points/000001.bin'
bbox3d_fields = []
points = np.array([[0.20397437, 1.4267826, -1.0503972, 0.16195858],
[-2.2095256, 3.3159535, -0.7706928, 0.4416629],
[1.5090443, 3.2764456, -1.1913797, 0.02097607],
[-1.373904, 3.8711405, 0.8524302, 2.064786],
[-1.8139812, 3.538856, -1.0056694, 0.20668638]])
points = DepthPoints(points, points_dim=4, attribute_dims=dict(height=3))
results = dict(
points=points,
pts_file_name=pts_file_name,
sample_idx=sample_idx,
file_name=file_name,
bbox3d_fields=bbox3d_fields)
results = multi_scale_flip_aug_3D(results)
expected_points = torch.tensor(
[[-2.2418, 3.2942, -0.7707, 0.4417], [-1.4116, 3.8575, 0.8524, 2.0648],
[-1.8484, 3.5210, -1.0057, 0.2067], [0.1900, 1.4287, -1.0504, 0.1620],
[1.4770, 3.2910, -1.1914, 0.0210]],
dtype=torch.float32)
assert torch.allclose(
results['points'][0]._data, expected_points, atol=1e-4)
# Copyright (c) OpenMMLab. All rights reserved.
from os import path as osp
import mmcv
import numpy as np
import torch
from mmdet3d.core.bbox import DepthInstance3DBoxes
from mmdet3d.datasets.pipelines import Compose
def test_scannet_pipeline():
class_names = ('cabinet', 'bed', 'chair', 'sofa', 'table', 'door',
'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'garbagebin')
np.random.seed(0)
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=True,
with_label_3d=True,
with_mask_3d=True,
with_seg_3d=True),
dict(type='GlobalAlignment', rotation_axis=2),
dict(
type='PointSegClassMapping',
valid_cat_ids=(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24, 28, 33,
34, 36, 39)),
dict(type='PointSample', num_points=5),
dict(
type='RandomFlip3D',
sync_2d=False,
flip_ratio_bev_horizontal=1.0,
flip_ratio_bev_vertical=1.0),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.087266, 0.087266],
scale_ratio_range=[1.0, 1.0],
shift_height=True),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D',
keys=[
'points', 'gt_bboxes_3d', 'gt_labels_3d', 'pts_semantic_mask',
'pts_instance_mask'
]),
]
pipeline = Compose(pipelines)
info = mmcv.load('./tests/data/scannet/scannet_infos.pkl')[0]
results = dict()
data_path = './tests/data/scannet'
results['pts_filename'] = osp.join(data_path, info['pts_path'])
if info['annos']['gt_num'] != 0:
scannet_gt_bboxes_3d = info['annos']['gt_boxes_upright_depth'].astype(
np.float32)
scannet_gt_labels_3d = info['annos']['class'].astype(np.int64)
else:
scannet_gt_bboxes_3d = np.zeros((1, 6), dtype=np.float32)
scannet_gt_labels_3d = np.zeros((1, ), dtype=np.int64)
results['ann_info'] = dict()
results['ann_info']['pts_instance_mask_path'] = osp.join(
data_path, info['pts_instance_mask_path'])
results['ann_info']['pts_semantic_mask_path'] = osp.join(
data_path, info['pts_semantic_mask_path'])
results['ann_info']['gt_bboxes_3d'] = DepthInstance3DBoxes(
scannet_gt_bboxes_3d, box_dim=6, with_yaw=False)
results['ann_info']['gt_labels_3d'] = scannet_gt_labels_3d
results['ann_info']['axis_align_matrix'] = \
info['annos']['axis_align_matrix']
results['img_fields'] = []
results['bbox3d_fields'] = []
results['pts_mask_fields'] = []
results['pts_seg_fields'] = []
results = pipeline(results)
points = results['points']._data
gt_bboxes_3d = results['gt_bboxes_3d']._data
gt_labels_3d = results['gt_labels_3d']._data
pts_semantic_mask = results['pts_semantic_mask']._data
pts_instance_mask = results['pts_instance_mask']._data
expected_points = torch.tensor(
[[1.8339e+00, 2.1093e+00, 2.2900e+00, 2.3895e+00],
[3.6079e+00, 1.4592e-01, 2.0687e+00, 2.1682e+00],
[4.1886e+00, 5.0614e+00, -1.0841e-01, -8.8736e-03],
[6.8790e+00, 1.5086e+00, -9.3154e-02, 6.3816e-03],
[4.8253e+00, 2.6668e-01, 1.4917e+00, 1.5912e+00]])
expected_gt_bboxes_3d = torch.tensor(
[[-1.1835, -3.6317, 1.8565, 1.7577, 0.3761, 0.5724, 0.0000],
[-3.1832, 3.2269, 1.5268, 0.6727, 0.2251, 0.6715, 0.0000],
[-0.9598, -2.2864, 0.6165, 0.7506, 2.5709, 1.2145, 0.0000],
[-2.6988, -2.7354, 0.9722, 0.7680, 1.8877, 0.2870, 0.0000],
[3.2989, 0.2885, 1.0712, 0.7600, 3.8814, 2.1603, 0.0000]])
expected_gt_labels_3d = np.array([
6, 6, 4, 9, 11, 11, 10, 0, 15, 17, 17, 17, 3, 12, 4, 4, 14, 1, 0, 0, 0,
0, 0, 0, 5, 5, 5
])
expected_pts_semantic_mask = np.array([0, 18, 18, 18, 18])
expected_pts_instance_mask = np.array([44, 22, 10, 10, 57])
assert torch.allclose(points, expected_points, 1e-2)
assert torch.allclose(gt_bboxes_3d.tensor[:5, :], expected_gt_bboxes_3d,
1e-2)
assert np.all(gt_labels_3d.numpy() == expected_gt_labels_3d)
assert np.all(pts_semantic_mask.numpy() == expected_pts_semantic_mask)
assert np.all(pts_instance_mask.numpy() == expected_pts_instance_mask)
def test_scannet_seg_pipeline():
class_names = ('wall', 'floor', 'cabinet', 'bed', 'chair', 'sofa', 'table',
'door', 'window', 'bookshelf', 'picture', 'counter', 'desk',
'curtain', 'refrigerator', 'showercurtrain', 'toilet',
'sink', 'bathtub', 'otherfurniture')
np.random.seed(0)
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=False,
with_label_3d=False,
with_mask_3d=False,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 24,
28, 33, 34, 36, 39),
max_cat_id=40),
dict(
type='IndoorPatchPointSample',
num_points=5,
block_size=1.5,
ignore_index=len(class_names),
use_normalized_coord=True,
enlarge_size=0.2,
min_unique_num=None),
dict(type='NormalizePointsColor', color_mean=None),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(type='Collect3D', keys=['points', 'pts_semantic_mask'])
]
pipeline = Compose(pipelines)
info = mmcv.load('./tests/data/scannet/scannet_infos.pkl')[0]
results = dict()
data_path = './tests/data/scannet'
results['pts_filename'] = osp.join(data_path, info['pts_path'])
results['ann_info'] = dict()
results['ann_info']['pts_semantic_mask_path'] = osp.join(
data_path, info['pts_semantic_mask_path'])
results['pts_seg_fields'] = []
results = pipeline(results)
points = results['points']._data
pts_semantic_mask = results['pts_semantic_mask']._data
# build sampled points
scannet_points = np.fromfile(
osp.join(data_path, info['pts_path']), dtype=np.float32).reshape(
(-1, 6))
scannet_choices = np.array([87, 34, 58, 9, 18])
scannet_center = np.array([-2.1772466, -3.4789145, 1.242711])
scannet_center[2] = 0.0
scannet_coord_max = np.amax(scannet_points[:, :3], axis=0)
expected_points = np.concatenate([
scannet_points[scannet_choices, :3] - scannet_center,
scannet_points[scannet_choices, 3:] / 255.,
scannet_points[scannet_choices, :3] / scannet_coord_max
],
axis=1)
expected_pts_semantic_mask = np.array([13, 13, 12, 2, 0])
assert np.allclose(points.numpy(), expected_points, atol=1e-6)
assert np.all(pts_semantic_mask.numpy() == expected_pts_semantic_mask)
def test_s3dis_seg_pipeline():
class_names = ('ceiling', 'floor', 'wall', 'beam', 'column', 'window',
'door', 'table', 'chair', 'sofa', 'bookcase', 'board',
'clutter')
np.random.seed(0)
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=False,
use_color=True,
load_dim=6,
use_dim=[0, 1, 2, 3, 4, 5]),
dict(
type='LoadAnnotations3D',
with_bbox_3d=False,
with_label_3d=False,
with_mask_3d=False,
with_seg_3d=True),
dict(
type='PointSegClassMapping',
valid_cat_ids=tuple(range(len(class_names))),
max_cat_id=13),
dict(
type='IndoorPatchPointSample',
num_points=5,
block_size=1.0,
ignore_index=len(class_names),
use_normalized_coord=True,
enlarge_size=0.2,
min_unique_num=None),
dict(type='NormalizePointsColor', color_mean=None),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(type='Collect3D', keys=['points', 'pts_semantic_mask'])
]
pipeline = Compose(pipelines)
info = mmcv.load('./tests/data/s3dis/s3dis_infos.pkl')[0]
results = dict()
data_path = './tests/data/s3dis'
results['pts_filename'] = osp.join(data_path, info['pts_path'])
results['ann_info'] = dict()
results['ann_info']['pts_semantic_mask_path'] = osp.join(
data_path, info['pts_semantic_mask_path'])
results['pts_seg_fields'] = []
results = pipeline(results)
points = results['points']._data
pts_semantic_mask = results['pts_semantic_mask']._data
# build sampled points
s3dis_points = np.fromfile(
osp.join(data_path, info['pts_path']), dtype=np.float32).reshape(
(-1, 6))
s3dis_choices = np.array([87, 37, 60, 18, 31])
s3dis_center = np.array([2.691, 2.231, 3.172])
s3dis_center[2] = 0.0
s3dis_coord_max = np.amax(s3dis_points[:, :3], axis=0)
expected_points = np.concatenate([
s3dis_points[s3dis_choices, :3] - s3dis_center,
s3dis_points[s3dis_choices, 3:] / 255.,
s3dis_points[s3dis_choices, :3] / s3dis_coord_max
],
axis=1)
expected_pts_semantic_mask = np.array([0, 1, 0, 8, 0])
assert np.allclose(points.numpy(), expected_points, atol=1e-6)
assert np.all(pts_semantic_mask.numpy() == expected_pts_semantic_mask)
def test_sunrgbd_pipeline():
class_names = ('bed', 'table', 'sofa', 'chair', 'toilet', 'desk',
'dresser', 'night_stand', 'bookshelf', 'bathtub')
np.random.seed(0)
pipelines = [
dict(
type='LoadPointsFromFile',
coord_type='DEPTH',
shift_height=True,
load_dim=6,
use_dim=[0, 1, 2]),
dict(type='LoadAnnotations3D'),
dict(
type='RandomFlip3D',
sync_2d=False,
flip_ratio_bev_horizontal=1.0,
),
dict(
type='GlobalRotScaleTrans',
rot_range=[-0.523599, 0.523599],
scale_ratio_range=[0.85, 1.15],
shift_height=True),
dict(type='PointSample', num_points=5),
dict(type='DefaultFormatBundle3D', class_names=class_names),
dict(
type='Collect3D', keys=['points', 'gt_bboxes_3d', 'gt_labels_3d']),
]
pipeline = Compose(pipelines)
results = dict()
info = mmcv.load('./tests/data/sunrgbd/sunrgbd_infos.pkl')[0]
data_path = './tests/data/sunrgbd'
results['pts_filename'] = osp.join(data_path, info['pts_path'])
if info['annos']['gt_num'] != 0:
gt_bboxes_3d = info['annos']['gt_boxes_upright_depth'].astype(
np.float32)
gt_labels_3d = info['annos']['class'].astype(np.int64)
else:
gt_bboxes_3d = np.zeros((1, 7), dtype=np.float32)
gt_labels_3d = np.zeros((1, ), dtype=np.int64)
# prepare input of pipeline
results['ann_info'] = dict()
results['ann_info']['gt_bboxes_3d'] = DepthInstance3DBoxes(gt_bboxes_3d)
results['ann_info']['gt_labels_3d'] = gt_labels_3d
results['img_fields'] = []
results['bbox3d_fields'] = []
results['pts_mask_fields'] = []
results['pts_seg_fields'] = []
results = pipeline(results)
points = results['points']._data
gt_bboxes_3d = results['gt_bboxes_3d']._data
gt_labels_3d = results['gt_labels_3d']._data
expected_points = torch.tensor([[0.8678, 1.3470, 0.1105, 0.0905],
[0.8707, 1.3635, 0.0437, 0.0238],
[0.8636, 1.3511, 0.0504, 0.0304],
[0.8690, 1.3461, 0.1265, 0.1065],
[0.8668, 1.3434, 0.1216, 0.1017]])
# Depth coordinate system update: only yaw changes since rotation in depth
# is counter-clockwise and yaw angle is clockwise originally
# But heading angles in sunrgbd data also reverses the sign
# and after horizontal flip the sign reverse again
rotation_angle = info['annos']['rotation_y']
expected_gt_bboxes_3d = torch.tensor(
[[
-1.2136, 4.0206, -0.2412, 2.2493, 1.8444, 1.9245,
1.3989 + 0.047001579467984445 * 2 - 2 * rotation_angle[0]
],
[
-2.7420, 4.5777, -0.7686, 0.5718, 0.8629, 0.9510,
1.4446 + 0.047001579467984445 * 2 - 2 * rotation_angle[1]
],
[
0.9729, 1.9087, -0.1443, 0.6965, 1.5273, 2.0563,
2.9924 + 0.047001579467984445 * 2 - 2 * rotation_angle[2]
]]).float()
expected_gt_labels_3d = np.array([0, 7, 6])
assert torch.allclose(gt_bboxes_3d.tensor, expected_gt_bboxes_3d, 1e-3)
assert np.allclose(gt_labels_3d.flatten(), expected_gt_labels_3d)
assert torch.allclose(points, expected_points, 1e-2)
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmdet3d.core.points import DepthPoints
from mmdet3d.datasets.pipelines import (IndoorPatchPointSample, PointSample,
PointSegClassMapping)
def test_indoor_sample():
np.random.seed(0)
scannet_sample_points = PointSample(5)
scannet_results = dict()
scannet_points = np.array([[1.0719866, -0.7870435, 0.8408122, 0.9196809],
[1.103661, 0.81065744, 2.6616862, 2.7405548],
[1.0276475, 1.5061463, 2.6174362, 2.6963048],
[-0.9709588, 0.6750515, 0.93901765, 1.0178864],
[1.0578915, 1.1693821, 0.87503505, 0.95390373],
[0.05560996, -1.5688863, 1.2440368, 1.3229055],
[-0.15731563, -1.7735453, 2.7535574, 2.832426],
[1.1188195, -0.99211365, 2.5551798, 2.6340485],
[-0.9186557, -1.7041215, 2.0562649, 2.1351335],
[-1.0128691, -1.3394243, 0.040936, 0.1198047]])
scannet_results['points'] = DepthPoints(
scannet_points, points_dim=4, attribute_dims=dict(height=3))
scannet_pts_instance_mask = np.array(
[15, 12, 11, 38, 0, 18, 17, 12, 17, 0])
scannet_results['pts_instance_mask'] = scannet_pts_instance_mask
scannet_pts_semantic_mask = np.array([38, 1, 1, 40, 0, 40, 1, 1, 1, 0])
scannet_results['pts_semantic_mask'] = scannet_pts_semantic_mask
scannet_results = scannet_sample_points(scannet_results)
scannet_points_result = scannet_results['points'].tensor.numpy()
scannet_instance_labels_result = scannet_results['pts_instance_mask']
scannet_semantic_labels_result = scannet_results['pts_semantic_mask']
scannet_choices = np.array([2, 8, 4, 9, 1])
assert np.allclose(scannet_points[scannet_choices], scannet_points_result)
assert np.all(scannet_pts_instance_mask[scannet_choices] ==
scannet_instance_labels_result)
assert np.all(scannet_pts_semantic_mask[scannet_choices] ==
scannet_semantic_labels_result)
np.random.seed(0)
sunrgbd_sample_points = PointSample(5)
sunrgbd_results = dict()
sunrgbd_point_cloud = np.array(
[[-1.8135729e-01, 1.4695230e+00, -1.2780589e+00, 7.8938007e-03],
[1.2581362e-03, 2.0561588e+00, -1.0341064e+00, 2.5184631e-01],
[6.8236995e-01, 3.3611867e+00, -9.2599887e-01, 3.5995382e-01],
[-2.9432583e-01, 1.8714852e+00, -9.0929651e-01, 3.7665617e-01],
[-0.5024875, 1.8032674, -1.1403012, 0.14565146],
[-0.520559, 1.6324949, -0.9896099, 0.2963428],
[0.95929825, 2.9402404, -0.8746674, 0.41128528],
[-0.74624217, 1.5244724, -0.8678476, 0.41810507],
[0.56485355, 1.5747732, -0.804522, 0.4814307],
[-0.0913099, 1.3673826, -1.2800645, 0.00588822]])
sunrgbd_results['points'] = DepthPoints(
sunrgbd_point_cloud, points_dim=4, attribute_dims=dict(height=3))
sunrgbd_results = sunrgbd_sample_points(sunrgbd_results)
sunrgbd_choices = np.array([2, 8, 4, 9, 1])
sunrgbd_points_result = sunrgbd_results['points'].tensor.numpy()
repr_str = repr(sunrgbd_sample_points)
expected_repr_str = 'PointSample(num_points=5, ' \
'sample_range=None, ' \
'replace=False)'
assert repr_str == expected_repr_str
assert np.allclose(sunrgbd_point_cloud[sunrgbd_choices],
sunrgbd_points_result)
def test_indoor_seg_sample():
# test the train time behavior of IndoorPatchPointSample
np.random.seed(0)
scannet_patch_sample_points = IndoorPatchPointSample(
5, 1.5, ignore_index=20, use_normalized_coord=True)
scannet_seg_class_mapping = \
PointSegClassMapping((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16,
24, 28, 33, 34, 36, 39), 40)
scannet_results = dict()
scannet_points = np.fromfile(
'./tests/data/scannet/points/scene0000_00.bin',
dtype=np.float32).reshape((-1, 6))
scannet_results['points'] = DepthPoints(
scannet_points, points_dim=6, attribute_dims=dict(color=[3, 4, 5]))
scannet_pts_semantic_mask = np.fromfile(
'./tests/data/scannet/semantic_mask/scene0000_00.bin', dtype=np.int64)
scannet_results['pts_semantic_mask'] = scannet_pts_semantic_mask
scannet_results = scannet_seg_class_mapping(scannet_results)
scannet_results = scannet_patch_sample_points(scannet_results)
scannet_points_result = scannet_results['points']
scannet_semantic_labels_result = scannet_results['pts_semantic_mask']
# manually constructed sampled points
scannet_choices = np.array([87, 34, 58, 9, 18])
scannet_center = np.array([-2.1772466, -3.4789145, 1.242711])
scannet_center[2] = 0.0
scannet_coord_max = np.amax(scannet_points[:, :3], axis=0)
scannet_input_points = np.concatenate([
scannet_points[scannet_choices, :3] - scannet_center,
scannet_points[scannet_choices, 3:],
scannet_points[scannet_choices, :3] / scannet_coord_max
], 1)
assert scannet_points_result.points_dim == 9
assert scannet_points_result.attribute_dims == dict(
color=[3, 4, 5], normalized_coord=[6, 7, 8])
scannet_points_result = scannet_points_result.tensor.numpy()
assert np.allclose(scannet_input_points, scannet_points_result, atol=1e-6)
assert np.all(
np.array([13, 13, 12, 2, 0]) == scannet_semantic_labels_result)
repr_str = repr(scannet_patch_sample_points)
expected_repr_str = 'IndoorPatchPointSample(num_points=5, ' \
'block_size=1.5, ' \
'ignore_index=20, ' \
'use_normalized_coord=True, ' \
'num_try=10, ' \
'enlarge_size=0.2, ' \
'min_unique_num=None, ' \
'eps=0.01)'
assert repr_str == expected_repr_str
# when enlarge_size and min_unique_num are set
np.random.seed(0)
scannet_patch_sample_points = IndoorPatchPointSample(
5,
1.0,
ignore_index=20,
use_normalized_coord=False,
num_try=1000,
enlarge_size=None,
min_unique_num=5)
# this patch is within [0, 1] and has 5 unique points
# it should be selected
scannet_points = np.random.rand(5, 6)
scannet_points[0, :3] = np.array([0.5, 0.5, 0.5])
# generate points smaller than `min_unique_num` in local patches
# they won't be sampled
for i in range(2, 11, 2):
scannet_points = np.concatenate(
[scannet_points, np.random.rand(4, 6) + i], axis=0)
scannet_results = dict(
points=DepthPoints(
scannet_points, points_dim=6,
attribute_dims=dict(color=[3, 4, 5])),
pts_semantic_mask=np.random.randint(0, 20,
(scannet_points.shape[0], )))
scannet_results = scannet_patch_sample_points(scannet_results)
scannet_points_result = scannet_results['points']
# manually constructed sampled points
scannet_choices = np.array([2, 4, 3, 1, 0])
scannet_center = np.array([0.56804454, 0.92559665, 0.07103606])
scannet_center[2] = 0.0
scannet_input_points = np.concatenate([
scannet_points[scannet_choices, :3] - scannet_center,
scannet_points[scannet_choices, 3:],
], 1)
assert scannet_points_result.points_dim == 6
assert scannet_points_result.attribute_dims == dict(color=[3, 4, 5])
scannet_points_result = scannet_points_result.tensor.numpy()
assert np.allclose(scannet_input_points, scannet_points_result, atol=1e-6)
# test on S3DIS dataset
np.random.seed(0)
s3dis_patch_sample_points = IndoorPatchPointSample(
5, 1.0, ignore_index=None, use_normalized_coord=True)
s3dis_results = dict()
s3dis_points = np.fromfile(
'./tests/data/s3dis/points/Area_1_office_2.bin',
dtype=np.float32).reshape((-1, 6))
s3dis_results['points'] = DepthPoints(
s3dis_points, points_dim=6, attribute_dims=dict(color=[3, 4, 5]))
s3dis_pts_semantic_mask = np.fromfile(
'./tests/data/s3dis/semantic_mask/Area_1_office_2.bin', dtype=np.int64)
s3dis_results['pts_semantic_mask'] = s3dis_pts_semantic_mask
s3dis_results = s3dis_patch_sample_points(s3dis_results)
s3dis_points_result = s3dis_results['points']
s3dis_semantic_labels_result = s3dis_results['pts_semantic_mask']
# manually constructed sampled points
s3dis_choices = np.array([87, 37, 60, 18, 31])
s3dis_center = np.array([2.691, 2.231, 3.172])
s3dis_center[2] = 0.0
s3dis_coord_max = np.amax(s3dis_points[:, :3], axis=0)
s3dis_input_points = np.concatenate([
s3dis_points[s3dis_choices, :3] - s3dis_center,
s3dis_points[s3dis_choices,
3:], s3dis_points[s3dis_choices, :3] / s3dis_coord_max
], 1)
assert s3dis_points_result.points_dim == 9
assert s3dis_points_result.attribute_dims == dict(
color=[3, 4, 5], normalized_coord=[6, 7, 8])
s3dis_points_result = s3dis_points_result.tensor.numpy()
assert np.allclose(s3dis_input_points, s3dis_points_result, atol=1e-6)
assert np.all(np.array([0, 1, 0, 8, 0]) == s3dis_semantic_labels_result)
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
import torch
from mmcv.parallel import DataContainer
from mmdet3d.datasets.pipelines import (DefaultFormatBundle,
LoadMultiViewImageFromFiles)
def test_load_multi_view_image_from_files():
multi_view_img_loader = LoadMultiViewImageFromFiles(to_float32=True)
num_views = 6
filename = 'tests/data/waymo/kitti_format/training/image_0/0000000.png'
filenames = [filename for _ in range(num_views)]
input_dict = dict(img_filename=filenames)
results = multi_view_img_loader(input_dict)
img = results['img']
img0 = img[0]
img_norm_cfg = results['img_norm_cfg']
assert isinstance(img, list)
assert len(img) == num_views
assert img0.dtype == np.float32
assert results['filename'] == filenames
assert results['img_shape'] == results['ori_shape'] == \
results['pad_shape'] == (1280, 1920, 3, num_views)
assert results['scale_factor'] == 1.0
assert np.all(img_norm_cfg['mean'] == np.zeros(3, dtype=np.float32))
assert np.all(img_norm_cfg['std'] == np.ones(3, dtype=np.float32))
assert not img_norm_cfg['to_rgb']
repr_str = repr(multi_view_img_loader)
expected_str = 'LoadMultiViewImageFromFiles(to_float32=True, ' \
"color_type='unchanged')"
assert repr_str == expected_str
# test LoadMultiViewImageFromFiles's compatibility with DefaultFormatBundle
# refer to https://github.com/open-mmlab/mmdetection3d/issues/227
default_format_bundle = DefaultFormatBundle()
results = default_format_bundle(results)
img = results['img']
assert isinstance(img, DataContainer)
assert img._data.shape == torch.Size((num_views, 3, 1280, 1920))
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmdet3d.core.points import LiDARPoints
from mmdet3d.datasets.pipelines.loading import LoadPointsFromMultiSweeps
def test_load_points_from_multi_sweeps():
np.random.seed(0)
file_client_args = dict(backend='disk')
load_points_from_multi_sweeps_1 = LoadPointsFromMultiSweeps(
sweeps_num=9,
use_dim=[0, 1, 2, 3, 4],
file_client_args=file_client_args)
load_points_from_multi_sweeps_2 = LoadPointsFromMultiSweeps(
sweeps_num=9,
use_dim=[0, 1, 2, 3, 4],
file_client_args=file_client_args,
pad_empty_sweeps=True,
remove_close=True)
load_points_from_multi_sweeps_3 = LoadPointsFromMultiSweeps(
sweeps_num=9,
use_dim=[0, 1, 2, 3, 4],
file_client_args=file_client_args,
pad_empty_sweeps=True,
remove_close=True,
test_mode=True)
points = np.random.random([100, 5]) * 2
points = LiDARPoints(points, points_dim=5)
input_results = dict(points=points, sweeps=[], timestamp=None)
results = load_points_from_multi_sweeps_1(input_results)
assert results['points'].tensor.numpy().shape == (100, 5)
input_results = dict(points=points, sweeps=[], timestamp=None)
results = load_points_from_multi_sweeps_2(input_results)
assert results['points'].tensor.numpy().shape == (775, 5)
sensor2lidar_rotation = np.array(
[[9.99999967e-01, 1.13183067e-05, 2.56845368e-04],
[-1.12839618e-05, 9.99999991e-01, -1.33719456e-04],
[-2.56846879e-04, 1.33716553e-04, 9.99999958e-01]])
sensor2lidar_translation = np.array([-0.0009198, -0.03964854, -0.00190136])
sweep = dict(
data_path='tests/data/nuscenes/sweeps/LIDAR_TOP/'
'n008-2018-09-18-12-07-26-0400__LIDAR_TOP__'
'1537287083900561.pcd.bin',
sensor2lidar_rotation=sensor2lidar_rotation,
sensor2lidar_translation=sensor2lidar_translation,
timestamp=0)
input_results = dict(points=points, sweeps=[sweep], timestamp=1.0)
results = load_points_from_multi_sweeps_1(input_results)
assert results['points'].tensor.numpy().shape == (500, 5)
input_results = dict(points=points, sweeps=[sweep], timestamp=1.0)
results = load_points_from_multi_sweeps_2(input_results)
assert results['points'].tensor.numpy().shape == (451, 5)
input_results = dict(points=points, sweeps=[sweep] * 10, timestamp=1.0)
results = load_points_from_multi_sweeps_2(input_results)
assert results['points'].tensor.numpy().shape == (3259, 5)
input_results = dict(points=points, sweeps=[sweep] * 10, timestamp=1.0)
results = load_points_from_multi_sweeps_3(input_results)
assert results['points'].tensor.numpy().shape == (3259, 5)
This diff is collapsed.
# Copyright (c) OpenMMLab. All rights reserved.
"""Test model forward process.
CommandLine:
pytest tests/test_models/test_forward.py
xdoctest tests/test_models/test_forward.py zero
"""
import copy
from os.path import dirname, exists, join
import numpy as np
import torch
def _get_config_directory():
"""Find the predefined detector config directory."""
try:
# Assume we are running in the source mmdetection3d repo
repo_dpath = dirname(dirname(dirname(__file__)))
except NameError:
# For IPython development when this __file__ is not defined
import mmdet3d
repo_dpath = dirname(dirname(mmdet3d.__file__))
config_dpath = join(repo_dpath, 'configs')
if not exists(config_dpath):
raise Exception('Cannot find config path')
return config_dpath
def _get_config_module(fname):
"""Load a configuration as a python module."""
from mmcv import Config
config_dpath = _get_config_directory()
config_fpath = join(config_dpath, fname)
config_mod = Config.fromfile(config_fpath)
return config_mod
def _get_detector_cfg(fname):
"""Grab configs necessary to create a detector.
These are deep copied to allow for safe modification of parameters without
influencing other tests.
"""
config = _get_config_module(fname)
model = copy.deepcopy(config.model)
return model
def _test_two_stage_forward(cfg_file):
model = _get_detector_cfg(cfg_file)
model['pretrained'] = None
from mmdet.models import build_detector
detector = build_detector(model)
input_shape = (1, 3, 256, 256)
# Test forward train with a non-empty truth batch
mm_inputs = _demo_mm_inputs(input_shape, num_items=[10])
imgs = mm_inputs.pop('imgs')
img_metas = mm_inputs.pop('img_metas')
gt_bboxes = mm_inputs['gt_bboxes']
gt_labels = mm_inputs['gt_labels']
gt_masks = mm_inputs['gt_masks']
losses = detector.forward(
imgs,
img_metas,
gt_bboxes=gt_bboxes,
gt_labels=gt_labels,
gt_masks=gt_masks,
return_loss=True)
assert isinstance(losses, dict)
loss, _ = detector._parse_losses(losses)
loss.requires_grad_(True)
assert float(loss.item()) > 0
loss.backward()
# Test forward train with an empty truth batch
mm_inputs = _demo_mm_inputs(input_shape, num_items=[0])
imgs = mm_inputs.pop('imgs')
img_metas = mm_inputs.pop('img_metas')
gt_bboxes = mm_inputs['gt_bboxes']
gt_labels = mm_inputs['gt_labels']
gt_masks = mm_inputs['gt_masks']
losses = detector.forward(
imgs,
img_metas,
gt_bboxes=gt_bboxes,
gt_labels=gt_labels,
gt_masks=gt_masks,
return_loss=True)
assert isinstance(losses, dict)
loss, _ = detector._parse_losses(losses)
assert float(loss.item()) > 0
loss.backward()
# Test forward test
with torch.no_grad():
img_list = [g[None, :] for g in imgs]
batch_results = []
for one_img, one_meta in zip(img_list, img_metas):
result = detector.forward([one_img], [[one_meta]],
return_loss=False)
batch_results.append(result)
def _test_single_stage_forward(cfg_file):
model = _get_detector_cfg(cfg_file)
model['pretrained'] = None
from mmdet.models import build_detector
detector = build_detector(model)
input_shape = (1, 3, 300, 300)
mm_inputs = _demo_mm_inputs(input_shape)
imgs = mm_inputs.pop('imgs')
img_metas = mm_inputs.pop('img_metas')
# Test forward train
gt_bboxes = mm_inputs['gt_bboxes']
gt_labels = mm_inputs['gt_labels']
losses = detector.forward(
imgs,
img_metas,
gt_bboxes=gt_bboxes,
gt_labels=gt_labels,
return_loss=True)
assert isinstance(losses, dict)
loss, _ = detector._parse_losses(losses)
assert float(loss.item()) > 0
# Test forward test
with torch.no_grad():
img_list = [g[None, :] for g in imgs]
batch_results = []
for one_img, one_meta in zip(img_list, img_metas):
result = detector.forward([one_img], [[one_meta]],
return_loss=False)
batch_results.append(result)
def _demo_mm_inputs(input_shape=(1, 3, 300, 300),
num_items=None, num_classes=10): # yapf: disable
"""Create a superset of inputs needed to run test or train batches.
Args:
input_shape (tuple):
input batch dimensions
num_items (List[int]):
specifies the number of boxes in each batch item
num_classes (int):
number of different labels a box might have
"""
from mmdet.core import BitmapMasks
(N, C, H, W) = input_shape
rng = np.random.RandomState(0)
imgs = rng.rand(*input_shape)
img_metas = [{
'img_shape': (H, W, C),
'ori_shape': (H, W, C),
'pad_shape': (H, W, C),
'filename': '<demo>.png',
'scale_factor': 1.0,
'flip': False,
} for _ in range(N)]
gt_bboxes = []
gt_labels = []
gt_masks = []
for batch_idx in range(N):
if num_items is None:
num_boxes = rng.randint(1, 10)
else:
num_boxes = num_items[batch_idx]
cx, cy, bw, bh = rng.rand(num_boxes, 4).T
tl_x = ((cx * W) - (W * bw / 2)).clip(0, W)
tl_y = ((cy * H) - (H * bh / 2)).clip(0, H)
br_x = ((cx * W) + (W * bw / 2)).clip(0, W)
br_y = ((cy * H) + (H * bh / 2)).clip(0, H)
boxes = np.vstack([tl_x, tl_y, br_x, br_y]).T
class_idxs = rng.randint(1, num_classes, size=num_boxes)
gt_bboxes.append(torch.FloatTensor(boxes))
gt_labels.append(torch.LongTensor(class_idxs))
mask = np.random.randint(0, 2, (len(boxes), H, W), dtype=np.uint8)
gt_masks.append(BitmapMasks(mask, H, W))
mm_inputs = {
'imgs': torch.FloatTensor(imgs).requires_grad_(True),
'img_metas': img_metas,
'gt_bboxes': gt_bboxes,
'gt_labels': gt_labels,
'gt_bboxes_ignore': None,
'gt_masks': gt_masks,
}
return mm_inputs
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment