giantmonkeyTC
mm2
c2ca15f
# Copyright (c) OpenMMLab. All rights reserved.
import numpy as np
from mmcv.transforms import LoadImageFromFile
from pyquaternion import Quaternion
# yapf: disable
from mmdet3d.datasets.transforms import (LoadAnnotations3D,
LoadImageFromFileMono3D,
LoadMultiViewImageFromFiles,
LoadPointsFromFile,
LoadPointsFromMultiSweeps,
MultiScaleFlipAug3D, Pack3DDetInputs,
PointSegClassMapping)
# yapf: enable
from mmdet3d.registry import TRANSFORMS
def is_loading_function(transform):
"""Judge whether a transform function is a loading function.
Note: `MultiScaleFlipAug3D` is a wrapper for multiple pipeline functions,
so we need to search if its inner transforms contain any loading function.
Args:
transform (dict | :obj:`Pipeline`): A transform config or a function.
Returns:
bool: Whether it is a loading function. None means can't judge.
When transform is `MultiScaleFlipAug3D`, we return None.
"""
# TODO: use more elegant way to distinguish loading modules
loading_functions = (LoadImageFromFile, LoadPointsFromFile,
LoadAnnotations3D, LoadMultiViewImageFromFiles,
LoadPointsFromMultiSweeps, Pack3DDetInputs,
LoadImageFromFileMono3D, PointSegClassMapping)
if isinstance(transform, dict):
obj_cls = TRANSFORMS.get(transform['type'])
if obj_cls is None:
return False
if obj_cls in loading_functions:
return True
if obj_cls in (MultiScaleFlipAug3D, ):
return None
elif callable(transform):
if isinstance(transform, loading_functions):
return True
if isinstance(transform, (MultiScaleFlipAug3D)):
return None
return False
def get_loading_pipeline(pipeline):
"""Only keep loading image, points and annotations related configuration.
Args:
pipeline (list[dict] | list[:obj:`Pipeline`]):
Data pipeline configs or list of pipeline functions.
Returns:
list[dict] | list[:obj:`Pipeline`]): The new pipeline list with only
keep loading image, points and annotations related configuration.
Examples:
>>> transforms = [
... dict(type='LoadPointsFromFile',
... coord_type='LIDAR', load_dim=4, use_dim=4),
... dict(type='LoadImageFromFile'),
... dict(type='LoadAnnotations3D',
... with_bbox=True, with_label_3d=True),
... dict(type='Resize',
... img_scale=[(640, 192), (2560, 768)], keep_ratio=True),
... dict(type='RandomFlip3D', flip_ratio_bev_horizontal=0.5),
... dict(type='PointsRangeFilter',
... point_cloud_range=point_cloud_range),
... dict(type='ObjectRangeFilter',
... point_cloud_range=point_cloud_range),
... dict(type='PointShuffle'),
... dict(type='Normalize', **img_norm_cfg),
... dict(type='Pad', size_divisor=32),
... dict(type='DefaultFormatBundle3D', class_names=class_names),
... dict(type='Collect3D',
... keys=['points', 'img', 'gt_bboxes_3d', 'gt_labels_3d'])
... ]
>>> expected_pipelines = [
... dict(type='LoadPointsFromFile',
... coord_type='LIDAR', load_dim=4, use_dim=4),
... dict(type='LoadImageFromFile'),
... dict(type='LoadAnnotations3D',
... with_bbox=True, with_label_3d=True),
... dict(type='DefaultFormatBundle3D', class_names=class_names),
... dict(type='Collect3D',
... keys=['points', 'img', 'gt_bboxes_3d', 'gt_labels_3d'])
... ]
>>> assert expected_pipelines == \
... get_loading_pipeline(transforms)
"""
loading_pipeline = []
for transform in pipeline:
is_loading = is_loading_function(transform)
if is_loading is None: # MultiScaleFlipAug3D
# extract its inner pipeline
if isinstance(transform, dict):
inner_pipeline = transform.get('transforms', [])
else:
inner_pipeline = transform.transforms.transforms
loading_pipeline.extend(get_loading_pipeline(inner_pipeline))
elif is_loading:
loading_pipeline.append(transform)
assert len(loading_pipeline) > 0, \
'The data pipeline in your config file must include ' \
'loading step.'
return loading_pipeline
def convert_quaternion_to_matrix(quaternion: list,
translation: list = None) -> list:
"""Compute a transform matrix by given quaternion and translation
vector."""
result = np.eye(4)
result[:3, :3] = Quaternion(quaternion).rotation_matrix
if translation is not None:
result[:3, 3] = np.array(translation)
return result.astype(np.float32).tolist()