Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
mmdetection3d
Commits
3b7ec493
Commit
3b7ec493
authored
Jun 10, 2020
by
zhangwenwei
Browse files
Use box3d structure
parent
40006a6a
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
313 additions
and
67 deletions
+313
-67
configs/kitti/hv_second_secfpn_6x8_80e_kitti-3d-car.py
configs/kitti/hv_second_secfpn_6x8_80e_kitti-3d-car.py
+14
-11
mmdet3d/core/bbox/structures/base_box3d.py
mmdet3d/core/bbox/structures/base_box3d.py
+31
-7
mmdet3d/core/bbox/structures/cam_box3d.py
mmdet3d/core/bbox/structures/cam_box3d.py
+3
-3
mmdet3d/core/bbox/structures/depth_box3d.py
mmdet3d/core/bbox/structures/depth_box3d.py
+3
-3
mmdet3d/core/bbox/structures/lidar_box3d.py
mmdet3d/core/bbox/structures/lidar_box3d.py
+33
-3
mmdet3d/datasets/nuscenes_dataset.py
mmdet3d/datasets/nuscenes_dataset.py
+8
-5
mmdet3d/models/roi_heads/mask_heads/pointwise_semantic_head.py
...3d/models/roi_heads/mask_heads/pointwise_semantic_head.py
+28
-17
mmdet3d/models/roi_heads/part_aggregation_roi_head.py
mmdet3d/models/roi_heads/part_aggregation_roi_head.py
+5
-5
tests/test_box3d.py
tests/test_box3d.py
+49
-3
tests/test_pipeline/test_outdoor_pipeline.py
tests/test_pipeline/test_outdoor_pipeline.py
+122
-1
tests/test_semantic_heads.py
tests/test_semantic_heads.py
+17
-9
No files found.
configs/kitti/hv_second_secfpn_6x8_80e_kitti-3d-car.py
View file @
3b7ec493
...
@@ -151,6 +151,9 @@ data = dict(
...
@@ -151,6 +151,9 @@ data = dict(
samples_per_gpu
=
6
,
samples_per_gpu
=
6
,
workers_per_gpu
=
4
,
workers_per_gpu
=
4
,
train
=
dict
(
train
=
dict
(
type
=
'RepeatDataset'
,
times
=
2
,
dataset
=
dict
(
type
=
dataset_type
,
type
=
dataset_type
,
data_root
=
data_root
,
data_root
=
data_root
,
ann_file
=
data_root
+
'kitti_infos_train.pkl'
,
ann_file
=
data_root
+
'kitti_infos_train.pkl'
,
...
@@ -159,7 +162,7 @@ data = dict(
...
@@ -159,7 +162,7 @@ data = dict(
pipeline
=
train_pipeline
,
pipeline
=
train_pipeline
,
modality
=
input_modality
,
modality
=
input_modality
,
classes
=
class_names
,
classes
=
class_names
,
test_mode
=
False
),
test_mode
=
False
)
)
,
val
=
dict
(
val
=
dict
(
type
=
dataset_type
,
type
=
dataset_type
,
data_root
=
data_root
,
data_root
=
data_root
,
...
@@ -197,7 +200,7 @@ momentum_config = dict(
...
@@ -197,7 +200,7 @@ momentum_config = dict(
step_ratio_up
=
0.4
,
step_ratio_up
=
0.4
,
)
)
checkpoint_config
=
dict
(
interval
=
1
)
checkpoint_config
=
dict
(
interval
=
1
)
evaluation
=
dict
(
interval
=
2
)
evaluation
=
dict
(
interval
=
1
)
# yapf:disable
# yapf:disable
log_config
=
dict
(
log_config
=
dict
(
interval
=
50
,
interval
=
50
,
...
@@ -207,7 +210,7 @@ log_config = dict(
...
@@ -207,7 +210,7 @@ log_config = dict(
])
])
# yapf:enable
# yapf:enable
# runtime settings
# runtime settings
total_epochs
=
8
0
total_epochs
=
4
0
dist_params
=
dict
(
backend
=
'nccl'
)
dist_params
=
dict
(
backend
=
'nccl'
)
log_level
=
'INFO'
log_level
=
'INFO'
work_dir
=
'./work_dirs/sec_secfpn_80e'
work_dir
=
'./work_dirs/sec_secfpn_80e'
...
...
mmdet3d/core/bbox/structures/base_box3d.py
View file @
3b7ec493
...
@@ -10,15 +10,24 @@ from .utils import limit_period, xywhr2xyxyr
...
@@ -10,15 +10,24 @@ from .utils import limit_period, xywhr2xyxyr
class
BaseInstance3DBoxes
(
object
):
class
BaseInstance3DBoxes
(
object
):
"""Base class for 3D Boxes
"""Base class for 3D Boxes
Note:
The box is bottom centered, i.e. the relative position of origin in
the box is [0.5, 0.5, 0].
Args:
Args:
tensor (torch.Tensor | np.ndarray): a Nxbox_dim matrix.
tensor (torch.Tensor | np.ndarray
| list
): a Nxbox_dim matrix.
box_dim (int): number of the dimension of a box
box_dim (int): number of the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw).
Each row is (x, y, z, x_size, y_size, z_size, yaw).
with_yaw (bool): if True, the value of yaw will be
Default to 7.
set to 0 as minmax boxes.
with_yaw (bool): Whether the box is with yaw rotation.
If False, the value of yaw will be set to 0 as minmax boxes.
Default to True.
origin (tuple): The relative position of origin in the box.
Default to [0.5, 0.5, 0]. This will guide the box be converted to
[0.5, 0.5, 0] mode.
"""
"""
def
__init__
(
self
,
tensor
,
box_dim
=
7
,
with_yaw
=
True
):
def
__init__
(
self
,
tensor
,
box_dim
=
7
,
with_yaw
=
True
,
origin
=
[
0.5
,
0.5
,
0
]
):
if
isinstance
(
tensor
,
torch
.
Tensor
):
if
isinstance
(
tensor
,
torch
.
Tensor
):
device
=
tensor
.
device
device
=
tensor
.
device
else
:
else
:
...
@@ -41,6 +50,11 @@ class BaseInstance3DBoxes(object):
...
@@ -41,6 +50,11 @@ class BaseInstance3DBoxes(object):
self
.
with_yaw
=
with_yaw
self
.
with_yaw
=
with_yaw
self
.
tensor
=
tensor
self
.
tensor
=
tensor
if
origin
!=
[
0.5
,
0.5
,
0
]:
dst
=
self
.
tensor
.
new_tensor
([
0.5
,
0.5
,
0
])
src
=
self
.
tensor
.
new_tensor
(
origin
)
self
.
tensor
[:,
:
3
]
+=
self
.
tensor
[:,
3
:
6
]
*
(
dst
-
src
)
@
property
@
property
def
volume
(
self
):
def
volume
(
self
):
"""Computes the volume of all the boxes.
"""Computes the volume of all the boxes.
...
@@ -61,12 +75,21 @@ class BaseInstance3DBoxes(object):
...
@@ -61,12 +75,21 @@ class BaseInstance3DBoxes(object):
"""
"""
return
self
.
tensor
[:,
3
:
6
]
return
self
.
tensor
[:,
3
:
6
]
@
property
def
yaw
(
self
):
"""Obtain the rotation of all the boxes.
Returns:
torch.Tensor: a vector with yaw of each box.
"""
return
self
.
tensor
[:,
6
]
@
property
@
property
def
height
(
self
):
def
height
(
self
):
"""Obtain the height of all the boxes.
"""Obtain the height of all the boxes.
Returns:
Returns:
torch.Tensor: a vector with
volume
of each box.
torch.Tensor: a vector with
height
of each box.
"""
"""
return
self
.
tensor
[:,
5
]
return
self
.
tensor
[:,
5
]
...
@@ -438,7 +461,8 @@ class BaseInstance3DBoxes(object):
...
@@ -438,7 +461,8 @@ class BaseInstance3DBoxes(object):
BaseInstance3DBoxes: A new bbox with data and other
BaseInstance3DBoxes: A new bbox with data and other
properties are similar to self.
properties are similar to self.
"""
"""
new_tensor
=
self
.
tensor
.
new_tensor
(
data
)
new_tensor
=
self
.
tensor
.
new_tensor
(
data
)
\
if
not
isinstance
(
data
,
torch
.
Tensor
)
else
data
.
to
(
self
.
device
)
original_type
=
type
(
self
)
original_type
=
type
(
self
)
return
original_type
(
return
original_type
(
new_tensor
,
box_dim
=
self
.
box_dim
,
with_yaw
=
self
.
with_yaw
)
new_tensor
,
box_dim
=
self
.
box_dim
,
with_yaw
=
self
.
with_yaw
)
mmdet3d/core/bbox/structures/cam_box3d.py
View file @
3b7ec493
...
@@ -29,8 +29,8 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
...
@@ -29,8 +29,8 @@ class CameraInstance3DBoxes(BaseInstance3DBoxes):
tensor (torch.Tensor): float matrix of N x box_dim.
tensor (torch.Tensor): float matrix of N x box_dim.
box_dim (int): integer indicates the dimension of a box
box_dim (int): integer indicates the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
with_yaw (bool): if True, the value of yaw will be
with_yaw (bool): if True, the value of yaw will be
set to 0 as minmax
set to 0 as minmax
boxes.
boxes.
"""
"""
@
property
@
property
...
...
mmdet3d/core/bbox/structures/depth_box3d.py
View file @
3b7ec493
...
@@ -26,8 +26,8 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
...
@@ -26,8 +26,8 @@ class DepthInstance3DBoxes(BaseInstance3DBoxes):
tensor (torch.Tensor): float matrix of N x box_dim.
tensor (torch.Tensor): float matrix of N x box_dim.
box_dim (int): integer indicates the dimension of a box
box_dim (int): integer indicates the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
with_yaw (bool): if True, the value of yaw will be
with_yaw (bool): if True, the value of yaw will be
set to 0 as minmax
set to 0 as minmax
boxes.
boxes.
"""
"""
@
property
@
property
...
...
mmdet3d/core/bbox/structures/lidar_box3d.py
View file @
3b7ec493
import
numpy
as
np
import
numpy
as
np
import
torch
import
torch
from
mmdet3d.ops.roiaware_pool3d
import
points_in_boxes_gpu
from
.base_box3d
import
BaseInstance3DBoxes
from
.base_box3d
import
BaseInstance3DBoxes
from
.utils
import
limit_period
,
rotation_3d_in_axis
from
.utils
import
limit_period
,
rotation_3d_in_axis
...
@@ -26,8 +27,8 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
...
@@ -26,8 +27,8 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
tensor (torch.Tensor): float matrix of N x box_dim.
tensor (torch.Tensor): float matrix of N x box_dim.
box_dim (int): integer indicates the dimension of a box
box_dim (int): integer indicates the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
with_yaw (bool): if True, the value of yaw will be
with_yaw (bool): if True, the value of yaw will be
set to 0 as minmax
set to 0 as minmax
boxes.
boxes.
"""
"""
@
property
@
property
...
@@ -196,3 +197,32 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
...
@@ -196,3 +197,32 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
from
.box_3d_mode
import
Box3DMode
from
.box_3d_mode
import
Box3DMode
return
Box3DMode
.
convert
(
return
Box3DMode
.
convert
(
box
=
self
,
src
=
Box3DMode
.
LIDAR
,
dst
=
dst
,
rt_mat
=
rt_mat
)
box
=
self
,
src
=
Box3DMode
.
LIDAR
,
dst
=
dst
,
rt_mat
=
rt_mat
)
def
enlarged_box
(
self
,
extra_width
):
"""Enlarge the length, width and height boxes
Args:
extra_width (float | torch.Tensor): extra width to enlarge the box
Returns:
:obj:LiDARInstance3DBoxes: enlarged boxes
"""
enlarged_boxes
=
self
.
tensor
.
clone
()
enlarged_boxes
[:,
3
:
6
]
+=
extra_width
*
2
# bottom center z minus extra_width
enlarged_boxes
[:,
2
]
-=
extra_width
return
self
.
new_box
(
enlarged_boxes
)
def
points_in_boxes
(
self
,
points
):
"""Find the box which the points are in.
Args:
points (:obj:torch.Tensor): Points in shape Nx3
Returns:
torch.Tensor: The index of box where each point are in.
"""
box_idx
=
points_in_boxes_gpu
(
points
.
unsqueeze
(
0
),
self
.
tensor
.
unsqueeze
(
0
).
to
(
points
.
device
)).
squeeze
(
0
)
return
box_idx
mmdet3d/datasets/nuscenes_dataset.py
View file @
3b7ec493
...
@@ -7,7 +7,7 @@ import pyquaternion
...
@@ -7,7 +7,7 @@ import pyquaternion
from
nuscenes.utils.data_classes
import
Box
as
NuScenesBox
from
nuscenes.utils.data_classes
import
Box
as
NuScenesBox
from
mmdet.datasets
import
DATASETS
from
mmdet.datasets
import
DATASETS
from
..core.bbox
import
box_np_ops
from
..core.bbox
import
LiDARInstance3DBoxes
,
box_np_ops
from
.custom_3d
import
Custom3DDataset
from
.custom_3d
import
Custom3DDataset
...
@@ -152,10 +152,6 @@ class NuScenesDataset(Custom3DDataset):
...
@@ -152,10 +152,6 @@ class NuScenesDataset(Custom3DDataset):
# filter out bbox containing no points
# filter out bbox containing no points
mask
=
info
[
'num_lidar_pts'
]
>
0
mask
=
info
[
'num_lidar_pts'
]
>
0
gt_bboxes_3d
=
info
[
'gt_boxes'
][
mask
]
gt_bboxes_3d
=
info
[
'gt_boxes'
][
mask
]
# the nuscenes box center is [0.5, 0.5, 0.5], we keep it
# the same as KITTI [0.5, 0.5, 0]
box_np_ops
.
change_box3d_center_
(
gt_bboxes_3d
,
[
0.5
,
0.5
,
0.5
],
[
0.5
,
0.5
,
0
])
gt_names_3d
=
info
[
'gt_names'
][
mask
]
gt_names_3d
=
info
[
'gt_names'
][
mask
]
gt_labels_3d
=
[]
gt_labels_3d
=
[]
for
cat
in
gt_names_3d
:
for
cat
in
gt_names_3d
:
...
@@ -171,6 +167,13 @@ class NuScenesDataset(Custom3DDataset):
...
@@ -171,6 +167,13 @@ class NuScenesDataset(Custom3DDataset):
gt_velocity
[
nan_mask
]
=
[
0.0
,
0.0
]
gt_velocity
[
nan_mask
]
=
[
0.0
,
0.0
]
gt_bboxes_3d
=
np
.
concatenate
([
gt_bboxes_3d
,
gt_velocity
],
axis
=-
1
)
gt_bboxes_3d
=
np
.
concatenate
([
gt_bboxes_3d
,
gt_velocity
],
axis
=-
1
)
# the nuscenes box center is [0.5, 0.5, 0.5], we keep it
# the same as KITTI [0.5, 0.5, 0]
gt_bboxes_3d
=
LiDARInstance3DBoxes
(
gt_bboxes_3d
,
box_dim
=
gt_bboxes_3d
.
shape
[
-
1
],
origin
=
[
0.5
,
0.5
,
0.5
])
anns_results
=
dict
(
anns_results
=
dict
(
gt_bboxes_3d
=
gt_bboxes_3d
,
gt_bboxes_3d
=
gt_bboxes_3d
,
gt_labels_3d
=
gt_labels_3d
,
gt_labels_3d
=
gt_labels_3d
,
...
...
mmdet3d/models/roi_heads/mask_heads/pointwise_semantic_head.py
View file @
3b7ec493
...
@@ -5,7 +5,6 @@ import torch.nn.functional as F
...
@@ -5,7 +5,6 @@ import torch.nn.functional as F
from
mmdet3d.core
import
multi_apply
from
mmdet3d.core
import
multi_apply
from
mmdet3d.core.bbox
import
box_torch_ops
from
mmdet3d.core.bbox
import
box_torch_ops
from
mmdet3d.models.builder
import
build_loss
from
mmdet3d.models.builder
import
build_loss
from
mmdet3d.ops.roiaware_pool3d
import
points_in_boxes_gpu
from
mmdet.models
import
HEADS
from
mmdet.models
import
HEADS
...
@@ -14,7 +13,7 @@ class PointwiseSemanticHead(nn.Module):
...
@@ -14,7 +13,7 @@ class PointwiseSemanticHead(nn.Module):
"""Semantic segmentation head for point-wise segmentation.
"""Semantic segmentation head for point-wise segmentation.
Predict point-wise segmentation and part regression results for PartA2.
Predict point-wise segmentation and part regression results for PartA2.
See https://arxiv.org/abs/1907.03670 for more detials.
See
`paper <
https://arxiv.org/abs/1907.03670
>`_
for more detials.
Args:
Args:
in_channels (int): the number of input channel.
in_channels (int): the number of input channel.
...
@@ -65,28 +64,27 @@ class PointwiseSemanticHead(nn.Module):
...
@@ -65,28 +64,27 @@ class PointwiseSemanticHead(nn.Module):
seg_preds
=
seg_preds
,
part_preds
=
part_preds
,
part_feats
=
part_feats
)
seg_preds
=
seg_preds
,
part_preds
=
part_preds
,
part_feats
=
part_feats
)
def
get_targets_single
(
self
,
voxel_centers
,
gt_bboxes_3d
,
gt_labels_3d
):
def
get_targets_single
(
self
,
voxel_centers
,
gt_bboxes_3d
,
gt_labels_3d
):
"""generate segmentation and part prediction targets
"""generate segmentation and part prediction targets
for a single sample
Args:
Args:
voxel_centers (torch.Tensor): shape [voxel_num, 3],
voxel_centers (torch.Tensor): shape [voxel_num, 3],
the center of voxels
the center of voxels
gt_bboxes_3d (torch.Tensor): shape [box_num, 7], gt boxes
gt_bboxes_3d (:obj:BaseInstance3DBoxes): gt boxes containing tensor
of shape [box_num, 7].
gt_labels_3d (torch.Tensor): shape [box_num], class label of gt
gt_labels_3d (torch.Tensor): shape [box_num], class label of gt
Returns:
Returns:
tuple : segmentation targets with shape [voxel_num]
tuple : segmentation targets with shape [voxel_num]
part prediction targets with shape [voxel_num, 3]
part prediction targets with shape [voxel_num, 3]
"""
"""
enlarged_gt_boxes
=
box_torch_ops
.
enlarge_box3d_lidar
(
gt_bboxes_3d
=
gt_bboxes_3d
.
to
(
voxel_centers
.
device
)
gt_bboxes_3d
,
extra_width
=
self
.
extra_width
)
enlarged_gt_boxes
=
gt_bboxes_3d
.
enlarged_box
(
self
.
extra_width
)
part_targets
=
voxel_centers
.
new_zeros
((
voxel_centers
.
shape
[
0
],
3
),
part_targets
=
voxel_centers
.
new_zeros
((
voxel_centers
.
shape
[
0
],
3
),
dtype
=
torch
.
float32
)
dtype
=
torch
.
float32
)
box_idx
=
points_in_boxes_gpu
(
box_idx
=
gt_bboxes_3d
.
points_in_boxes
(
voxel_centers
)
voxel_centers
.
unsqueeze
(
0
),
enlarge_box_idx
=
enlarged_gt_boxes
.
points_in_boxes
(
gt_bboxes_3d
.
unsqueeze
(
0
)).
squeeze
(
0
)
# -1 ~ box_num
voxel_centers
).
long
()
enlarge_box_idx
=
points_in_boxes_gpu
(
voxel_centers
.
unsqueeze
(
0
),
enlarged_gt_boxes
.
unsqueeze
(
0
)).
squeeze
(
0
).
long
()
# -1 ~ box_num
gt_labels_pad
=
F
.
pad
(
gt_labels_pad
=
F
.
pad
(
gt_labels_3d
,
(
1
,
0
),
mode
=
'constant'
,
value
=
self
.
num_classes
)
gt_labels_3d
,
(
1
,
0
),
mode
=
'constant'
,
value
=
self
.
num_classes
)
...
@@ -95,24 +93,37 @@ class PointwiseSemanticHead(nn.Module):
...
@@ -95,24 +93,37 @@ class PointwiseSemanticHead(nn.Module):
ignore_flag
=
fg_pt_flag
^
(
enlarge_box_idx
>
-
1
)
ignore_flag
=
fg_pt_flag
^
(
enlarge_box_idx
>
-
1
)
seg_targets
[
ignore_flag
]
=
-
1
seg_targets
[
ignore_flag
]
=
-
1
for
k
in
range
(
gt_bboxes_3d
.
shape
[
0
]
):
for
k
in
range
(
len
(
gt_bboxes_3d
)
):
k_box_flag
=
box_idx
==
k
k_box_flag
=
box_idx
==
k
# no point in current box (caused by velodyne reduce)
# no point in current box (caused by velodyne reduce)
if
not
k_box_flag
.
any
():
if
not
k_box_flag
.
any
():
continue
continue
fg_voxels
=
voxel_centers
[
k_box_flag
]
fg_voxels
=
voxel_centers
[
k_box_flag
]
transformed_voxels
=
fg_voxels
-
gt_bboxes_3d
[
k
,
0
:
3
]
transformed_voxels
=
fg_voxels
-
gt_bboxes_3d
.
bottom_center
[
k
]
transformed_voxels
=
box_torch_ops
.
rotation_3d_in_axis
(
transformed_voxels
=
box_torch_ops
.
rotation_3d_in_axis
(
transformed_voxels
.
unsqueeze
(
0
),
transformed_voxels
.
unsqueeze
(
0
),
-
gt_bboxes_3d
[
k
,
6
].
view
(
1
),
-
gt_bboxes_3d
.
yaw
[
k
].
view
(
1
),
axis
=
2
)
axis
=
2
)
part_targets
[
k_box_flag
]
=
transformed_voxels
/
gt_bboxes_3d
[
part_targets
[
k_box_flag
]
=
transformed_voxels
/
gt_bboxes_3d
.
dims
[
k
,
3
:
6
]
+
voxel_centers
.
new_tensor
([
0.5
,
0.5
,
0
])
k
]
+
voxel_centers
.
new_tensor
([
0.5
,
0.5
,
0
])
part_targets
=
torch
.
clamp
(
part_targets
,
min
=
0
)
part_targets
=
torch
.
clamp
(
part_targets
,
min
=
0
)
return
seg_targets
,
part_targets
return
seg_targets
,
part_targets
def
get_targets
(
self
,
voxels_dict
,
gt_bboxes_3d
,
gt_labels_3d
):
def
get_targets
(
self
,
voxels_dict
,
gt_bboxes_3d
,
gt_labels_3d
):
"""generate segmentation and part prediction targets
Args:
voxel_centers (torch.Tensor): shape [voxel_num, 3],
the center of voxels
gt_bboxes_3d (list[:obj:BaseInstance3DBoxes]): list of gt boxes
containing tensor of shape [box_num, 7].
gt_labels_3d (list[torch.Tensor]): list of GT labels.
Returns:
tuple : segmentation targets with shape [voxel_num]
part prediction targets with shape [voxel_num, 3]
"""
batch_size
=
len
(
gt_labels_3d
)
batch_size
=
len
(
gt_labels_3d
)
voxel_center_list
=
[]
voxel_center_list
=
[]
for
idx
in
range
(
batch_size
):
for
idx
in
range
(
batch_size
):
...
...
mmdet3d/models/roi_heads/part_aggregation_roi_head.py
View file @
3b7ec493
...
@@ -8,7 +8,7 @@ from ..builder import build_head, build_roi_extractor
...
@@ -8,7 +8,7 @@ from ..builder import build_head, build_roi_extractor
from
.base_3droi_head
import
Base3DRoIHead
from
.base_3droi_head
import
Base3DRoIHead
@
HEADS
.
register_module
@
HEADS
.
register_module
()
class
PartAggregationROIHead
(
Base3DRoIHead
):
class
PartAggregationROIHead
(
Base3DRoIHead
):
"""Part aggregation roi head for PartA2"""
"""Part aggregation roi head for PartA2"""
...
@@ -174,7 +174,7 @@ class PartAggregationROIHead(Base3DRoIHead):
...
@@ -174,7 +174,7 @@ class PartAggregationROIHead(Base3DRoIHead):
cur_proposal_list
=
proposal_list
[
batch_idx
]
cur_proposal_list
=
proposal_list
[
batch_idx
]
cur_boxes
=
cur_proposal_list
[
'boxes_3d'
]
cur_boxes
=
cur_proposal_list
[
'boxes_3d'
]
cur_labels_3d
=
cur_proposal_list
[
'labels_3d'
]
cur_labels_3d
=
cur_proposal_list
[
'labels_3d'
]
cur_gt_bboxes
=
gt_bboxes_3d
[
batch_idx
]
cur_gt_bboxes
=
gt_bboxes_3d
[
batch_idx
]
.
to
(
cur_boxes
.
device
)
cur_gt_labels
=
gt_labels_3d
[
batch_idx
]
cur_gt_labels
=
gt_labels_3d
[
batch_idx
]
batch_num_gts
=
0
batch_num_gts
=
0
...
@@ -189,7 +189,7 @@ class PartAggregationROIHead(Base3DRoIHead):
...
@@ -189,7 +189,7 @@ class PartAggregationROIHead(Base3DRoIHead):
pred_per_cls
=
(
cur_labels_3d
==
i
)
pred_per_cls
=
(
cur_labels_3d
==
i
)
cur_assign_res
=
assigner
.
assign
(
cur_assign_res
=
assigner
.
assign
(
cur_boxes
[
pred_per_cls
],
cur_boxes
[
pred_per_cls
],
cur_gt_bboxes
[
gt_per_cls
],
cur_gt_bboxes
.
tensor
[
gt_per_cls
],
gt_labels
=
cur_gt_labels
[
gt_per_cls
])
gt_labels
=
cur_gt_labels
[
gt_per_cls
])
# gather assign_results in different class into one result
# gather assign_results in different class into one result
batch_num_gts
+=
cur_assign_res
.
num_gts
batch_num_gts
+=
cur_assign_res
.
num_gts
...
@@ -215,11 +215,11 @@ class PartAggregationROIHead(Base3DRoIHead):
...
@@ -215,11 +215,11 @@ class PartAggregationROIHead(Base3DRoIHead):
batch_gt_labels
)
batch_gt_labels
)
else
:
# for single class
else
:
# for single class
assign_result
=
self
.
bbox_assigner
.
assign
(
assign_result
=
self
.
bbox_assigner
.
assign
(
cur_boxes
,
cur_gt_bboxes
,
gt_labels
=
cur_gt_labels
)
cur_boxes
,
cur_gt_bboxes
.
tensor
,
gt_labels
=
cur_gt_labels
)
# sample boxes
# sample boxes
sampling_result
=
self
.
bbox_sampler
.
sample
(
assign_result
,
sampling_result
=
self
.
bbox_sampler
.
sample
(
assign_result
,
cur_boxes
,
cur_boxes
,
cur_gt_bboxes
,
cur_gt_bboxes
.
tensor
,
cur_gt_labels
)
cur_gt_labels
)
sampling_results
.
append
(
sampling_result
)
sampling_results
.
append
(
sampling_result
)
return
sampling_results
return
sampling_results
...
...
tests/test_box3d.py
View file @
3b7ec493
...
@@ -13,6 +13,46 @@ def test_lidar_boxes3d():
...
@@ -13,6 +13,46 @@ def test_lidar_boxes3d():
assert
boxes
.
tensor
.
shape
[
0
]
==
0
assert
boxes
.
tensor
.
shape
[
0
]
==
0
assert
boxes
.
tensor
.
shape
[
1
]
==
7
assert
boxes
.
tensor
.
shape
[
1
]
==
7
# Test init with origin
gravity_center_box
=
np
.
array
(
[[
-
5.24223238e+00
,
4.00209696e+01
,
2.97570381e-01
,
2.06200000e+00
,
4.40900000e+00
,
1.54800000e+00
,
-
1.48801203e+00
],
[
-
2.66751588e+01
,
5.59499564e+00
,
-
9.14345860e-01
,
3.43000000e-01
,
4.58000000e-01
,
7.82000000e-01
,
-
4.62759755e+00
],
[
-
5.80979675e+00
,
3.54092357e+01
,
2.00889888e-01
,
2.39600000e+00
,
3.96900000e+00
,
1.73200000e+00
,
-
4.65203216e+00
],
[
-
3.13086877e+01
,
1.09007628e+00
,
-
1.94612112e-01
,
1.94400000e+00
,
3.85700000e+00
,
1.72300000e+00
,
-
2.81427027e+00
]],
dtype
=
np
.
float32
)
bottom_center_box
=
LiDARInstance3DBoxes
(
gravity_center_box
,
origin
=
[
0.5
,
0.5
,
0.5
])
expected_tensor
=
torch
.
tensor
(
[[
-
5.24223238e+00
,
4.00209696e+01
,
-
4.76429619e-01
,
2.06200000e+00
,
4.40900000e+00
,
1.54800000e+00
,
-
1.48801203e+00
],
[
-
2.66751588e+01
,
5.59499564e+00
,
-
1.30534586e+00
,
3.43000000e-01
,
4.58000000e-01
,
7.82000000e-01
,
-
4.62759755e+00
],
[
-
5.80979675e+00
,
3.54092357e+01
,
-
6.65110112e-01
,
2.39600000e+00
,
3.96900000e+00
,
1.73200000e+00
,
-
4.65203216e+00
],
[
-
3.13086877e+01
,
1.09007628e+00
,
-
1.05611211e+00
,
1.94400000e+00
,
3.85700000e+00
,
1.72300000e+00
,
-
2.81427027e+00
]])
assert
torch
.
allclose
(
expected_tensor
,
bottom_center_box
.
tensor
)
# Test init with numpy array
# Test init with numpy array
np_boxes
=
np
.
array
(
np_boxes
=
np
.
array
(
[[
1.7802081
,
2.516249
,
-
1.7501148
,
1.75
,
3.39
,
1.65
,
1.48
],
[[
1.7802081
,
2.516249
,
-
1.7501148
,
1.75
,
3.39
,
1.65
,
1.48
],
...
@@ -313,6 +353,8 @@ def test_boxes_conversion():
...
@@ -313,6 +353,8 @@ def test_boxes_conversion():
[
31.31978
,
8.162144
,
-
1.6217787
,
1.74
,
3.77
,
1.48
,
2.79
]])
[
31.31978
,
8.162144
,
-
1.6217787
,
1.74
,
3.77
,
1.48
,
2.79
]])
cam_box_tensor
=
Box3DMode
.
convert
(
lidar_boxes
.
tensor
,
Box3DMode
.
LIDAR
,
cam_box_tensor
=
Box3DMode
.
convert
(
lidar_boxes
.
tensor
,
Box3DMode
.
LIDAR
,
Box3DMode
.
CAM
)
Box3DMode
.
CAM
)
expected_box
=
lidar_boxes
.
convert_to
(
Box3DMode
.
CAM
)
assert
torch
.
equal
(
expected_box
.
tensor
,
cam_box_tensor
)
# Some properties should be the same
# Some properties should be the same
cam_boxes
=
CameraInstance3DBoxes
(
cam_box_tensor
)
cam_boxes
=
CameraInstance3DBoxes
(
cam_box_tensor
)
...
@@ -342,7 +384,7 @@ def test_boxes_conversion():
...
@@ -342,7 +384,7 @@ def test_boxes_conversion():
# test similar mode conversion
# test similar mode conversion
same_results
=
Box3DMode
.
convert
(
depth_box_tensor
,
Box3DMode
.
DEPTH
,
same_results
=
Box3DMode
.
convert
(
depth_box_tensor
,
Box3DMode
.
DEPTH
,
Box3DMode
.
DEPTH
)
Box3DMode
.
DEPTH
)
assert
(
same_results
==
depth_box_tensor
)
.
all
()
assert
torch
.
equal
(
same_results
,
depth_box_tensor
)
# test conversion with a given rt_mat
# test conversion with a given rt_mat
camera_boxes
=
CameraInstance3DBoxes
(
camera_boxes
=
CameraInstance3DBoxes
(
...
@@ -418,8 +460,10 @@ def test_boxes_conversion():
...
@@ -418,8 +460,10 @@ def test_boxes_conversion():
[
1.4856
,
2.5299
,
-
0.5570
,
0.9385
,
2.1404
,
0.8954
,
3.0601
]],
[
1.4856
,
2.5299
,
-
0.5570
,
0.9385
,
2.1404
,
0.8954
,
3.0601
]],
dtype
=
torch
.
float32
)
dtype
=
torch
.
float32
)
depth_boxes
=
DepthInstance3DBoxes
(
depth_boxes
)
depth_boxes
=
DepthInstance3DBoxes
(
depth_boxes
)
depth_to_lidar_box
=
Box3DMode
.
convert
(
depth_boxes
,
Box3DMode
.
DEPTH
,
depth_to_lidar_box
=
depth_boxes
.
convert_to
(
Box3DMode
.
LIDAR
)
Box3DMode
.
LIDAR
)
expected_box
=
depth_to_lidar_box
.
convert_to
(
Box3DMode
.
DEPTH
)
assert
torch
.
equal
(
depth_boxes
.
tensor
,
expected_box
.
tensor
)
lidar_to_depth_box
=
Box3DMode
.
convert
(
depth_to_lidar_box
,
Box3DMode
.
LIDAR
,
lidar_to_depth_box
=
Box3DMode
.
convert
(
depth_to_lidar_box
,
Box3DMode
.
LIDAR
,
Box3DMode
.
DEPTH
)
Box3DMode
.
DEPTH
)
assert
torch
.
allclose
(
depth_boxes
.
tensor
,
lidar_to_depth_box
.
tensor
)
assert
torch
.
allclose
(
depth_boxes
.
tensor
,
lidar_to_depth_box
.
tensor
)
...
@@ -430,6 +474,8 @@ def test_boxes_conversion():
...
@@ -430,6 +474,8 @@ def test_boxes_conversion():
Box3DMode
.
CAM
)
Box3DMode
.
CAM
)
cam_to_depth_box
=
Box3DMode
.
convert
(
depth_to_cam_box
,
Box3DMode
.
CAM
,
cam_to_depth_box
=
Box3DMode
.
convert
(
depth_to_cam_box
,
Box3DMode
.
CAM
,
Box3DMode
.
DEPTH
)
Box3DMode
.
DEPTH
)
expected_tensor
=
depth_to_cam_box
.
convert_to
(
Box3DMode
.
DEPTH
)
assert
torch
.
equal
(
expected_tensor
.
tensor
,
cam_to_depth_box
.
tensor
)
assert
torch
.
allclose
(
depth_boxes
.
tensor
,
cam_to_depth_box
.
tensor
)
assert
torch
.
allclose
(
depth_boxes
.
tensor
,
cam_to_depth_box
.
tensor
)
assert
torch
.
allclose
(
depth_boxes
.
volume
,
cam_to_depth_box
.
volume
)
assert
torch
.
allclose
(
depth_boxes
.
volume
,
cam_to_depth_box
.
volume
)
...
...
tests/test_pipeline/test_outdoor_pipeline.py
View file @
3b7ec493
...
@@ -5,7 +5,7 @@ from mmdet3d.core.bbox import LiDARInstance3DBoxes
...
@@ -5,7 +5,7 @@ from mmdet3d.core.bbox import LiDARInstance3DBoxes
from
mmdet3d.datasets.pipelines
import
Compose
from
mmdet3d.datasets.pipelines
import
Compose
def
test_outdoor_pipeline
():
def
test_outdoor_
aug_
pipeline
():
point_cloud_range
=
[
0
,
-
40
,
-
3
,
70.4
,
40
,
1
]
point_cloud_range
=
[
0
,
-
40
,
-
3
,
70.4
,
40
,
1
]
class_names
=
[
'Car'
]
class_names
=
[
'Car'
]
np
.
random
.
seed
(
0
)
np
.
random
.
seed
(
0
)
...
@@ -119,3 +119,124 @@ def test_outdoor_pipeline():
...
@@ -119,3 +119,124 @@ def test_outdoor_pipeline():
[
8.9259
,
-
1.2578
,
-
1.6081
,
1.5223
,
3.0350
,
1.3308
,
-
1.7212
]])
[
8.9259
,
-
1.2578
,
-
1.6081
,
1.5223
,
3.0350
,
1.3308
,
-
1.7212
]])
assert
torch
.
allclose
(
assert
torch
.
allclose
(
output
[
'gt_bboxes_3d'
].
_data
.
tensor
,
expected_tensor
,
atol
=
1e-3
)
output
[
'gt_bboxes_3d'
].
_data
.
tensor
,
expected_tensor
,
atol
=
1e-3
)
def
test_outdoor_velocity_aug_pipeline
():
point_cloud_range
=
[
-
50
,
-
50
,
-
5
,
50
,
50
,
3
]
class_names
=
[
'car'
,
'truck'
,
'trailer'
,
'bus'
,
'construction_vehicle'
,
'bicycle'
,
'motorcycle'
,
'pedestrian'
,
'traffic_cone'
,
'barrier'
]
np
.
random
.
seed
(
0
)
train_pipeline
=
[
dict
(
type
=
'LoadPointsFromFile'
,
load_dim
=
4
,
use_dim
=
4
),
dict
(
type
=
'LoadAnnotations3D'
,
with_bbox_3d
=
True
,
with_label_3d
=
True
),
dict
(
type
=
'GlobalRotScale'
,
rot_uniform_noise
=
[
-
0.3925
,
0.3925
],
scaling_uniform_noise
=
[
0.95
,
1.05
],
trans_normal_noise
=
[
0
,
0
,
0
]),
dict
(
type
=
'RandomFlip3D'
,
flip_ratio
=
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
=
'DefaultFormatBundle3D'
,
class_names
=
class_names
),
dict
(
type
=
'Collect3D'
,
keys
=
[
'points'
,
'gt_bboxes_3d'
,
'gt_labels_3d'
])
]
pipeline
=
Compose
(
train_pipeline
)
gt_bboxes_3d
=
LiDARInstance3DBoxes
(
torch
.
tensor
(
[[
-
5.2422e+00
,
4.0021e+01
,
-
4.7643e-01
,
2.0620e+00
,
4.4090e+00
,
1.5480e+00
,
-
1.4880e+00
,
8.5338e-03
,
4.4934e-02
],
[
-
2.6675e+01
,
5.5950e+00
,
-
1.3053e+00
,
3.4300e-01
,
4.5800e-01
,
7.8200e-01
,
-
4.6276e+00
,
-
4.3284e-04
,
-
1.8543e-03
],
[
-
5.8098e+00
,
3.5409e+01
,
-
6.6511e-01
,
2.3960e+00
,
3.9690e+00
,
1.7320e+00
,
-
4.6520e+00
,
0.0000e+00
,
0.0000e+00
],
[
-
3.1309e+01
,
1.0901e+00
,
-
1.0561e+00
,
1.9440e+00
,
3.8570e+00
,
1.7230e+00
,
-
2.8143e+00
,
-
2.7606e-02
,
-
8.0573e-02
],
[
-
4.5642e+01
,
2.0136e+01
,
-
2.4681e-02
,
1.9870e+00
,
4.4400e+00
,
1.9420e+00
,
2.8336e-01
,
0.0000e+00
,
0.0000e+00
],
[
-
5.1617e+00
,
1.8305e+01
,
-
1.0879e+00
,
2.3230e+00
,
4.8510e+00
,
1.3710e+00
,
-
1.5803e+00
,
0.0000e+00
,
0.0000e+00
],
[
-
2.5285e+01
,
4.1442e+00
,
-
1.2713e+00
,
1.7550e+00
,
1.9890e+00
,
2.2200e+00
,
-
4.4900e+00
,
-
3.1784e-02
,
-
1.5291e-01
],
[
-
2.2611e+00
,
1.9170e+01
,
-
1.1452e+00
,
9.1900e-01
,
1.1230e+00
,
1.9310e+00
,
4.7790e-02
,
6.7684e-02
,
-
1.7537e+00
],
[
-
6.5878e+01
,
1.3500e+01
,
-
2.2528e-01
,
1.8200e+00
,
3.8520e+00
,
1.5450e+00
,
-
2.8757e+00
,
0.0000e+00
,
0.0000e+00
],
[
-
5.4490e+00
,
2.8363e+01
,
-
7.7275e-01
,
2.2360e+00
,
3.7540e+00
,
1.5590e+00
,
-
4.6520e+00
,
-
7.9736e-03
,
7.7207e-03
]],
dtype
=
torch
.
float32
),
box_dim
=
9
)
gt_labels_3d
=
np
.
array
([
0
,
8
,
0
,
0
,
0
,
0
,
-
1
,
7
,
0
,
0
])
results
=
dict
(
pts_filename
=
'tests/data/kitti/a.bin'
,
ann_info
=
dict
(
gt_bboxes_3d
=
gt_bboxes_3d
,
gt_labels_3d
=
gt_labels_3d
),
bbox3d_fields
=
[],
)
output
=
pipeline
(
results
)
expected_tensor
=
torch
.
tensor
(
[[
-
3.7849e+00
,
-
4.1057e+01
,
-
4.8668e-01
,
2.1064e+00
,
4.5039e+00
,
1.5813e+00
,
-
1.6919e+00
,
1.0469e-02
,
-
4.5533e-02
],
[
-
2.7010e+01
,
-
6.7551e+00
,
-
1.3334e+00
,
3.5038e-01
,
4.6786e-01
,
7.9883e-01
,
1.4477e+00
,
-
5.1440e-04
,
1.8758e-03
],
[
-
4.5448e+00
,
-
3.6372e+01
,
-
6.7942e-01
,
2.4476e+00
,
4.0544e+00
,
1.7693e+00
,
1.4721e+00
,
0.0000e+00
,
-
0.0000e+00
],
[
-
3.1916e+01
,
-
2.3379e+00
,
-
1.0788e+00
,
1.9858e+00
,
3.9400e+00
,
1.7601e+00
,
-
3.6564e-01
,
-
3.1333e-02
,
8.1166e-02
],
[
-
4.5802e+01
,
-
2.2340e+01
,
-
2.5213e-02
,
2.0298e+00
,
4.5355e+00
,
1.9838e+00
,
2.8199e+00
,
0.0000e+00
,
-
0.0000e+00
],
[
-
4.5526e+00
,
-
1.8887e+01
,
-
1.1114e+00
,
2.3730e+00
,
4.9554e+00
,
1.4005e+00
,
-
1.5997e+00
,
0.0000e+00
,
-
0.0000e+00
],
[
-
2.5648e+01
,
-
5.2197e+00
,
-
1.2987e+00
,
1.7928e+00
,
2.0318e+00
,
2.2678e+00
,
1.3100e+00
,
-
3.8428e-02
,
1.5485e-01
],
[
-
1.5578e+00
,
-
1.9657e+01
,
-
1.1699e+00
,
9.3878e-01
,
1.1472e+00
,
1.9726e+00
,
3.0555e+00
,
4.5907e-04
,
1.7928e+00
],
[
-
4.4522e+00
,
-
2.9166e+01
,
-
7.8938e-01
,
2.2841e+00
,
3.8348e+00
,
1.5925e+00
,
1.4721e+00
,
-
7.8371e-03
,
-
8.1931e-03
]])
assert
torch
.
allclose
(
output
[
'gt_bboxes_3d'
].
_data
.
tensor
,
expected_tensor
,
atol
=
1e-3
)
tests/test_semantic_heads.py
View file @
3b7ec493
import
pytest
import
pytest
import
torch
import
torch
from
mmdet3d.core.bbox
import
LiDARInstance3DBoxes
def
test_PointwiseSemanticHead
():
def
test_PointwiseSemanticHead
():
# PointwiseSemanticHead only support gpu version currently.
# PointwiseSemanticHead only support gpu version currently.
...
@@ -47,19 +49,29 @@ def test_PointwiseSemanticHead():
...
@@ -47,19 +49,29 @@ def test_PointwiseSemanticHead():
[
1
,
35
,
930
,
469
]],
[
1
,
35
,
930
,
469
]],
dtype
=
torch
.
int32
).
cuda
()
# n, 4(batch, ind_x, ind_y, ind_z)
dtype
=
torch
.
int32
).
cuda
()
# n, 4(batch, ind_x, ind_y, ind_z)
voxel_dict
=
dict
(
voxel_centers
=
voxel_centers
,
coors
=
coordinates
)
voxel_dict
=
dict
(
voxel_centers
=
voxel_centers
,
coors
=
coordinates
)
gt_bboxes
=
list
(
gt_bboxes
=
[
LiDARInstance3DBoxes
(
torch
.
tensor
(
[[
6.4118
,
-
3.4305
,
-
1.7291
,
1.7033
,
3.4693
,
1.6197
,
-
0.9091
]],
dtype
=
torch
.
float32
).
cuda
()),
LiDARInstance3DBoxes
(
torch
.
tensor
(
torch
.
tensor
(
[[[
6.4118
,
-
3.4305
,
-
1.7291
,
1.7033
,
3.4693
,
1.6197
,
-
0.9091
]],
[[
16.9107
,
9.7925
,
-
1.9201
,
1.6097
,
3.2786
,
1.5307
,
-
2.4056
]],
[[
16.9107
,
9.7925
,
-
1.9201
,
1.6097
,
3.2786
,
1.5307
,
-
2.4056
]]],
dtype
=
torch
.
float32
).
cuda
())
dtype
=
torch
.
float32
).
cuda
())
]
# batch size is 2 in the unit test
gt_labels
=
list
(
torch
.
tensor
([[
0
],
[
1
]],
dtype
=
torch
.
int64
).
cuda
())
gt_labels
=
list
(
torch
.
tensor
([[
0
],
[
1
]],
dtype
=
torch
.
int64
).
cuda
())
# test get_targets
# test get_targets
target_dict
=
self
.
get_targets
(
voxel_dict
,
gt_bboxes
,
gt_labels
)
target_dict
=
self
.
get_targets
(
voxel_dict
,
gt_bboxes
,
gt_labels
)
assert
target_dict
[
'seg_targets'
].
shape
==
torch
.
Size
(
assert
target_dict
[
'seg_targets'
].
shape
==
torch
.
Size
(
[
voxel_features
.
shape
[
0
]])
[
voxel_features
.
shape
[
0
]])
assert
torch
.
allclose
(
target_dict
[
'seg_targets'
],
target_dict
[
'seg_targets'
].
new_tensor
([
3
,
-
1
,
3
,
3
]))
assert
target_dict
[
'part_targets'
].
shape
==
torch
.
Size
(
assert
target_dict
[
'part_targets'
].
shape
==
torch
.
Size
(
[
voxel_features
.
shape
[
0
],
3
])
[
voxel_features
.
shape
[
0
],
3
])
assert
target_dict
[
'part_targets'
].
sum
()
==
0
# test loss
# test loss
loss_dict
=
self
.
loss
(
feats_dict
,
target_dict
)
loss_dict
=
self
.
loss
(
feats_dict
,
target_dict
)
...
@@ -67,7 +79,3 @@ def test_PointwiseSemanticHead():
...
@@ -67,7 +79,3 @@ def test_PointwiseSemanticHead():
assert
loss_dict
[
'loss_part'
]
==
0
# no points in gt_boxes
assert
loss_dict
[
'loss_part'
]
==
0
# no points in gt_boxes
total_loss
=
loss_dict
[
'loss_seg'
]
+
loss_dict
[
'loss_part'
]
total_loss
=
loss_dict
[
'loss_seg'
]
+
loss_dict
[
'loss_part'
]
total_loss
.
backward
()
total_loss
.
backward
()
if
__name__
==
'__main__'
:
test_PointwiseSemanticHead
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment