|
|
|
|
|
import numpy as np |
|
|
from mmcv.transforms import LoadImageFromFile |
|
|
from pyquaternion import Quaternion |
|
|
|
|
|
|
|
|
from mmdet3d.datasets.transforms import (LoadAnnotations3D, |
|
|
LoadImageFromFileMono3D, |
|
|
LoadMultiViewImageFromFiles, |
|
|
LoadPointsFromFile, |
|
|
LoadPointsFromMultiSweeps, |
|
|
MultiScaleFlipAug3D, Pack3DDetInputs, |
|
|
PointSegClassMapping) |
|
|
|
|
|
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. |
|
|
""" |
|
|
|
|
|
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: |
|
|
|
|
|
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() |
|
|
|