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
32a4328b
Unverified
Commit
32a4328b
authored
Feb 24, 2022
by
Wenwei Zhang
Committed by
GitHub
Feb 24, 2022
Browse files
Bump version to V1.0.0rc0
Bump version to V1.0.0rc0
parents
86cc487c
a8817998
Changes
414
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
785 additions
and
340 deletions
+785
-340
mmdet3d/core/evaluation/waymo_utils/prediction_kitti_to_waymo.py
.../core/evaluation/waymo_utils/prediction_kitti_to_waymo.py
+4
-3
mmdet3d/core/points/base_points.py
mmdet3d/core/points/base_points.py
+50
-46
mmdet3d/core/points/cam_points.py
mmdet3d/core/points/cam_points.py
+18
-25
mmdet3d/core/points/depth_points.py
mmdet3d/core/points/depth_points.py
+14
-26
mmdet3d/core/points/lidar_points.py
mmdet3d/core/points/lidar_points.py
+14
-26
mmdet3d/core/post_processing/box3d_nms.py
mmdet3d/core/post_processing/box3d_nms.py
+15
-9
mmdet3d/core/utils/__init__.py
mmdet3d/core/utils/__init__.py
+8
-2
mmdet3d/core/utils/array_converter.py
mmdet3d/core/utils/array_converter.py
+324
-0
mmdet3d/core/utils/gaussian.py
mmdet3d/core/utils/gaussian.py
+76
-4
mmdet3d/core/visualizer/image_vis.py
mmdet3d/core/visualizer/image_vis.py
+14
-6
mmdet3d/core/visualizer/open3d_vis.py
mmdet3d/core/visualizer/open3d_vis.py
+83
-66
mmdet3d/core/visualizer/show_result.py
mmdet3d/core/visualizer/show_result.py
+19
-18
mmdet3d/core/voxel/voxel_generator.py
mmdet3d/core/voxel/voxel_generator.py
+20
-20
mmdet3d/datasets/__init__.py
mmdet3d/datasets/__init__.py
+9
-7
mmdet3d/datasets/builder.py
mmdet3d/datasets/builder.py
+1
-0
mmdet3d/datasets/custom_3d.py
mmdet3d/datasets/custom_3d.py
+16
-12
mmdet3d/datasets/custom_3d_seg.py
mmdet3d/datasets/custom_3d_seg.py
+12
-11
mmdet3d/datasets/kitti2d_dataset.py
mmdet3d/datasets/kitti2d_dataset.py
+3
-2
mmdet3d/datasets/kitti_dataset.py
mmdet3d/datasets/kitti_dataset.py
+56
-33
mmdet3d/datasets/kitti_mono_dataset.py
mmdet3d/datasets/kitti_mono_dataset.py
+29
-24
No files found.
mmdet3d/core/evaluation/waymo_utils/prediction_kitti_to_waymo.py
View file @
32a4328b
...
...
@@ -10,11 +10,12 @@ except ImportError:
'Please run "pip install waymo-open-dataset-tf-2-1-0==1.2.0" '
'to install the official devkit first.'
)
from
glob
import
glob
from
os.path
import
join
import
mmcv
import
numpy
as
np
import
tensorflow
as
tf
from
glob
import
glob
from
os.path
import
join
from
waymo_open_dataset
import
label_pb2
from
waymo_open_dataset.protos
import
metrics_pb2
...
...
@@ -114,7 +115,7 @@ class KITTI2Waymo(object):
instance_idx (int): Index of the instance to be converted.
Returns:
:obj:`Object`: Predicted instance in waymo dataset
\
:obj:`Object`: Predicted instance in waymo dataset
Object proto.
"""
cls
=
kitti_result
[
'name'
][
instance_idx
]
...
...
mmdet3d/core/points/base_points.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
numpy
as
np
import
torch
import
warnings
from
abc
import
abstractmethod
import
numpy
as
np
import
torch
from
..bbox.structures.utils
import
rotation_3d_in_axis
class
BasePoints
(
object
):
"""Base class for Points.
Args:
tensor (torch.Tensor | np.ndarray | list): a N x points_dim matrix.
points_dim (int): Number of the dimension of a point.
Each row is (x, y, z). Default to 3.
attribute_dims (dict): Dictionary to indicate the
meaning of extra
dimension. Default to None.
points_dim (int
, optional
): Number of the dimension of a point.
Each row is (x, y, z). Default
s
to 3.
attribute_dims (dict
, optional
): Dictionary to indicate the
meaning of extra
dimension. Default
s
to None.
Attributes:
tensor (torch.Tensor): Float matrix of N x points_dim.
points_dim (int): Integer indicating the dimension of a point.
Each row is (x, y, z, ...).
attribute_dims (bool): Dictionary to indicate the meaning of extra
dimension. Default to None.
dimension. Default
s
to None.
rotation_axis (int): Default rotation axis for points rotation.
"""
...
...
@@ -45,7 +48,7 @@ class BasePoints(object):
@
property
def
coord
(
self
):
"""torch.Tensor: Coordinates of each point
with siz
e (N, 3)."""
"""torch.Tensor: Coordinates of each point
in shap
e (N, 3)."""
return
self
.
tensor
[:,
:
3
]
@
coord
.
setter
...
...
@@ -61,7 +64,8 @@ class BasePoints(object):
@
property
def
height
(
self
):
"""torch.Tensor: A vector with height of each point."""
"""torch.Tensor:
A vector with height of each point in shape (N, 1), or None."""
if
self
.
attribute_dims
is
not
None
and
\
'height'
in
self
.
attribute_dims
.
keys
():
return
self
.
tensor
[:,
self
.
attribute_dims
[
'height'
]]
...
...
@@ -91,7 +95,8 @@ class BasePoints(object):
@
property
def
color
(
self
):
"""torch.Tensor: A vector with color of each point."""
"""torch.Tensor:
A vector with color of each point in shape (N, 3), or None."""
if
self
.
attribute_dims
is
not
None
and
\
'color'
in
self
.
attribute_dims
.
keys
():
return
self
.
tensor
[:,
self
.
attribute_dims
[
'color'
]]
...
...
@@ -141,9 +146,9 @@ class BasePoints(object):
"""Rotate points with the given rotation matrix or angle.
Args:
rotation (float
,
np.ndarray
,
torch.Tensor): Rotation matrix
rotation (float
|
np.ndarray
|
torch.Tensor): Rotation matrix
or angle.
axis (int): Axis to rotate at. Defaults to None.
axis (int
, optional
): Axis to rotate at. Defaults to None.
"""
if
not
isinstance
(
rotation
,
torch
.
Tensor
):
rotation
=
self
.
tensor
.
new_tensor
(
rotation
)
...
...
@@ -154,34 +159,24 @@ class BasePoints(object):
axis
=
self
.
rotation_axis
if
rotation
.
numel
()
==
1
:
rot_sin
=
torch
.
sin
(
rotation
)
rot_cos
=
torch
.
cos
(
rotation
)
if
axis
==
1
:
rot_mat_T
=
rotation
.
new_tensor
([[
rot_cos
,
0
,
-
rot_sin
],
[
0
,
1
,
0
],
[
rot_sin
,
0
,
rot_cos
]])
elif
axis
==
2
or
axis
==
-
1
:
rot_mat_T
=
rotation
.
new_tensor
([[
rot_cos
,
-
rot_sin
,
0
],
[
rot_sin
,
rot_cos
,
0
],
[
0
,
0
,
1
]])
elif
axis
==
0
:
rot_mat_T
=
rotation
.
new_tensor
([[
1
,
0
,
0
],
[
0
,
rot_cos
,
-
rot_sin
],
[
0
,
rot_sin
,
rot_cos
]])
else
:
raise
ValueError
(
'axis should in range'
)
rot_mat_T
=
rot_mat_T
.
T
elif
rotation
.
numel
()
==
9
:
rot_mat_T
=
rotation
rotated_points
,
rot_mat_T
=
rotation_3d_in_axis
(
self
.
tensor
[:,
:
3
][
None
],
rotation
,
axis
=
axis
,
return_mat
=
True
)
self
.
tensor
[:,
:
3
]
=
rotated_points
.
squeeze
(
0
)
rot_mat_T
=
rot_mat_T
.
squeeze
(
0
)
else
:
raise
NotImplementedError
self
.
tensor
[:,
:
3
]
=
self
.
tensor
[:,
:
3
]
@
rot_mat_T
# rotation.numel() == 9
self
.
tensor
[:,
:
3
]
=
self
.
tensor
[:,
:
3
]
@
rotation
rot_mat_T
=
rotation
return
rot_mat_T
@
abstractmethod
def
flip
(
self
,
bev_direction
=
'horizontal'
):
"""Flip the points in BEV along given BEV direction."""
"""Flip the points along given BEV direction.
Args:
bev_direction (str): Flip direction (horizontal or vertical).
"""
pass
def
translate
(
self
,
trans_vector
):
...
...
@@ -218,7 +213,7 @@ class BasePoints(object):
polygon, we try to reduce the burden for simpler cases.
Returns:
torch.Tensor: A binary vector indicating whether each point is
\
torch.Tensor: A binary vector indicating whether each point is
inside the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
point_range
[
0
])
...
...
@@ -229,7 +224,11 @@ class BasePoints(object):
&
(
self
.
tensor
[:,
2
]
<
point_range
[
5
]))
return
in_range_flags
@
abstractmethod
@
property
def
bev
(
self
):
"""torch.Tensor: BEV of the points in shape (N, 2)."""
return
self
.
tensor
[:,
[
0
,
1
]]
def
in_range_bev
(
self
,
point_range
):
"""Check whether the points are in the given range.
...
...
@@ -238,10 +237,14 @@ class BasePoints(object):
in order of (x_min, y_min, x_max, y_max).
Returns:
torch.Tensor: Indicating whether each point is inside
\
torch.Tensor: Indicating whether each point is inside
the reference range.
"""
pass
in_range_flags
=
((
self
.
bev
[:,
0
]
>
point_range
[
0
])
&
(
self
.
bev
[:,
1
]
>
point_range
[
1
])
&
(
self
.
bev
[:,
1
]
<
point_range
[
2
])
&
(
self
.
bev
[:,
1
]
<
point_range
[
3
]))
return
in_range_flags
@
abstractmethod
def
convert_to
(
self
,
dst
,
rt_mat
=
None
):
...
...
@@ -249,14 +252,15 @@ class BasePoints(object):
Args:
dst (:obj:`CoordMode`): The target Box mode.
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
rt_mat (np.ndarray | torch.Tensor, optional): The rotation and
translation matrix between different coordinates.
Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BasePoints`: The converted box of the same type
\
:obj:`BasePoints`: The converted box of the same type
in the `dst` mode.
"""
pass
...
...
@@ -288,7 +292,7 @@ class BasePoints(object):
subject to Pytorch's indexing semantics.
Returns:
:obj:`BasePoints`: A new object of
\
:obj:`BasePoints`: A new object of
:class:`BasePoints` after indexing.
"""
original_type
=
type
(
self
)
...
...
@@ -379,7 +383,7 @@ class BasePoints(object):
device (str | :obj:`torch.device`): The name of the device.
Returns:
:obj:`BasePoints`: A new boxes object on the
\
:obj:`BasePoints`: A new boxes object on the
specific device.
"""
original_type
=
type
(
self
)
...
...
@@ -392,7 +396,7 @@ class BasePoints(object):
"""Clone the Points.
Returns:
:obj:`BasePoints`: Box object with the same properties
\
:obj:`BasePoints`: Box object with the same properties
as self.
"""
original_type
=
type
(
self
)
...
...
@@ -417,14 +421,14 @@ class BasePoints(object):
def
new_point
(
self
,
data
):
"""Create a new point object with data.
The new point and its tensor has the similar properties
\
The new point and its tensor has the similar properties
as self and self.tensor, respectively.
Args:
data (torch.Tensor | numpy.array | list): Data to be copied.
Returns:
:obj:`BasePoints`: A new point object with ``data``,
\
:obj:`BasePoints`: A new point object with ``data``,
the object's other properties are similar to ``self``.
"""
new_tensor
=
self
.
tensor
.
new_tensor
(
data
)
\
...
...
mmdet3d/core/points/cam_points.py
View file @
32a4328b
...
...
@@ -7,17 +7,17 @@ class CameraPoints(BasePoints):
Args:
tensor (torch.Tensor | np.ndarray | list): a N x points_dim matrix.
points_dim (int): Number of the dimension of a point.
Each row is (x, y, z). Default to 3.
attribute_dims (dict): Dictionary to indicate the
meaning of extra
dimension. Default to None.
points_dim (int
, optional
): Number of the dimension of a point.
Each row is (x, y, z). Default
s
to 3.
attribute_dims (dict
, optional
): Dictionary to indicate the
meaning of extra
dimension. Default
s
to None.
Attributes:
tensor (torch.Tensor): Float matrix of N x points_dim.
points_dim (int): Integer indicating the dimension of a point.
Each row is (x, y, z, ...).
attribute_dims (bool): Dictionary to indicate the meaning of extra
dimension. Default to None.
dimension. Default
s
to None.
rotation_axis (int): Default rotation axis for points rotation.
"""
...
...
@@ -27,42 +27,35 @@ class CameraPoints(BasePoints):
self
.
rotation_axis
=
1
def
flip
(
self
,
bev_direction
=
'horizontal'
):
"""Flip the boxes in BEV along given BEV direction."""
"""Flip the points along given BEV direction.
Args:
bev_direction (str): Flip direction (horizontal or vertical).
"""
if
bev_direction
==
'horizontal'
:
self
.
tensor
[:,
0
]
=
-
self
.
tensor
[:,
0
]
elif
bev_direction
==
'vertical'
:
self
.
tensor
[:,
2
]
=
-
self
.
tensor
[:,
2
]
def
in_range_bev
(
self
,
point_range
):
"""Check whether the points are in the given range.
Args:
point_range (list | torch.Tensor): The range of point
in order of (x_min, y_min, x_max, y_max).
Returns:
torch.Tensor: Indicating whether each point is inside
\
the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
point_range
[
0
])
&
(
self
.
tensor
[:,
2
]
>
point_range
[
1
])
&
(
self
.
tensor
[:,
0
]
<
point_range
[
2
])
&
(
self
.
tensor
[:,
2
]
<
point_range
[
3
]))
return
in_range_flags
@
property
def
bev
(
self
):
"""torch.Tensor: BEV of the points in shape (N, 2)."""
return
self
.
tensor
[:,
[
0
,
2
]]
def
convert_to
(
self
,
dst
,
rt_mat
=
None
):
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`CoordMode`): The target Point mode.
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
rt_mat (np.ndarray | torch.Tensor, optional): The rotation and
translation matrix between different coordinates.
Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BasePoints`: The converted point of the same type
\
:obj:`BasePoints`: The converted point of the same type
in the `dst` mode.
"""
from
mmdet3d.core.bbox
import
Coord3DMode
...
...
mmdet3d/core/points/depth_points.py
View file @
32a4328b
...
...
@@ -7,17 +7,17 @@ class DepthPoints(BasePoints):
Args:
tensor (torch.Tensor | np.ndarray | list): a N x points_dim matrix.
points_dim (int): Number of the dimension of a point.
Each row is (x, y, z). Default to 3.
attribute_dims (dict): Dictionary to indicate the
meaning of extra
dimension. Default to None.
points_dim (int
, optional
): Number of the dimension of a point.
Each row is (x, y, z). Default
s
to 3.
attribute_dims (dict
, optional
): Dictionary to indicate the
meaning of extra
dimension. Default
s
to None.
Attributes:
tensor (torch.Tensor): Float matrix of N x points_dim.
points_dim (int): Integer indicating the dimension of a point.
Each row is (x, y, z, ...).
attribute_dims (bool): Dictionary to indicate the meaning of extra
dimension. Default to None.
dimension. Default
s
to None.
rotation_axis (int): Default rotation axis for points rotation.
"""
...
...
@@ -27,42 +27,30 @@ class DepthPoints(BasePoints):
self
.
rotation_axis
=
2
def
flip
(
self
,
bev_direction
=
'horizontal'
):
"""Flip the boxes in BEV along given BEV direction."""
"""Flip the points along given BEV direction.
Args:
bev_direction (str): Flip direction (horizontal or vertical).
"""
if
bev_direction
==
'horizontal'
:
self
.
tensor
[:,
0
]
=
-
self
.
tensor
[:,
0
]
elif
bev_direction
==
'vertical'
:
self
.
tensor
[:,
1
]
=
-
self
.
tensor
[:,
1
]
def
in_range_bev
(
self
,
point_range
):
"""Check whether the points are in the given range.
Args:
point_range (list | torch.Tensor): The range of point
in order of (x_min, y_min, x_max, y_max).
Returns:
torch.Tensor: Indicating whether each point is inside
\
the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
point_range
[
0
])
&
(
self
.
tensor
[:,
1
]
>
point_range
[
1
])
&
(
self
.
tensor
[:,
0
]
<
point_range
[
2
])
&
(
self
.
tensor
[:,
1
]
<
point_range
[
3
]))
return
in_range_flags
def
convert_to
(
self
,
dst
,
rt_mat
=
None
):
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`CoordMode`): The target Point mode.
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
rt_mat (np.ndarray | torch.Tensor, optional): The rotation and
translation matrix between different coordinates.
Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BasePoints`: The converted point of the same type
\
:obj:`BasePoints`: The converted point of the same type
in the `dst` mode.
"""
from
mmdet3d.core.bbox
import
Coord3DMode
...
...
mmdet3d/core/points/lidar_points.py
View file @
32a4328b
...
...
@@ -7,17 +7,17 @@ class LiDARPoints(BasePoints):
Args:
tensor (torch.Tensor | np.ndarray | list): a N x points_dim matrix.
points_dim (int): Number of the dimension of a point.
Each row is (x, y, z). Default to 3.
attribute_dims (dict): Dictionary to indicate the
meaning of extra
dimension. Default to None.
points_dim (int
, optional
): Number of the dimension of a point.
Each row is (x, y, z). Default
s
to 3.
attribute_dims (dict
, optional
): Dictionary to indicate the
meaning of extra
dimension. Default
s
to None.
Attributes:
tensor (torch.Tensor): Float matrix of N x points_dim.
points_dim (int): Integer indicating the dimension of a point.
Each row is (x, y, z, ...).
attribute_dims (bool): Dictionary to indicate the meaning of extra
dimension. Default to None.
dimension. Default
s
to None.
rotation_axis (int): Default rotation axis for points rotation.
"""
...
...
@@ -27,42 +27,30 @@ class LiDARPoints(BasePoints):
self
.
rotation_axis
=
2
def
flip
(
self
,
bev_direction
=
'horizontal'
):
"""Flip the boxes in BEV along given BEV direction."""
"""Flip the points along given BEV direction.
Args:
bev_direction (str): Flip direction (horizontal or vertical).
"""
if
bev_direction
==
'horizontal'
:
self
.
tensor
[:,
1
]
=
-
self
.
tensor
[:,
1
]
elif
bev_direction
==
'vertical'
:
self
.
tensor
[:,
0
]
=
-
self
.
tensor
[:,
0
]
def
in_range_bev
(
self
,
point_range
):
"""Check whether the points are in the given range.
Args:
point_range (list | torch.Tensor): The range of point
in order of (x_min, y_min, x_max, y_max).
Returns:
torch.Tensor: Indicating whether each point is inside
\
the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
point_range
[
0
])
&
(
self
.
tensor
[:,
1
]
>
point_range
[
1
])
&
(
self
.
tensor
[:,
0
]
<
point_range
[
2
])
&
(
self
.
tensor
[:,
1
]
<
point_range
[
3
]))
return
in_range_flags
def
convert_to
(
self
,
dst
,
rt_mat
=
None
):
"""Convert self to ``dst`` mode.
Args:
dst (:obj:`CoordMode`): The target Point mode.
rt_mat (np.ndarray | torch.Tensor): The rotation and translation
matrix between different coordinates. Defaults to None.
rt_mat (np.ndarray | torch.Tensor, optional): The rotation and
translation matrix between different coordinates.
Defaults to None.
The conversion from `src` coordinates to `dst` coordinates
usually comes along the change of sensors, e.g., from camera
to LiDAR. This requires a transformation matrix.
Returns:
:obj:`BasePoints`: The converted point of the same type
\
:obj:`BasePoints`: The converted point of the same type
in the `dst` mode.
"""
from
mmdet3d.core.bbox
import
Coord3DMode
...
...
mmdet3d/core/post_processing/box3d_nms.py
View file @
32a4328b
...
...
@@ -15,16 +15,18 @@ def box3d_multiclass_nms(mlvl_bboxes,
mlvl_dir_scores
=
None
,
mlvl_attr_scores
=
None
,
mlvl_bboxes2d
=
None
):
"""Multi-class nms for 3D boxes.
"""Multi-class NMS for 3D boxes. The IoU used for NMS is defined as the 2D
IoU between BEV boxes.
Args:
mlvl_bboxes (torch.Tensor): Multi-level boxes with shape (N, M).
M is the dimensions of boxes.
mlvl_bboxes_for_nms (torch.Tensor): Multi-level boxes with shape
(N, 5) ([x1, y1, x2, y2, ry]). N is the number of boxes.
The coordinate system of the BEV boxes is counterclockwise.
mlvl_scores (torch.Tensor): Multi-level boxes with shape
(N, C + 1). N is the number of boxes. C is the number of classes.
score_thr (float): Score thre
d
hold to filter boxes with low
score_thr (float): Score thre
s
hold to filter boxes with low
confidence.
max_num (int): Maximum number of boxes will be kept.
cfg (dict): Configuration dict of NMS.
...
...
@@ -36,8 +38,8 @@ def box3d_multiclass_nms(mlvl_bboxes,
boxes. Defaults to None.
Returns:
tuple[torch.Tensor]: Return results after nms, including 3D
\
bounding boxes, scores, labels, direction scores, attribute
\
tuple[torch.Tensor]: Return results after nms, including 3D
bounding boxes, scores, labels, direction scores, attribute
scores (optional) and 2D bounding boxes (optional).
"""
# do multi class nms
...
...
@@ -128,13 +130,13 @@ def box3d_multiclass_nms(mlvl_bboxes,
def
aligned_3d_nms
(
boxes
,
scores
,
classes
,
thresh
):
"""3
d nms
for aligned boxes.
"""3
D NMS
for aligned boxes.
Args:
boxes (torch.Tensor): Aligned box with shape [n, 6].
scores (torch.Tensor): Scores of each box.
classes (torch.Tensor): Class of each box.
thresh (float): Io
u
threshold for nms.
thresh (float): Io
U
threshold for nms.
Returns:
torch.Tensor: Indices of selected boxes.
...
...
@@ -188,8 +190,8 @@ def circle_nms(dets, thresh, post_max_size=83):
Args:
dets (torch.Tensor): Detection results with the shape of [N, 3].
thresh (float): Value of threshold.
post_max_size (int): Max number of prediction to be kept.
Defaults
to 83
post_max_size (int
, optional
): Max number of prediction to be kept.
Defaults
to 83
.
Returns:
torch.Tensor: Indexes of the detections to be kept.
...
...
@@ -217,4 +219,8 @@ def circle_nms(dets, thresh, post_max_size=83):
# ovr = inter / areas[j]
if
dist
<=
thresh
:
suppressed
[
j
]
=
1
return
keep
[:
post_max_size
]
if
post_max_size
<
len
(
keep
):
return
keep
[:
post_max_size
]
return
keep
mmdet3d/core/utils/__init__.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
from
.gaussian
import
draw_heatmap_gaussian
,
gaussian_2d
,
gaussian_radius
from
.array_converter
import
ArrayConverter
,
array_converter
from
.gaussian
import
(
draw_heatmap_gaussian
,
ellip_gaussian2D
,
gaussian_2d
,
gaussian_radius
,
get_ellip_gaussian_2D
)
__all__
=
[
'gaussian_2d'
,
'gaussian_radius'
,
'draw_heatmap_gaussian'
]
__all__
=
[
'gaussian_2d'
,
'gaussian_radius'
,
'draw_heatmap_gaussian'
,
'ArrayConverter'
,
'array_converter'
,
'ellip_gaussian2D'
,
'get_ellip_gaussian_2D'
]
mmdet3d/core/utils/array_converter.py
0 → 100644
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
functools
from
inspect
import
getfullargspec
import
numpy
as
np
import
torch
def
array_converter
(
to_torch
=
True
,
apply_to
=
tuple
(),
template_arg_name_
=
None
,
recover
=
True
):
"""Wrapper function for data-type agnostic processing.
First converts input arrays to PyTorch tensors or NumPy ndarrays
for middle calculation, then convert output to original data-type if
`recover=True`.
Args:
to_torch (Bool, optional): Whether convert to PyTorch tensors
for middle calculation. Defaults to True.
apply_to (tuple[str], optional): The arguments to which we apply
data-type conversion. Defaults to an empty tuple.
template_arg_name_ (str, optional): Argument serving as the template (
return arrays should have the same dtype and device
as the template). Defaults to None. If None, we will use the
first argument in `apply_to` as the template argument.
recover (Bool, optional): Whether or not recover the wrapped function
outputs to the `template_arg_name_` type. Defaults to True.
Raises:
ValueError: When template_arg_name_ is not among all args, or
when apply_to contains an arg which is not among all args,
a ValueError will be raised. When the template argument or
an argument to convert is a list or tuple, and cannot be
converted to a NumPy array, a ValueError will be raised.
TypeError: When the type of the template argument or
an argument to convert does not belong to the above range,
or the contents of such an list-or-tuple-type argument
do not share the same data type, a TypeError is raised.
Returns:
(function): wrapped function.
Example:
>>> import torch
>>> import numpy as np
>>>
>>> # Use torch addition for a + b,
>>> # and convert return values to the type of a
>>> @array_converter(apply_to=('a', 'b'))
>>> def simple_add(a, b):
>>> return a + b
>>>
>>> a = np.array([1.1])
>>> b = np.array([2.2])
>>> simple_add(a, b)
>>>
>>> # Use numpy addition for a + b,
>>> # and convert return values to the type of b
>>> @array_converter(to_torch=False, apply_to=('a', 'b'),
>>> template_arg_name_='b')
>>> def simple_add(a, b):
>>> return a + b
>>>
>>> simple_add()
>>>
>>> # Use torch funcs for floor(a) if flag=True else ceil(a),
>>> # and return the torch tensor
>>> @array_converter(apply_to=('a',), recover=False)
>>> def floor_or_ceil(a, flag=True):
>>> return torch.floor(a) if flag else torch.ceil(a)
>>>
>>> floor_or_ceil(a, flag=False)
"""
def
array_converter_wrapper
(
func
):
"""Outer wrapper for the function."""
@
functools
.
wraps
(
func
)
def
new_func
(
*
args
,
**
kwargs
):
"""Inner wrapper for the arguments."""
if
len
(
apply_to
)
==
0
:
return
func
(
*
args
,
**
kwargs
)
func_name
=
func
.
__name__
arg_spec
=
getfullargspec
(
func
)
arg_names
=
arg_spec
.
args
arg_num
=
len
(
arg_names
)
default_arg_values
=
arg_spec
.
defaults
if
default_arg_values
is
None
:
default_arg_values
=
[]
no_default_arg_num
=
len
(
arg_names
)
-
len
(
default_arg_values
)
kwonly_arg_names
=
arg_spec
.
kwonlyargs
kwonly_default_arg_values
=
arg_spec
.
kwonlydefaults
if
kwonly_default_arg_values
is
None
:
kwonly_default_arg_values
=
{}
all_arg_names
=
arg_names
+
kwonly_arg_names
# in case there are args in the form of *args
if
len
(
args
)
>
arg_num
:
named_args
=
args
[:
arg_num
]
nameless_args
=
args
[
arg_num
:]
else
:
named_args
=
args
nameless_args
=
[]
# template argument data type is used for all array-like arguments
if
template_arg_name_
is
None
:
template_arg_name
=
apply_to
[
0
]
else
:
template_arg_name
=
template_arg_name_
if
template_arg_name
not
in
all_arg_names
:
raise
ValueError
(
f
'
{
template_arg_name
}
is not among the '
f
'argument list of function
{
func_name
}
'
)
# inspect apply_to
for
arg_to_apply
in
apply_to
:
if
arg_to_apply
not
in
all_arg_names
:
raise
ValueError
(
f
'
{
arg_to_apply
}
is not '
f
'an argument of
{
func_name
}
'
)
new_args
=
[]
new_kwargs
=
{}
converter
=
ArrayConverter
()
target_type
=
torch
.
Tensor
if
to_torch
else
np
.
ndarray
# non-keyword arguments
for
i
,
arg_value
in
enumerate
(
named_args
):
if
arg_names
[
i
]
in
apply_to
:
new_args
.
append
(
converter
.
convert
(
input_array
=
arg_value
,
target_type
=
target_type
))
else
:
new_args
.
append
(
arg_value
)
if
arg_names
[
i
]
==
template_arg_name
:
template_arg_value
=
arg_value
kwonly_default_arg_values
.
update
(
kwargs
)
kwargs
=
kwonly_default_arg_values
# keyword arguments and non-keyword arguments using default value
for
i
in
range
(
len
(
named_args
),
len
(
all_arg_names
)):
arg_name
=
all_arg_names
[
i
]
if
arg_name
in
kwargs
:
if
arg_name
in
apply_to
:
new_kwargs
[
arg_name
]
=
converter
.
convert
(
input_array
=
kwargs
[
arg_name
],
target_type
=
target_type
)
else
:
new_kwargs
[
arg_name
]
=
kwargs
[
arg_name
]
else
:
default_value
=
default_arg_values
[
i
-
no_default_arg_num
]
if
arg_name
in
apply_to
:
new_kwargs
[
arg_name
]
=
converter
.
convert
(
input_array
=
default_value
,
target_type
=
target_type
)
else
:
new_kwargs
[
arg_name
]
=
default_value
if
arg_name
==
template_arg_name
:
template_arg_value
=
kwargs
[
arg_name
]
# add nameless args provided by *args (if exists)
new_args
+=
nameless_args
return_values
=
func
(
*
new_args
,
**
new_kwargs
)
converter
.
set_template
(
template_arg_value
)
def
recursive_recover
(
input_data
):
if
isinstance
(
input_data
,
(
tuple
,
list
)):
new_data
=
[]
for
item
in
input_data
:
new_data
.
append
(
recursive_recover
(
item
))
return
tuple
(
new_data
)
if
isinstance
(
input_data
,
tuple
)
else
new_data
elif
isinstance
(
input_data
,
dict
):
new_data
=
{}
for
k
,
v
in
input_data
.
items
():
new_data
[
k
]
=
recursive_recover
(
v
)
return
new_data
elif
isinstance
(
input_data
,
(
torch
.
Tensor
,
np
.
ndarray
)):
return
converter
.
recover
(
input_data
)
else
:
return
input_data
if
recover
:
return
recursive_recover
(
return_values
)
else
:
return
return_values
return
new_func
return
array_converter_wrapper
class
ArrayConverter
:
SUPPORTED_NON_ARRAY_TYPES
=
(
int
,
float
,
np
.
int8
,
np
.
int16
,
np
.
int32
,
np
.
int64
,
np
.
uint8
,
np
.
uint16
,
np
.
uint32
,
np
.
uint64
,
np
.
float16
,
np
.
float32
,
np
.
float64
)
def
__init__
(
self
,
template_array
=
None
):
if
template_array
is
not
None
:
self
.
set_template
(
template_array
)
def
set_template
(
self
,
array
):
"""Set template array.
Args:
array (tuple | list | int | float | np.ndarray | torch.Tensor):
Template array.
Raises:
ValueError: If input is list or tuple and cannot be converted to
to a NumPy array, a ValueError is raised.
TypeError: If input type does not belong to the above range,
or the contents of a list or tuple do not share the
same data type, a TypeError is raised.
"""
self
.
array_type
=
type
(
array
)
self
.
is_num
=
False
self
.
device
=
'cpu'
if
isinstance
(
array
,
np
.
ndarray
):
self
.
dtype
=
array
.
dtype
elif
isinstance
(
array
,
torch
.
Tensor
):
self
.
dtype
=
array
.
dtype
self
.
device
=
array
.
device
elif
isinstance
(
array
,
(
list
,
tuple
)):
try
:
array
=
np
.
array
(
array
)
if
array
.
dtype
not
in
self
.
SUPPORTED_NON_ARRAY_TYPES
:
raise
TypeError
self
.
dtype
=
array
.
dtype
except
(
ValueError
,
TypeError
):
print
(
f
'The following list cannot be converted to'
f
' a numpy array of supported dtype:
\n
{
array
}
'
)
raise
elif
isinstance
(
array
,
self
.
SUPPORTED_NON_ARRAY_TYPES
):
self
.
array_type
=
np
.
ndarray
self
.
is_num
=
True
self
.
dtype
=
np
.
dtype
(
type
(
array
))
else
:
raise
TypeError
(
f
'Template type
{
self
.
array_type
}
'
f
' is not supported.'
)
def
convert
(
self
,
input_array
,
target_type
=
None
,
target_array
=
None
):
"""Convert input array to target data type.
Args:
input_array (tuple | list | np.ndarray |
torch.Tensor | int | float ):
Input array. Defaults to None.
target_type (<class 'np.ndarray'> | <class 'torch.Tensor'>,
optional):
Type to which input array is converted. Defaults to None.
target_array (np.ndarray | torch.Tensor, optional):
Template array to which input array is converted.
Defaults to None.
Raises:
ValueError: If input is list or tuple and cannot be converted to
to a NumPy array, a ValueError is raised.
TypeError: If input type does not belong to the above range,
or the contents of a list or tuple do not share the
same data type, a TypeError is raised.
"""
if
isinstance
(
input_array
,
(
list
,
tuple
)):
try
:
input_array
=
np
.
array
(
input_array
)
if
input_array
.
dtype
not
in
self
.
SUPPORTED_NON_ARRAY_TYPES
:
raise
TypeError
except
(
ValueError
,
TypeError
):
print
(
f
'The input cannot be converted to'
f
' a single-type numpy array:
\n
{
input_array
}
'
)
raise
elif
isinstance
(
input_array
,
self
.
SUPPORTED_NON_ARRAY_TYPES
):
input_array
=
np
.
array
(
input_array
)
array_type
=
type
(
input_array
)
assert
target_type
is
not
None
or
target_array
is
not
None
,
\
'must specify a target'
if
target_type
is
not
None
:
assert
target_type
in
(
np
.
ndarray
,
torch
.
Tensor
),
\
'invalid target type'
if
target_type
==
array_type
:
return
input_array
elif
target_type
==
np
.
ndarray
:
# default dtype is float32
converted_array
=
input_array
.
cpu
().
numpy
().
astype
(
np
.
float32
)
else
:
# default dtype is float32, device is 'cpu'
converted_array
=
torch
.
tensor
(
input_array
,
dtype
=
torch
.
float32
)
else
:
assert
isinstance
(
target_array
,
(
np
.
ndarray
,
torch
.
Tensor
)),
\
'invalid target array type'
if
isinstance
(
target_array
,
array_type
):
return
input_array
elif
isinstance
(
target_array
,
np
.
ndarray
):
converted_array
=
input_array
.
cpu
().
numpy
().
astype
(
target_array
.
dtype
)
else
:
converted_array
=
target_array
.
new_tensor
(
input_array
)
return
converted_array
def
recover
(
self
,
input_array
):
assert
isinstance
(
input_array
,
(
np
.
ndarray
,
torch
.
Tensor
)),
\
'invalid input array type'
if
isinstance
(
input_array
,
self
.
array_type
):
return
input_array
elif
isinstance
(
input_array
,
torch
.
Tensor
):
converted_array
=
input_array
.
cpu
().
numpy
().
astype
(
self
.
dtype
)
else
:
converted_array
=
torch
.
tensor
(
input_array
,
dtype
=
self
.
dtype
,
device
=
self
.
device
)
if
self
.
is_num
:
converted_array
=
converted_array
.
item
()
return
converted_array
mmdet3d/core/utils/gaussian.py
View file @
32a4328b
...
...
@@ -8,7 +8,7 @@ def gaussian_2d(shape, sigma=1):
Args:
shape (list[int]): Shape of the map.
sigma (float): Sigma to generate gaussian map.
sigma (float
, optional
): Sigma to generate gaussian map.
Defaults to 1.
Returns:
...
...
@@ -28,8 +28,8 @@ def draw_heatmap_gaussian(heatmap, center, radius, k=1):
Args:
heatmap (torch.Tensor): Heatmap to be masked.
center (torch.Tensor): Center coord of the heatmap.
radius (int): Radius of gausian.
K (int): Multiple of masked_gaussian. Defaults to 1.
radius (int): Radius of gaus
s
ian.
K (int
, optional
): Multiple of masked_gaussian. Defaults to 1.
Returns:
torch.Tensor: Masked heatmap.
...
...
@@ -59,7 +59,7 @@ def gaussian_radius(det_size, min_overlap=0.5):
Args:
det_size (tuple[torch.Tensor]): Size of the detection result.
min_overlap (float): Gaussian_overlap. Defaults to 0.5.
min_overlap (float
, optional
): Gaussian_overlap. Defaults to 0.5.
Returns:
torch.Tensor: Computed radius.
...
...
@@ -84,3 +84,75 @@ def gaussian_radius(det_size, min_overlap=0.5):
sq3
=
torch
.
sqrt
(
b3
**
2
-
4
*
a3
*
c3
)
r3
=
(
b3
+
sq3
)
/
2
return
min
(
r1
,
r2
,
r3
)
def
get_ellip_gaussian_2D
(
heatmap
,
center
,
radius_x
,
radius_y
,
k
=
1
):
"""Generate 2D ellipse gaussian heatmap.
Args:
heatmap (Tensor): Input heatmap, the gaussian kernel will cover on
it and maintain the max value.
center (list[int]): Coord of gaussian kernel's center.
radius_x (int): X-axis radius of gaussian kernel.
radius_y (int): Y-axis radius of gaussian kernel.
k (int, optional): Coefficient of gaussian kernel. Default: 1.
Returns:
out_heatmap (Tensor): Updated heatmap covered by gaussian kernel.
"""
diameter_x
,
diameter_y
=
2
*
radius_x
+
1
,
2
*
radius_y
+
1
gaussian_kernel
=
ellip_gaussian2D
((
radius_x
,
radius_y
),
sigma_x
=
diameter_x
/
6
,
sigma_y
=
diameter_y
/
6
,
dtype
=
heatmap
.
dtype
,
device
=
heatmap
.
device
)
x
,
y
=
int
(
center
[
0
]),
int
(
center
[
1
])
height
,
width
=
heatmap
.
shape
[
0
:
2
]
left
,
right
=
min
(
x
,
radius_x
),
min
(
width
-
x
,
radius_x
+
1
)
top
,
bottom
=
min
(
y
,
radius_y
),
min
(
height
-
y
,
radius_y
+
1
)
masked_heatmap
=
heatmap
[
y
-
top
:
y
+
bottom
,
x
-
left
:
x
+
right
]
masked_gaussian
=
gaussian_kernel
[
radius_y
-
top
:
radius_y
+
bottom
,
radius_x
-
left
:
radius_x
+
right
]
out_heatmap
=
heatmap
torch
.
max
(
masked_heatmap
,
masked_gaussian
*
k
,
out
=
out_heatmap
[
y
-
top
:
y
+
bottom
,
x
-
left
:
x
+
right
])
return
out_heatmap
def
ellip_gaussian2D
(
radius
,
sigma_x
,
sigma_y
,
dtype
=
torch
.
float32
,
device
=
'cpu'
):
"""Generate 2D ellipse gaussian kernel.
Args:
radius (tuple(int)): Ellipse radius (radius_x, radius_y) of gaussian
kernel.
sigma_x (int): X-axis sigma of gaussian function.
sigma_y (int): Y-axis sigma of gaussian function.
dtype (torch.dtype, optional): Dtype of gaussian tensor.
Default: torch.float32.
device (str, optional): Device of gaussian tensor.
Default: 'cpu'.
Returns:
h (Tensor): Gaussian kernel with a
``(2 * radius_y + 1) * (2 * radius_x + 1)`` shape.
"""
x
=
torch
.
arange
(
-
radius
[
0
],
radius
[
0
]
+
1
,
dtype
=
dtype
,
device
=
device
).
view
(
1
,
-
1
)
y
=
torch
.
arange
(
-
radius
[
1
],
radius
[
1
]
+
1
,
dtype
=
dtype
,
device
=
device
).
view
(
-
1
,
1
)
h
=
(
-
(
x
*
x
)
/
(
2
*
sigma_x
*
sigma_x
)
-
(
y
*
y
)
/
(
2
*
sigma_y
*
sigma_y
)).
exp
()
h
[
h
<
torch
.
finfo
(
h
.
dtype
).
eps
*
h
.
max
()]
=
0
return
h
mmdet3d/core/visualizer/image_vis.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
copy
import
cv2
import
numpy
as
np
import
torch
...
...
@@ -18,7 +19,7 @@ def project_pts_on_img(points,
raw_img (numpy.array): The numpy array of image.
lidar2img_rt (numpy.array, shape=[4, 4]): The projection matrix
according to the camera intrinsic parameters.
max_distance (float): the max distance of the points cloud.
max_distance (float
, optional
): the max distance of the points cloud.
Default: 70.
thickness (int, optional): The thickness of 2D points. Default: -1.
"""
...
...
@@ -69,7 +70,8 @@ def plot_rect3d_on_img(img,
num_rects (int): Number of 3D rectangulars.
rect_corners (numpy.array): Coordinates of the corners of 3D
rectangulars. Should be in the shape of [num_rect, 8, 2].
color (tuple[int]): The color to draw bboxes. Default: (0, 255, 0).
color (tuple[int], optional): The color to draw bboxes.
Default: (0, 255, 0).
thickness (int, optional): The thickness of bboxes. Default: 1.
"""
line_indices
=
((
0
,
1
),
(
0
,
3
),
(
0
,
4
),
(
1
,
2
),
(
1
,
5
),
(
3
,
2
),
(
3
,
7
),
...
...
@@ -99,7 +101,8 @@ def draw_lidar_bbox3d_on_img(bboxes3d,
lidar2img_rt (numpy.array, shape=[4, 4]): The projection matrix
according to the camera intrinsic parameters.
img_metas (dict): Useless here.
color (tuple[int]): The color to draw bboxes. Default: (0, 255, 0).
color (tuple[int], optional): The color to draw bboxes.
Default: (0, 255, 0).
thickness (int, optional): The thickness of bboxes. Default: 1.
"""
img
=
raw_img
.
copy
()
...
...
@@ -136,7 +139,8 @@ def draw_depth_bbox3d_on_img(bboxes3d,
raw_img (numpy.array): The numpy array of image.
calibs (dict): Camera calibration information, Rt and K.
img_metas (dict): Used in coordinates transformation.
color (tuple[int]): The color to draw bboxes. Default: (0, 255, 0).
color (tuple[int], optional): The color to draw bboxes.
Default: (0, 255, 0).
thickness (int, optional): The thickness of bboxes. Default: 1.
"""
from
mmdet3d.core.bbox
import
points_cam2img
...
...
@@ -176,7 +180,8 @@ def draw_camera_bbox3d_on_img(bboxes3d,
cam2img (dict): Camera intrinsic matrix,
denoted as `K` in depth bbox coordinate system.
img_metas (dict): Useless here.
color (tuple[int]): The color to draw bboxes. Default: (0, 255, 0).
color (tuple[int], optional): The color to draw bboxes.
Default: (0, 255, 0).
thickness (int, optional): The thickness of bboxes. Default: 1.
"""
from
mmdet3d.core.bbox
import
points_cam2img
...
...
@@ -188,7 +193,10 @@ def draw_camera_bbox3d_on_img(bboxes3d,
points_3d
=
corners_3d
.
reshape
(
-
1
,
3
)
if
not
isinstance
(
cam2img
,
torch
.
Tensor
):
cam2img
=
torch
.
from_numpy
(
np
.
array
(
cam2img
))
cam2img
=
cam2img
.
reshape
(
3
,
3
).
float
().
cpu
()
assert
(
cam2img
.
shape
==
torch
.
Size
([
3
,
3
])
or
cam2img
.
shape
==
torch
.
Size
([
4
,
4
]))
cam2img
=
cam2img
.
float
().
cpu
()
# project to 2d to get image coords (uv)
uv_origin
=
points_cam2img
(
points_3d
,
cam2img
)
...
...
mmdet3d/core/visualizer/open3d_vis.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
copy
import
numpy
as
np
import
torch
...
...
@@ -22,12 +23,12 @@ def _draw_points(points,
points (numpy.array | torch.tensor, shape=[N, 3+C]):
points to visualize.
vis (:obj:`open3d.visualization.Visualizer`): open3d visualizer.
points_size (int): the size of points to show on visualizer.
points_size (int
, optional
): the size of points to show on visualizer.
Default: 2.
point_color (tuple[float]): the color of points.
point_color (tuple[float]
, optional
): the color of points.
Default: (0.5, 0.5, 0.5).
mode (str): indicate type of the input points,
avaliable mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points,
available mode
['xyz', 'xyzrgb']. Default: 'xyz'.
Returns:
tuple: points, color of each point.
...
...
@@ -69,19 +70,21 @@ def _draw_bboxes(bbox3d,
Args:
bbox3d (numpy.array | torch.tensor, shape=[M, 7]):
3d bbox (x, y, z,
dx, dy, dz
, yaw) to visualize.
3d bbox (x, y, z,
x_size, y_size, z_size
, yaw) to visualize.
vis (:obj:`open3d.visualization.Visualizer`): open3d visualizer.
points_colors (numpy.array): color of each points.
pcd (:obj:`open3d.geometry.PointCloud`): point cloud. Default: None.
bbox_color (tuple[float]): the color of bbox. Default: (0, 1, 0).
points_in_box_color (tuple[float]):
pcd (:obj:`open3d.geometry.PointCloud`, optional): point cloud.
Default: None.
bbox_color (tuple[float], optional): the color of bbox.
Default: (0, 1, 0).
points_in_box_color (tuple[float], optional):
the color of points inside bbox3d. Default: (1, 0, 0).
rot_axis (int): rotation axis of bbox. Default: 2.
center_mode (bool): indicate the center of bbox is
bottom center
or gravity center. ava
l
iable mode
rot_axis (int
, optional
): rotation axis of bbox. Default: 2.
center_mode (bool
, optional
): indicate the center of bbox is
bottom center
or gravity center. avai
l
able mode
['lidar_bottom', 'camera_bottom']. Default: 'lidar_bottom'.
mode (str): indicate type of the input points,
avaliable mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points,
available mode
['xyz', 'xyzrgb']. Default: 'xyz'.
"""
if
isinstance
(
bbox3d
,
torch
.
Tensor
):
bbox3d
=
bbox3d
.
cpu
().
numpy
()
...
...
@@ -135,23 +138,27 @@ def show_pts_boxes(points,
Args:
points (numpy.array | torch.tensor, shape=[N, 3+C]):
points to visualize.
bbox3d (numpy.array | torch.tensor, shape=[M, 7]):
3d bbox (x, y, z, dx, dy, dz, yaw) to visualize. Default: None.
show (bool): whether to show the visualization results. Default: True.
save_path (str): path to save visualized results. Default: None.
points_size (int): the size of points to show on visualizer.
bbox3d (numpy.array | torch.tensor, shape=[M, 7], optional):
3D bbox (x, y, z, x_size, y_size, z_size, yaw) to visualize.
Defaults to None.
show (bool, optional): whether to show the visualization results.
Default: True.
save_path (str, optional): path to save visualized results.
Default: None.
points_size (int, optional): the size of points to show on visualizer.
Default: 2.
point_color (tuple[float]): the color of points.
point_color (tuple[float]
, optional
): the color of points.
Default: (0.5, 0.5, 0.5).
bbox_color (tuple[float]): the color of bbox. Default: (0, 1, 0).
points_in_box_color (tuple[float]):
bbox_color (tuple[float], optional): the color of bbox.
Default: (0, 1, 0).
points_in_box_color (tuple[float], optional):
the color of points which are in bbox3d. Default: (1, 0, 0).
rot_axis (int): rotation axis of bbox. Default: 2.
center_mode (bool): indicate the center of bbox is bottom
center
or gravity center. ava
l
iable mode
rot_axis (int
, optional
): rotation axis of bbox. Default: 2.
center_mode (bool
, optional
): indicate the center of bbox is bottom
center
or gravity center. avai
l
able mode
['lidar_bottom', 'camera_bottom']. Default: 'lidar_bottom'.
mode (str): indicate type of the input points, ava
l
iable
mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points, avai
l
able
mode
['xyz', 'xyzrgb']. Default: 'xyz'.
"""
# TODO: support score and class info
assert
0
<=
rot_axis
<=
2
...
...
@@ -196,21 +203,23 @@ def _draw_bboxes_ind(bbox3d,
Args:
bbox3d (numpy.array | torch.tensor, shape=[M, 7]):
3d bbox (x, y, z,
dx, dy, dz
, yaw) to visualize.
3d bbox (x, y, z,
x_size, y_size, z_size
, yaw) to visualize.
vis (:obj:`open3d.visualization.Visualizer`): open3d visualizer.
indices (numpy.array | torch.tensor, shape=[N, M]):
indicate which bbox3d that each point lies in.
points_colors (numpy.array): color of each points.
pcd (:obj:`open3d.geometry.PointCloud`): point cloud. Default: None.
bbox_color (tuple[float]): the color of bbox. Default: (0, 1, 0).
points_in_box_color (tuple[float]):
pcd (:obj:`open3d.geometry.PointCloud`, optional): point cloud.
Default: None.
bbox_color (tuple[float], optional): the color of bbox.
Default: (0, 1, 0).
points_in_box_color (tuple[float], optional):
the color of points which are in bbox3d. Default: (1, 0, 0).
rot_axis (int): rotation axis of bbox. Default: 2.
center_mode (bool): indicate the center of bbox is
bottom center
or gravity center. ava
l
iable mode
rot_axis (int
, optional
): rotation axis of bbox. Default: 2.
center_mode (bool
, optional
): indicate the center of bbox is
bottom center
or gravity center. avai
l
able mode
['lidar_bottom', 'camera_bottom']. Default: 'lidar_bottom'.
mode (str): indicate type of the input points,
avaliable mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points,
available mode
['xyz', 'xyzrgb']. Default: 'xyz'.
"""
if
isinstance
(
bbox3d
,
torch
.
Tensor
):
bbox3d
=
bbox3d
.
cpu
().
numpy
()
...
...
@@ -270,24 +279,28 @@ def show_pts_index_boxes(points,
points (numpy.array | torch.tensor, shape=[N, 3+C]):
points to visualize.
bbox3d (numpy.array | torch.tensor, shape=[M, 7]):
3d bbox (x, y, z, dx, dy, dz, yaw) to visualize. Default: None.
show (bool): whether to show the visualization results. Default: True.
indices (numpy.array | torch.tensor, shape=[N, M]):
3D bbox (x, y, z, x_size, y_size, z_size, yaw) to visualize.
Defaults to None.
show (bool, optional): whether to show the visualization results.
Default: True.
indices (numpy.array | torch.tensor, shape=[N, M], optional):
indicate which bbox3d that each point lies in. Default: None.
save_path (str): path to save visualized results. Default: None.
points_size (int): the size of points to show on visualizer.
save_path (str, optional): path to save visualized results.
Default: None.
points_size (int, optional): the size of points to show on visualizer.
Default: 2.
point_color (tuple[float]): the color of points.
point_color (tuple[float]
, optional
): the color of points.
Default: (0.5, 0.5, 0.5).
bbox_color (tuple[float]): the color of bbox. Default: (0, 1, 0).
points_in_box_color (tuple[float]):
bbox_color (tuple[float], optional): the color of bbox.
Default: (0, 1, 0).
points_in_box_color (tuple[float], optional):
the color of points which are in bbox3d. Default: (1, 0, 0).
rot_axis (int): rotation axis of bbox. Default: 2.
center_mode (bool): indicate the center of bbox is
bottom center
or gravity center. ava
l
iable mode
rot_axis (int
, optional
): rotation axis of bbox. Default: 2.
center_mode (bool
, optional
): indicate the center of bbox is
bottom center
or gravity center. avai
l
able mode
['lidar_bottom', 'camera_bottom']. Default: 'lidar_bottom'.
mode (str): indicate type of the input points,
avaliable mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points,
available mode
['xyz', 'xyzrgb']. Default: 'xyz'.
"""
# TODO: support score and class info
assert
0
<=
rot_axis
<=
2
...
...
@@ -324,24 +337,27 @@ class Visualizer(object):
points (numpy.array, shape=[N, 3+C]): Points to visualize. The Points
cloud is in mode of Coord3DMode.DEPTH (please refer to
core.structures.coord_3d_mode).
bbox3d (numpy.array, shape=[M, 7]): 3d bbox (x, y, z, dx, dy, dz, yaw)
to visualize. The 3d bbox is in mode of Box3DMode.DEPTH with
bbox3d (numpy.array, shape=[M, 7], optional): 3D bbox
(x, y, z, x_size, y_size, z_size, yaw) to visualize.
The 3D bbox is in mode of Box3DMode.DEPTH with
gravity_center (please refer to core.structures.box_3d_mode).
Default: None.
save_path (str): path to save visualized results. Default: None.
points_size (int): the size of points to show on visualizer.
save_path (str, optional): path to save visualized results.
Default: None.
points_size (int, optional): the size of points to show on visualizer.
Default: 2.
point_color (tuple[float]): the color of points.
point_color (tuple[float]
, optional
): the color of points.
Default: (0.5, 0.5, 0.5).
bbox_color (tuple[float]): the color of bbox. Default: (0, 1, 0).
points_in_box_color (tuple[float]):
bbox_color (tuple[float], optional): the color of bbox.
Default: (0, 1, 0).
points_in_box_color (tuple[float], optional):
the color of points which are in bbox3d. Default: (1, 0, 0).
rot_axis (int): rotation axis of bbox. Default: 2.
center_mode (bool): indicate the center of bbox is
bottom center
or gravity center. ava
l
iable mode
rot_axis (int
, optional
): rotation axis of bbox. Default: 2.
center_mode (bool
, optional
): indicate the center of bbox is
bottom center
or gravity center. avai
l
able mode
['lidar_bottom', 'camera_bottom']. Default: 'lidar_bottom'.
mode (str): indicate type of the input points,
avaliable mode
['xyz', 'xyzrgb']. Default: 'xyz'.
mode (str
, optional
): indicate type of the input points,
available mode
['xyz', 'xyzrgb']. Default: 'xyz'.
"""
def
__init__
(
self
,
...
...
@@ -390,12 +406,13 @@ class Visualizer(object):
Args:
bbox3d (numpy.array, shape=[M, 7]):
3D bbox (x, y, z, dx, dy, dz, yaw) to be visualized.
The 3d bbox is in mode of Box3DMode.DEPTH with
gravity_center (please refer to core.structures.box_3d_mode).
bbox_color (tuple[float]): the color of bbox. Defaule: None.
3D bbox (x, y, z, x_size, y_size, z_size, yaw)
to be visualized. The 3d bbox is in mode of
Box3DMode.DEPTH with gravity_center (please refer to
core.structures.box_3d_mode).
bbox_color (tuple[float]): the color of bbox. Default: None.
points_in_box_color (tuple[float]): the color of points which
are in bbox3d. Defaul
e
: None.
are in bbox3d. Defaul
t
: None.
"""
if
bbox_color
is
None
:
bbox_color
=
self
.
bbox_color
...
...
@@ -431,7 +448,7 @@ class Visualizer(object):
"""Visualize the points cloud.
Args:
save_path (str): path to save image. Default: None.
save_path (str
, optional
): path to save image. Default: None.
"""
self
.
o3d_visualizer
.
run
()
...
...
mmdet3d/core/visualizer/show_result.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
from
os
import
path
as
osp
import
mmcv
import
numpy
as
np
import
trimesh
from
os
import
path
as
osp
from
.image_vis
import
(
draw_camera_bbox3d_on_img
,
draw_depth_bbox3d_on_img
,
draw_lidar_bbox3d_on_img
)
...
...
@@ -35,7 +36,7 @@ def _write_oriented_bbox(scene_bbox, out_filename):
Args:
scene_bbox(list[ndarray] or ndarray): xyz pos of center and
3 lengths (
dx,dy,dz
) and heading angle around Z axis.
3 lengths (
x_size, y_size, z_size
) and heading angle around Z axis.
Y forward, X right, Z upward. heading angle of positive X is 0,
heading angle of positive Y is 90 degrees.
out_filename(str): Filename.
...
...
@@ -131,16 +132,14 @@ def show_result(points,
if
gt_bboxes
is
not
None
:
# bottom center to gravity center
gt_bboxes
[...,
2
]
+=
gt_bboxes
[...,
5
]
/
2
# the positive direction for yaw in meshlab is clockwise
gt_bboxes
[:,
6
]
*=
-
1
_write_oriented_bbox
(
gt_bboxes
,
osp
.
join
(
result_path
,
f
'
{
filename
}
_gt.obj'
))
if
pred_bboxes
is
not
None
:
# bottom center to gravity center
pred_bboxes
[...,
2
]
+=
pred_bboxes
[...,
5
]
/
2
# the positive direction for yaw in meshlab is clockwise
pred_bboxes
[:,
6
]
*=
-
1
_write_oriented_bbox
(
pred_bboxes
,
osp
.
join
(
result_path
,
f
'
{
filename
}
_pred.obj'
))
...
...
@@ -152,7 +151,7 @@ def show_seg_result(points,
filename
,
palette
,
ignore_index
=
None
,
show
=
Tru
e
,
show
=
Fals
e
,
snapshot
=
False
):
"""Convert results into format that is directly readable for meshlab.
...
...
@@ -163,10 +162,10 @@ def show_seg_result(points,
out_dir (str): Path of output directory
filename (str): Filename of the current frame.
palette (np.ndarray): Mapping between class labels and colors.
ignore_index (int, optional): The label index to be ignored, e.g.
\
ignore_index (int, optional): The label index to be ignored, e.g.
unannotated points. Defaults to None.
show (bool, optional): Visualize the results online. Defaults to False.
snapshot (bool, optional): Whether to save the online results.
\
snapshot (bool, optional): Whether to save the online results.
Defaults to False.
"""
# we need 3D coordinates to visualize segmentation mask
...
...
@@ -226,7 +225,7 @@ def show_multi_modality_result(img,
filename
,
box_mode
=
'lidar'
,
img_metas
=
None
,
show
=
Tru
e
,
show
=
Fals
e
,
gt_bbox_color
=
(
61
,
102
,
255
),
pred_bbox_color
=
(
241
,
101
,
72
)):
"""Convert multi-modality detection results into 2D results.
...
...
@@ -241,14 +240,16 @@ def show_multi_modality_result(img,
according to the camera intrinsic parameters.
out_dir (str): Path of output directory.
filename (str): Filename of the current frame.
box_mode (str): Coordinate system the boxes are in. Should be one of
'depth', 'lidar' and 'camera'. Defaults to 'lidar'.
img_metas (dict): Used in projecting depth bbox.
show (bool): Visualize the results online. Defaults to False.
gt_bbox_color (str or tuple(int)): Color of bbox lines.
The tuple of color should be in BGR order. Default: (255, 102, 61)
pred_bbox_color (str or tuple(int)): Color of bbox lines.
The tuple of color should be in BGR order. Default: (72, 101, 241)
box_mode (str, optional): Coordinate system the boxes are in.
Should be one of 'depth', 'lidar' and 'camera'.
Defaults to 'lidar'.
img_metas (dict, optional): Used in projecting depth bbox.
Defaults to None.
show (bool, optional): Visualize the results online. Defaults to False.
gt_bbox_color (str or tuple(int), optional): Color of bbox lines.
The tuple of color should be in BGR order. Default: (255, 102, 61).
pred_bbox_color (str or tuple(int), optional): Color of bbox lines.
The tuple of color should be in BGR order. Default: (72, 101, 241).
"""
if
box_mode
==
'depth'
:
draw_bbox
=
draw_depth_bbox3d_on_img
...
...
mmdet3d/core/voxel/voxel_generator.py
View file @
32a4328b
...
...
@@ -82,18 +82,18 @@ def points_to_voxel(points,
"""convert kitti points(N, >=3) to voxels.
Args:
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
\
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
points[:, 3:] contain other information such as reflectivity.
voxel_size (list, tuple, np.ndarray): [3] xyz, indicate voxel size
coors_range (list[float | tuple[float] | ndarray]): Voxel range.
\
coors_range (list[float | tuple[float] | ndarray]): Voxel range.
format: xyzxyz, minmax
max_points (int): Indicate maximum points contained in a voxel.
reverse_index (bool): Whether return reversed coordinates.
\
if points has xyz format and reverse_index is True, output
\
coordinates will be zyx format, but points in features always
\
reverse_index (bool): Whether return reversed coordinates.
if points has xyz format and reverse_index is True, output
coordinates will be zyx format, but points in features always
xyz format.
max_voxels (int): Maximum number of voxels this function creates.
\
For second, 20000 is a good choice. Points should be shuffled for
\
max_voxels (int): Maximum number of voxels this function creates.
For second, 20000 is a good choice. Points should be shuffled for
randomness before this function because max_voxels drops points.
Returns:
...
...
@@ -147,20 +147,20 @@ def _points_to_voxel_reverse_kernel(points,
"""convert kitti points(N, >=3) to voxels.
Args:
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
\
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
points[:, 3:] contain other information such as reflectivity.
voxel_size (list, tuple, np.ndarray): [3] xyz, indicate voxel size
\
coors_range (list[float | tuple[float] | ndarray]): Range of voxels.
\
voxel_size (list, tuple, np.ndarray): [3] xyz, indicate voxel size
coors_range (list[float | tuple[float] | ndarray]): Range of voxels.
format: xyzxyz, minmax
num_points_per_voxel (int): Number of points per voxel.
coor_to_voxel_idx (np.ndarray): A voxel grid of shape (D, H, W),
\
which has the same shape as the complete voxel map. It indicates
\
coor_to_voxel_idx (np.ndarray): A voxel grid of shape (D, H, W),
which has the same shape as the complete voxel map. It indicates
the index of each corresponding voxel.
voxels (np.ndarray): Created empty voxels.
coors (np.ndarray): Created coordinates of each voxel.
max_points (int): Indicate maximum points contained in a voxel.
max_voxels (int): Maximum number of voxels this function create.
\
for second, 20000 is a good choice. Points should be shuffled for
\
max_voxels (int): Maximum number of voxels this function create.
for second, 20000 is a good choice. Points should be shuffled for
randomness before this function because max_voxels drops points.
Returns:
...
...
@@ -221,20 +221,20 @@ def _points_to_voxel_kernel(points,
"""convert kitti points(N, >=3) to voxels.
Args:
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
\
points (np.ndarray): [N, ndim]. points[:, :3] contain xyz points and
points[:, 3:] contain other information such as reflectivity.
voxel_size (list, tuple, np.ndarray): [3] xyz, indicate voxel size.
coors_range (list[float | tuple[float] | ndarray]): Range of voxels.
\
coors_range (list[float | tuple[float] | ndarray]): Range of voxels.
format: xyzxyz, minmax
num_points_per_voxel (int): Number of points per voxel.
coor_to_voxel_idx (np.ndarray): A voxel grid of shape (D, H, W),
\
which has the same shape as the complete voxel map. It indicates
\
coor_to_voxel_idx (np.ndarray): A voxel grid of shape (D, H, W),
which has the same shape as the complete voxel map. It indicates
the index of each corresponding voxel.
voxels (np.ndarray): Created empty voxels.
coors (np.ndarray): Created coordinates of each voxel.
max_points (int): Indicate maximum points contained in a voxel.
max_voxels (int): Maximum number of voxels this function create.
\
for second, 20000 is a good choice. Points should be shuffled for
\
max_voxels (int): Maximum number of voxels this function create.
for second, 20000 is a good choice. Points should be shuffled for
randomness before this function because max_voxels drops points.
Returns:
...
...
mmdet3d/datasets/__init__.py
View file @
32a4328b
...
...
@@ -9,14 +9,15 @@ from .lyft_dataset import LyftDataset
from
.nuscenes_dataset
import
NuScenesDataset
from
.nuscenes_mono_dataset
import
NuScenesMonoDataset
# yapf: disable
from
.pipelines
import
(
BackgroundPointsFilter
,
GlobalAlignment
,
from
.pipelines
import
(
AffineResize
,
BackgroundPointsFilter
,
GlobalAlignment
,
GlobalRotScaleTrans
,
IndoorPatchPointSample
,
IndoorPointSample
,
LoadAnnotations3D
,
LoadPointsFromFile
,
LoadPointsFromMultiSweeps
,
NormalizePointsColor
,
ObjectNameFilter
,
ObjectNoise
,
ObjectRangeFilter
,
ObjectSample
,
PointSample
,
PointShuffle
,
PointsRangeFilter
,
RandomDropPointsColor
,
RandomFlip3D
,
RandomJitterPoints
,
LoadPointsFromDict
,
LoadPointsFromFile
,
LoadPointsFromMultiSweeps
,
NormalizePointsColor
,
ObjectNameFilter
,
ObjectNoise
,
ObjectRangeFilter
,
ObjectSample
,
PointSample
,
PointShuffle
,
PointsRangeFilter
,
RandomDropPointsColor
,
RandomFlip3D
,
RandomJitterPoints
,
RandomShiftScale
,
VoxelBasedPointSampler
)
# yapf: enable
from
.s3dis_dataset
import
S3DISDataset
,
S3DISSegDataset
...
...
@@ -38,5 +39,6 @@ __all__ = [
'Custom3DDataset'
,
'Custom3DSegDataset'
,
'LoadPointsFromMultiSweeps'
,
'WaymoDataset'
,
'BackgroundPointsFilter'
,
'VoxelBasedPointSampler'
,
'get_loading_pipeline'
,
'RandomDropPointsColor'
,
'RandomJitterPoints'
,
'ObjectNameFilter'
'ObjectNameFilter'
,
'AffineResize'
,
'RandomShiftScale'
,
'LoadPointsFromDict'
]
mmdet3d/datasets/builder.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
platform
from
mmcv.utils
import
Registry
,
build_from_cfg
from
mmdet.datasets
import
DATASETS
...
...
mmdet3d/datasets/custom_3d.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
mmcv
import
numpy
as
np
import
tempfile
import
warnings
from
os
import
path
as
osp
import
mmcv
import
numpy
as
np
from
torch.utils.data
import
Dataset
from
mmdet.datasets
import
DATASETS
...
...
@@ -88,7 +89,7 @@ class Custom3DDataset(Dataset):
index (int): Index of the sample data to get.
Returns:
dict: Data information that will be passed to the data
\
dict: Data information that will be passed to the data
preprocessing pipelines. It includes the following keys:
- sample_idx (str): Sample index.
...
...
@@ -177,7 +178,7 @@ class Custom3DDataset(Dataset):
"""Get class names of current dataset.
Args:
classes (Sequence[str] | str
| None
): If classes is None, use
classes (Sequence[str] | str): If classes is None, use
default CLASSES defined by builtin dataset. If classes is a
string, take it as a file name. The file contains the name of
classes where each line contains one class name. If classes is
...
...
@@ -207,13 +208,13 @@ class Custom3DDataset(Dataset):
Args:
outputs (list[dict]): Testing results of the dataset.
pklfile_prefix (str
| None
): The prefix of pkl files. It includes
pklfile_prefix (str): The prefix of pkl files. It includes
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
Returns:
tuple: (outputs, tmp_dir), outputs is the detection results,
\
tmp_dir is the temporal directory created for saving json
\
tuple: (outputs, tmp_dir), outputs is the detection results,
tmp_dir is the temporal directory created for saving json
files when ``jsonfile_prefix`` is not specified.
"""
if
pklfile_prefix
is
None
:
...
...
@@ -237,11 +238,14 @@ class Custom3DDataset(Dataset):
Args:
results (list[dict]): List of results.
metric (str | list[str]): Metrics to be evaluated.
iou_thr (list[float]): AP IoU thresholds.
show (bool): Whether to visualize.
metric (str | list[str], optional): Metrics to be evaluated.
Defaults to None.
iou_thr (list[float]): AP IoU thresholds. Defaults to (0.25, 0.5).
logger (logging.Logger | str, optional): Logger used for printing
related information during evaluation. Defaults to None.
show (bool, optional): Whether to visualize.
Default: False.
out_dir (str): Path to save the visualization results.
out_dir (str
, optional
): Path to save the visualization results.
Default: None.
pipeline (list[dict], optional): raw data loading for showing.
Default: None.
...
...
@@ -281,7 +285,7 @@ class Custom3DDataset(Dataset):
"""Get data loading pipeline in self.show/evaluate function.
Args:
pipeline (list[dict]
| None
): Input pipeline. If None is given,
\
pipeline (list[dict]): Input pipeline. If None is given,
get from self.pipeline.
"""
if
pipeline
is
None
:
...
...
mmdet3d/datasets/custom_3d_seg.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
mmcv
import
numpy
as
np
import
tempfile
import
warnings
from
os
import
path
as
osp
import
mmcv
import
numpy
as
np
from
torch.utils.data
import
Dataset
from
mmdet.datasets
import
DATASETS
...
...
@@ -32,7 +33,7 @@ class Custom3DSegDataset(Dataset):
as input. Defaults to None.
test_mode (bool, optional): Whether the dataset is in test mode.
Defaults to False.
ignore_index (int, optional): The label index to be ignored, e.g.
\
ignore_index (int, optional): The label index to be ignored, e.g.
unannotated points. If None is given, set to len(self.CLASSES) to
be consistent with PointSegClassMapping function in pipeline.
Defaults to None.
...
...
@@ -102,7 +103,7 @@ class Custom3DSegDataset(Dataset):
index (int): Index of the sample data to get.
Returns:
dict: Data information that will be passed to the data
\
dict: Data information that will be passed to the data
preprocessing pipelines. It includes the following keys:
- sample_idx (str): Sample index.
...
...
@@ -179,13 +180,13 @@ class Custom3DSegDataset(Dataset):
This function is taken from MMSegmentation.
Args:
classes (Sequence[str] | str
| None
): If classes is None, use
classes (Sequence[str] | str): If classes is None, use
default CLASSES defined by builtin dataset. If classes is a
string, take it as a file name. The file contains the name of
classes where each line contains one class name. If classes is
a tuple or list, override the CLASSES defined by the dataset.
Defaults to None.
palette (Sequence[Sequence[int]]] | np.ndarray
| None
):
palette (Sequence[Sequence[int]]] | np.ndarray):
The palette of segmentation map. If None is given, random
palette will be generated. Defaults to None.
"""
...
...
@@ -276,13 +277,13 @@ class Custom3DSegDataset(Dataset):
Args:
outputs (list[dict]): Testing results of the dataset.
pklfile_prefix (str
| None
): The prefix of pkl files. It includes
pklfile_prefix (str): The prefix of pkl files. It includes
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
Returns:
tuple: (outputs, tmp_dir), outputs is the detection results,
\
tmp_dir is the temporal directory created for saving json
\
tuple: (outputs, tmp_dir), outputs is the detection results,
tmp_dir is the temporal directory created for saving json
files when ``jsonfile_prefix`` is not specified.
"""
if
pklfile_prefix
is
None
:
...
...
@@ -306,7 +307,7 @@ class Custom3DSegDataset(Dataset):
Args:
results (list[dict]): List of results.
metric (str | list[str]): Metrics to be evaluated.
logger (logging.Logger |
None | str
): Logger used for printing
logger (logging.Logger |
str, optional
): Logger used for printing
related information during evaluation. Defaults to None.
show (bool, optional): Whether to visualize.
Defaults to False.
...
...
@@ -364,7 +365,7 @@ class Custom3DSegDataset(Dataset):
"""Get data loading pipeline in self.show/evaluate function.
Args:
pipeline (list[dict]
| None
): Input pipeline. If None is given,
\
pipeline (list[dict]): Input pipeline. If None is given,
get from self.pipeline.
"""
if
pipeline
is
None
:
...
...
mmdet3d/datasets/kitti2d_dataset.py
View file @
32a4328b
...
...
@@ -206,7 +206,8 @@ class Kitti2DDataset(CustomDataset):
Args:
outputs (list[np.ndarray]): List of arrays storing the inferenced
bounding boxes and scores.
out (str | None): The prefix of output file. Default: None.
out (str, optional): The prefix of output file.
Default: None.
Returns:
list[dict]: A list of dictionaries with the kitti 2D format.
...
...
@@ -222,7 +223,7 @@ class Kitti2DDataset(CustomDataset):
Args:
result_files (str): Path of result files.
eval_types (str): Types of evaluation. Default: None.
eval_types (str
, optional
): Types of evaluation. Default: None.
KITTI dataset only support 'bbox' evaluation type.
Returns:
...
...
mmdet3d/datasets/kitti_dataset.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
copy
import
mmcv
import
numpy
as
np
import
os
import
tempfile
from
os
import
path
as
osp
import
mmcv
import
numpy
as
np
import
torch
from
mmcv.utils
import
print_log
from
os
import
path
as
osp
from
mmdet.datasets
import
DATASETS
from
..core
import
show_multi_modality_result
,
show_result
...
...
@@ -47,8 +48,9 @@ class KittiDataset(Custom3DDataset):
Defaults to True.
test_mode (bool, optional): Whether the dataset is in test mode.
Defaults to False.
pcd_limit_range (list): The range of point cloud used to filter
invalid predicted boxes. Default: [0, -40, -3, 70.4, 40, 0.0].
pcd_limit_range (list, optional): The range of point cloud used to
filter invalid predicted boxes.
Default: [0, -40, -3, 70.4, 40, 0.0].
"""
CLASSES
=
(
'car'
,
'pedestrian'
,
'cyclist'
)
...
...
@@ -100,14 +102,14 @@ class KittiDataset(Custom3DDataset):
index (int): Index of the sample data to get.
Returns:
dict: Data information that will be passed to the data
\
dict: Data information that will be passed to the data
preprocessing pipelines. It includes the following keys:
- sample_idx (str): Sample index.
- pts_filename (str): Filename of point clouds.
- img_prefix (str
| None
): Prefix of image files.
- img_prefix (str): Prefix of image files.
- img_info (dict): Image info.
- lidar2img (list[np.ndarray], optional): Transformations
\
- lidar2img (list[np.ndarray], optional): Transformations
from lidar to different cameras.
- ann_info (dict): Annotation info.
"""
...
...
@@ -145,19 +147,38 @@ class KittiDataset(Custom3DDataset):
Returns:
dict: annotation information consists of the following keys:
- gt_bboxes_3d (:obj:`LiDARInstance3DBoxes`):
\
- gt_bboxes_3d (:obj:`LiDARInstance3DBoxes`):
3D ground truth bboxes.
- gt_labels_3d (np.ndarray): Labels of ground truths.
- gt_bboxes (np.ndarray): 2D ground truth bboxes.
- gt_labels (np.ndarray): Labels of ground truths.
- gt_names (list[str]): Class names of ground truths.
- difficulty (int): kitti difficulty.
- difficulty (int): Difficulty defined by KITTI.
0, 1, 2 represent xxxxx respectively.
"""
# Use index to get the annos, thus the evalhook could also use this api
info
=
self
.
data_infos
[
index
]
rect
=
info
[
'calib'
][
'R0_rect'
].
astype
(
np
.
float32
)
Trv2c
=
info
[
'calib'
][
'Tr_velo_to_cam'
].
astype
(
np
.
float32
)
if
'plane'
in
info
:
# convert ground plane to velodyne coordinates
reverse
=
np
.
linalg
.
inv
(
rect
@
Trv2c
)
(
plane_norm_cam
,
plane_off_cam
)
=
(
info
[
'plane'
][:
3
],
-
info
[
'plane'
][:
3
]
*
info
[
'plane'
][
3
])
plane_norm_lidar
=
\
(
reverse
[:
3
,
:
3
]
@
plane_norm_cam
[:,
None
])[:,
0
]
plane_off_lidar
=
(
reverse
[:
3
,
:
3
]
@
plane_off_cam
[:,
None
][:,
0
]
+
reverse
[:
3
,
3
])
plane_lidar
=
np
.
zeros_like
(
plane_norm_lidar
,
shape
=
(
4
,
))
plane_lidar
[:
3
]
=
plane_norm_lidar
plane_lidar
[
3
]
=
-
plane_norm_lidar
.
T
@
plane_off_lidar
else
:
plane_lidar
=
None
difficulty
=
info
[
'annos'
][
'difficulty'
]
annos
=
info
[
'annos'
]
# we need other objects to avoid collision when sample
...
...
@@ -193,6 +214,7 @@ class KittiDataset(Custom3DDataset):
bboxes
=
gt_bboxes
,
labels
=
gt_labels
,
gt_names
=
gt_names
,
plane
=
plane_lidar
,
difficulty
=
difficulty
)
return
anns_results
...
...
@@ -251,17 +273,17 @@ class KittiDataset(Custom3DDataset):
Args:
outputs (list[dict]): Testing results of the dataset.
pklfile_prefix (str
| None
): The prefix of pkl files. It includes
pklfile_prefix (str): The prefix of pkl files. It includes
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
submission_prefix (str
| None
): The prefix of submitted files. It
submission_prefix (str): The prefix of submitted files. It
includes the file path and the prefix of filename, e.g.,
"a/b/prefix". If not specified, a temp file will be created.
Default: None.
Returns:
tuple: (result_files, tmp_dir), result_files is a dict containing
\
the json filepaths, tmp_dir is the temporal directory created
\
tuple: (result_files, tmp_dir), result_files is a dict containing
the json filepaths, tmp_dir is the temporal directory created
for saving json files when jsonfile_prefix is not specified.
"""
if
pklfile_prefix
is
None
:
...
...
@@ -311,17 +333,19 @@ class KittiDataset(Custom3DDataset):
Args:
results (list[dict]): Testing results of the dataset.
metric (str | list[str]): Metrics to be evaluated.
logger (logging.Logger | str | None): Logger used for printing
metric (str | list[str], optional): Metrics to be evaluated.
Default: None.
logger (logging.Logger | str, optional): Logger used for printing
related information during evaluation. Default: None.
pklfile_prefix (str
| None
): The prefix of pkl files
. It
includ
es
pklfile_prefix (str
, optional
): The prefix of pkl files
,
includ
ing
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
submission_prefix (str
| None
): The prefix of submission data.
submission_prefix (str
, optional
): The prefix of submission data.
If not specified, the submission data will not be generated.
show (bool): Whether to visualize.
Default: None.
show (bool, optional): Whether to visualize.
Default: False.
out_dir (str): Path to save the visualization results.
out_dir (str
, optional
): Path to save the visualization results.
Default: None.
pipeline (list[dict], optional): raw data loading for showing.
Default: None.
...
...
@@ -361,8 +385,8 @@ class KittiDataset(Custom3DDataset):
if
tmp_dir
is
not
None
:
tmp_dir
.
cleanup
()
if
show
:
self
.
show
(
results
,
out_dir
,
pipeline
=
pipeline
)
if
show
or
out_dir
:
self
.
show
(
results
,
out_dir
,
show
=
show
,
pipeline
=
pipeline
)
return
ap_dict
def
bbox2result_kitti
(
self
,
...
...
@@ -374,11 +398,11 @@ class KittiDataset(Custom3DDataset):
submission.
Args:
net_outputs (list[np.ndarray]): List of array storing the
\
net_outputs (list[np.ndarray]): List of array storing the
inferenced bounding boxes and scores.
class_names (list[String]): A list of class names.
pklfile_prefix (str
| None
): The prefix of pkl file.
submission_prefix (str
| None
): The prefix of submission file.
pklfile_prefix (str): The prefix of pkl file.
submission_prefix (str): The prefix of submission file.
Returns:
list[dict]: A list of dictionaries with the kitti format.
...
...
@@ -489,11 +513,11 @@ class KittiDataset(Custom3DDataset):
submission.
Args:
net_outputs (list[np.ndarray]): List of array storing the
\
net_outputs (list[np.ndarray]): List of array storing the
inferenced bounding boxes and scores.
class_names (list[String]): A list of class names.
pklfile_prefix (str
| None
): The prefix of pkl file.
submission_prefix (str
| None
): The prefix of submission file.
pklfile_prefix (str): The prefix of pkl file.
submission_prefix (str): The prefix of submission file.
Returns:
list[dict]: A list of dictionaries have the kitti format
...
...
@@ -607,9 +631,9 @@ class KittiDataset(Custom3DDataset):
dict: Valid predicted boxes.
- bbox (np.ndarray): 2D bounding boxes.
- box3d_camera (np.ndarray): 3D bounding boxes in
\
- box3d_camera (np.ndarray): 3D bounding boxes in
camera coordinate.
- box3d_lidar (np.ndarray): 3D bounding boxes in
\
- box3d_lidar (np.ndarray): 3D bounding boxes in
LiDAR coordinate.
- scores (np.ndarray): Scores of boxes.
- label_preds (np.ndarray): Class label predictions.
...
...
@@ -620,8 +644,6 @@ class KittiDataset(Custom3DDataset):
scores
=
box_dict
[
'scores_3d'
]
labels
=
box_dict
[
'labels_3d'
]
sample_idx
=
info
[
'image'
][
'image_idx'
]
# TODO: remove the hack of yaw
box_preds
.
tensor
[:,
-
1
]
=
box_preds
.
tensor
[:,
-
1
]
-
np
.
pi
box_preds
.
limit_yaw
(
offset
=
0.5
,
period
=
np
.
pi
*
2
)
if
len
(
box_preds
)
==
0
:
...
...
@@ -701,7 +723,8 @@ class KittiDataset(Custom3DDataset):
Args:
results (list[dict]): List of bounding boxes results.
out_dir (str): Output directory of visualization result.
show (bool): Visualize the results online.
show (bool): Whether to visualize the results online.
Default: False.
pipeline (list[dict], optional): raw data loading for showing.
Default: None.
"""
...
...
mmdet3d/datasets/kitti_mono_dataset.py
View file @
32a4328b
# Copyright (c) OpenMMLab. All rights reserved.
import
copy
import
tempfile
from
os
import
path
as
osp
import
mmcv
import
numpy
as
np
import
tempfile
import
torch
from
mmcv.utils
import
print_log
from
os
import
path
as
osp
from
mmdet.datasets
import
DATASETS
from
..core.bbox
import
Box3DMode
,
CameraInstance3DBoxes
,
points_cam2img
...
...
@@ -57,8 +58,8 @@ class KittiMonoDataset(NuScenesMonoDataset):
with_mask (bool): Whether to parse mask annotations.
Returns:
dict: A dict containing the following keys: bboxes, bboxes_ignore,
\
labels, masks, seg_map. "masks" are raw annotations and not
\
dict: A dict containing the following keys: bboxes, bboxes_ignore,
labels, masks, seg_map. "masks" are raw annotations and not
decoded into binary masks.
"""
gt_bboxes
=
[]
...
...
@@ -147,17 +148,17 @@ class KittiMonoDataset(NuScenesMonoDataset):
Args:
outputs (list[dict]): Testing results of the dataset.
pklfile_prefix (str
| None
): The prefix of pkl files. It includes
pklfile_prefix (str): The prefix of pkl files. It includes
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
submission_prefix (str
| None
): The prefix of submitted files. It
submission_prefix (str): The prefix of submitted files. It
includes the file path and the prefix of filename, e.g.,
"a/b/prefix". If not specified, a temp file will be created.
Default: None.
Returns:
tuple: (result_files, tmp_dir), result_files is a dict containing
\
the json filepaths, tmp_dir is the temporal directory created
\
tuple: (result_files, tmp_dir), result_files is a dict containing
the json filepaths, tmp_dir is the temporal directory created
for saving json files when jsonfile_prefix is not specified.
"""
if
pklfile_prefix
is
None
:
...
...
@@ -202,22 +203,26 @@ class KittiMonoDataset(NuScenesMonoDataset):
pklfile_prefix
=
None
,
submission_prefix
=
None
,
show
=
False
,
out_dir
=
None
):
out_dir
=
None
,
pipeline
=
None
):
"""Evaluation in KITTI protocol.
Args:
results (list[dict]): Testing results of the dataset.
metric (str | list[str]): Metrics to be evaluated.
logger (logging.Logger | str | None): Logger used for printing
metric (str | list[str], optional): Metrics to be evaluated.
Defaults to None.
logger (logging.Logger | str, optional): Logger used for printing
related information during evaluation. Default: None.
pklfile_prefix (str
| None
): The prefix of pkl files
. It
includ
es
pklfile_prefix (str
, optional
): The prefix of pkl files
,
includ
ing
the file path and the prefix of filename, e.g., "a/b/prefix".
If not specified, a temp file will be created. Default: None.
submission_prefix (str
| None
): The prefix of submission data
s
.
submission_prefix (str
, optional
): The prefix of submission data.
If not specified, the submission data will not be generated.
show (bool): Whether to visualize.
show (bool
, optional
): Whether to visualize.
Default: False.
out_dir (str): Path to save the visualization results.
out_dir (str, optional): Path to save the visualization results.
Default: None.
pipeline (list[dict], optional): raw data loading for showing.
Default: None.
Returns:
...
...
@@ -255,8 +260,8 @@ class KittiMonoDataset(NuScenesMonoDataset):
if
tmp_dir
is
not
None
:
tmp_dir
.
cleanup
()
if
show
:
self
.
show
(
results
,
out_dir
)
if
show
or
out_dir
:
self
.
show
(
results
,
out_dir
,
show
=
show
,
pipeline
=
pipeline
)
return
ap_dict
def
bbox2result_kitti
(
self
,
...
...
@@ -268,11 +273,11 @@ class KittiMonoDataset(NuScenesMonoDataset):
submission.
Args:
net_outputs (list[np.ndarray]): List of array storing the
\
net_outputs (list[np.ndarray]): List of array storing the
inferenced bounding boxes and scores.
class_names (list[String]): A list of class names.
pklfile_prefix (str
| None
): The prefix of pkl file.
submission_prefix (str
| None
): The prefix of submission file.
pklfile_prefix (str): The prefix of pkl file.
submission_prefix (str): The prefix of submission file.
Returns:
list[dict]: A list of dictionaries with the kitti format.
...
...
@@ -383,11 +388,11 @@ class KittiMonoDataset(NuScenesMonoDataset):
submission.
Args:
net_outputs (list[np.ndarray]): List of array storing the
\
net_outputs (list[np.ndarray]): List of array storing the
inferenced bounding boxes and scores.
class_names (list[String]): A list of class names.
pklfile_prefix (str
| None
): The prefix of pkl file.
submission_prefix (str
| None
): The prefix of submission file.
pklfile_prefix (str): The prefix of pkl file.
submission_prefix (str): The prefix of submission file.
Returns:
list[dict]: A list of dictionaries have the kitti format
...
...
@@ -498,7 +503,7 @@ class KittiMonoDataset(NuScenesMonoDataset):
Returns:
dict: Valid predicted boxes.
- bbox (np.ndarray): 2D bounding boxes.
- box3d_camera (np.ndarray): 3D bounding boxes in
\
- box3d_camera (np.ndarray): 3D bounding boxes in
camera coordinate.
- scores (np.ndarray): Scores of boxes.
- label_preds (np.ndarray): Class label predictions.
...
...
Prev
1
…
5
6
7
8
9
10
11
12
13
…
21
Next
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