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
75d96044
Commit
75d96044
authored
May 08, 2020
by
zhangwenwei
Browse files
Add CAM box
parent
435fe45b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
256 additions
and
92 deletions
+256
-92
mmdet3d/core/bbox/structures/base_box3d.py
mmdet3d/core/bbox/structures/base_box3d.py
+64
-9
mmdet3d/core/bbox/structures/box_3d_mode.py
mmdet3d/core/bbox/structures/box_3d_mode.py
+7
-1
mmdet3d/core/bbox/structures/cam_box3d.py
mmdet3d/core/bbox/structures/cam_box3d.py
+157
-0
mmdet3d/core/bbox/structures/lidar_box3d.py
mmdet3d/core/bbox/structures/lidar_box3d.py
+28
-82
No files found.
mmdet3d/core/bbox/structures/base_box3d.py
View file @
75d96044
from
abc
import
abstractmethod
import
numpy
as
np
import
torch
from
.utils
import
limit_period
class
BaseInstance3DBoxes
(
object
):
"""Base class for 3D Boxes
...
...
@@ -36,6 +39,36 @@ class BaseInstance3DBoxes(object):
"""
return
self
.
tensor
[:,
3
]
*
self
.
tensor
[:,
4
]
*
self
.
tensor
[:,
5
]
@
property
def
dims
(
self
):
"""Calculate the length in each dimension of all the boxes.
Convert the boxes to the form of (x_size, y_size, z_size)
Returns:
torch.Tensor: corners of each box with size (N, 8, 3)
"""
return
self
.
tensor
[:,
3
:
6
]
@
property
def
center
(
self
):
"""Calculate the center of all the boxes.
Note:
In the MMDetection.3D's convention, the bottom center is
usually taken as the default center.
The relative position of the centers in different kinds of
boxes are different, e.g., the relative center of a boxes is
[0.5, 1.0, 0.5] in camera and [0.5, 0.5, 0] in lidar.
It is recommended to use `bottom_center` or `gravity_center`
for more clear usage.
Returns:
torch.Tensor: a tensor with center of each box.
"""
return
self
.
bottom_center
@
property
def
bottom_center
(
self
):
"""Calculate the bottom center of all the boxes.
...
...
@@ -43,7 +76,7 @@ class BaseInstance3DBoxes(object):
Returns:
torch.Tensor: a tensor with center of each box.
"""
return
self
.
tensor
[
...
,
:
3
]
return
self
.
tensor
[
:
,
:
3
]
@
property
def
gravity_center
(
self
):
...
...
@@ -79,16 +112,17 @@ class BaseInstance3DBoxes(object):
"""
pass
@
abstractmethod
def
translate
(
self
,
trans_vector
):
"""Calculate whether the points is in any of the boxes
Args:
trans_vector (torch.Tensor): translation vector of size 1x3
"""
pass
if
not
isinstance
(
trans_vector
,
torch
.
Tensor
):
trans_vector
=
self
.
tensor
.
new_tensor
(
trans_vector
)
self
.
tensor
[:,
:
3
]
+=
trans_vector
@
abstractmethod
def
in_range_3d
(
self
,
box_range
):
"""Check whether the boxes are in the given range
...
...
@@ -96,11 +130,23 @@ class BaseInstance3DBoxes(object):
box_range (list | torch.Tensor): the range of box
(x_min, y_min, z_min, x_max, y_max, z_max)
Note:
In the original implementation of SECOND, checking whether
a box in the range checks whether the points are in a convex
polygon, we try to reduce the burdun for simpler cases.
TODO: check whether this will effect the performance
Returns:
a binary vector, indicating whether each box is inside
the reference range.
"""
pass
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
box_range
[
0
])
&
(
self
.
tensor
[:,
1
]
>
box_range
[
1
])
&
(
self
.
tensor
[:,
2
]
>
box_range
[
2
])
&
(
self
.
tensor
[:,
0
]
<
box_range
[
3
])
&
(
self
.
tensor
[:,
1
]
<
box_range
[
4
])
&
(
self
.
tensor
[:,
2
]
<
box_range
[
5
]))
return
in_range_flags
@
abstractmethod
def
in_range_bev
(
self
,
box_range
):
...
...
@@ -116,15 +162,24 @@ class BaseInstance3DBoxes(object):
"""
pass
@
abstractmethod
def
scale
(
self
,
scale_factors
):
def
scale
(
self
,
scale_factor
):
"""Scale the box with horizontal and vertical scaling factors
Args:
scale_factors (float
| torch.Tensor | list[float]
):
scale_factors (float):
scale factors to scale the boxes.
"""
pass
self
.
tensor
[:,
:
6
]
*=
scale_factor
self
.
tensor
[:,
7
:]
*=
scale_factor
def
limit_yaw
(
self
,
offset
=
0.5
,
period
=
np
.
pi
):
"""Limit the yaw to a given period and offset
Args:
offset (float): the offset of the yaw
period (float): the expected period
"""
self
.
tensor
[:,
6
]
=
limit_period
(
self
.
tensor
[:,
6
],
offset
,
period
)
def
nonempty
(
self
,
threshold
:
float
=
0.0
):
"""Find boxes that are non-empty.
...
...
mmdet3d/core/bbox/structures/box_3d_mode.py
View file @
75d96044
...
...
@@ -8,13 +8,15 @@ import torch
class
Box3DMode
(
IntEnum
):
r
"""Enum of different ways to represent a box.
Coordinates in
velodyne/LiDAR sensors
:
Coordinates in
LiDAR
:
.. code-block:: none
up z x front
^ ^
| /
| /
left y <------ 0
The relative coordinate of bottom center in a LiDAR box is [0.5, 0.5, 0],
and the yaw is around the z axis, thus the rotation axis=2.
Coordinates in camera:
.. code-block:: none
...
...
@@ -26,6 +28,8 @@ class Box3DMode(IntEnum):
|
v
down y
The relative coordinate of bottom center in a CAM box is [0.5, 1.0, 0.5],
and the yaw is around the y axis, thus the rotation axis=1.
Coordinates in Depth mode:
.. code-block:: none
...
...
@@ -34,6 +38,8 @@ class Box3DMode(IntEnum):
| /
| /
front y <------ 0
The relative coordinate of bottom center in a DEPTH box is [0.5, 0.5, 0],
and the yaw is around the z axis, thus the rotation axis=2.
"""
LIDAR
=
0
...
...
mmdet3d/core/bbox/structures/cam_box3d.py
0 → 100644
View file @
75d96044
import
numpy
as
np
import
torch
from
.base_box3d
import
BaseInstance3DBoxes
from
.utils
import
limit_period
,
rotation_3d_in_axis
class
CAMInstance3DBoxes
(
BaseInstance3DBoxes
):
"""3D boxes of instances in CAM coordinates
Coordinates in camera:
.. code-block:: none
x right
/
/
front z <------ 0
|
|
v
down y
The relative coordinate of bottom center in a CAM box is [0.5, 1.0, 0.5],
and the yaw is around the y axis, thus the rotation axis=1.
Attributes:
tensor (torch.Tensor): float matrix of N x box_dim.
box_dim (int): integer indicates the dimension of a box
Each row is (x, y, z, x_size, y_size, z_size, yaw, ...).
"""
@
property
def
gravity_center
(
self
):
"""Calculate the gravity center of all the boxes.
Returns:
torch.Tensor: a tensor with center of each box.
"""
bottom_center
=
self
.
bottom_center
gravity_center
=
torch
.
zeros_like
(
bottom_center
)
gravity_center
[:,
[
0
,
2
]]
=
bottom_center
[:,
[
0
,
2
]]
gravity_center
[:,
1
]
=
bottom_center
[:,
1
]
-
self
.
tensor
[:,
5
]
*
0.5
return
gravity_center
@
property
def
corners
(
self
):
"""Calculate the coordinates of corners of all the boxes.
Convert the boxes to in clockwise order, in the form of
(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z0, x1y1z1)
.. code-block:: none
front z
/
/
(x0, y0, z1) + ----------- + (x1, y0, z1)
/| / |
/ | / |
(x0, y0, z0) + ----------- + + (x1, y1, z0)
| / . | /
| / oriign | /
(x0, y1, z0) + ----------- + -------> x right
| (x1, y1, z0)
|
v
down y
Returns:
torch.Tensor: corners of each box with size (N, 8, 3)
"""
dims
=
self
.
dims
corners_norm
=
torch
.
from_numpy
(
np
.
stack
(
np
.
unravel_index
(
np
.
arange
(
8
),
[
2
]
*
3
),
axis
=
1
)).
to
(
device
=
dims
.
device
,
dtype
=
dims
.
dtype
)
corners_norm
=
corners_norm
[[
0
,
1
,
3
,
2
,
4
,
5
,
7
,
6
]]
# use relative origin [0.5, 1, 0.5]
corners_norm
=
corners_norm
-
dims
.
new_tensor
([
0.5
,
1
,
0.5
])
corners
=
dims
.
view
([
-
1
,
1
,
3
])
*
corners_norm
.
reshape
([
1
,
8
,
3
])
# rotate around y axis
corners
=
rotation_3d_in_axis
(
corners
,
self
.
tensor
[:,
6
],
axis
=
1
)
corners
+=
self
.
tensor
[:,
:
3
].
view
(
-
1
,
1
,
3
)
return
corners
@
property
def
nearset_bev
(
self
):
"""Calculate the 2D bounding boxes in BEV without rotation
Returns:
torch.Tensor: a tensor of 2D BEV box of each box.
"""
# Obtain BEV boxes with rotation in XZWHR format
bev_rotated_boxes
=
self
.
tensor
[:,
[
0
,
2
,
3
,
5
,
6
]]
# convert the rotation to a valid range
rotations
=
bev_rotated_boxes
[:,
-
1
]
normed_rotations
=
torch
.
abs
(
limit_period
(
rotations
,
0.5
,
np
.
pi
))
# find the center of boxes
conditions
=
(
normed_rotations
>
np
.
pi
/
4
)[...,
None
]
bboxes_xywh
=
torch
.
where
(
conditions
,
bev_rotated_boxes
[:,
[
0
,
1
,
3
,
2
]],
bev_rotated_boxes
[:,
:
4
])
centers
=
bboxes_xywh
[:,
:
2
]
dims
=
bboxes_xywh
[:,
2
:]
bev_boxes
=
torch
.
cat
([
centers
-
dims
/
2
,
centers
+
dims
/
2
],
dim
=-
1
)
return
bev_boxes
def
rotate
(
self
,
angle
):
"""Calculate whether the points is in any of the boxes
Args:
angles (float | torch.Tensor): rotation angle
Returns:
None if `return_rot_mat=False`,
torch.Tensor if `return_rot_mat=True`
"""
if
not
isinstance
(
angle
,
torch
.
Tensor
):
angle
=
self
.
tensor
.
new_tensor
(
angle
)
rot_sin
=
torch
.
sin
(
angle
)
rot_cos
=
torch
.
cos
(
angle
)
rot_mat_T
=
self
.
tensor
.
new_tensor
([[
rot_cos
,
0
,
-
rot_sin
],
[
0
,
1
,
0
],
[
rot_sin
,
0
,
rot_cos
]])
self
.
tensor
[:,
:
3
]
=
self
.
tensor
[:,
:
3
]
@
rot_mat_T
self
.
tensor
[:,
6
]
+=
angle
def
flip
(
self
):
"""Flip the boxes in horizontal direction
In CAM coordinates, it flips the x axis.
"""
self
.
tensor
[:,
0
::
7
]
=
-
self
.
tensor
[:,
0
::
7
]
self
.
tensor
[:,
6
]
=
-
self
.
tensor
[:,
6
]
+
np
.
pi
def
in_range_bev
(
self
,
box_range
):
"""Check whether the boxes are in the given range
Args:
box_range (list | torch.Tensor): the range of box
(x_min, z_min, x_max, z_max)
Note:
In the original implementation of SECOND, checking whether
a box in the range checks whether the points are in a convex
polygon, we try to reduce the burdun for simpler cases.
TODO: check whether this will effect the performance
Returns:
a binary vector, indicating whether each box is inside
the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
box_range
[
0
])
&
(
self
.
tensor
[:,
2
]
>
box_range
[
1
])
&
(
self
.
tensor
[:,
0
]
<
box_range
[
2
])
&
(
self
.
tensor
[:,
2
]
<
box_range
[
3
]))
return
in_range_flags
mmdet3d/core/bbox/structures/lidar_box3d.py
View file @
75d96044
...
...
@@ -8,13 +8,15 @@ from .utils import limit_period, rotation_3d_in_axis
class
LiDARInstance3DBoxes
(
BaseInstance3DBoxes
):
"""3D boxes of instances in LIDAR coordinates
This structure stores a list of boxes as a NxM torch.Tensor,
where M >= 7.
It supports some common methods about boxes
(`area`, `clip`, `nonempty`, etc),
and also behaves like a Tensor
(support indexing, `to(device)`, `.device`, and iteration over all boxes)
By default the (x, y, z) is the bottom center of a box
Coordinates in LiDAR:
.. code-block:: none
up z x front
^ ^
| /
| /
left y <------ 0
The relative coordinate of bottom center in a LiDAR box is [0.5, 0.5, 0],
and the yaw is around the z axis, thus the rotation axis=2.
Attributes:
tensor (torch.Tensor): float matrix of N x box_dim.
...
...
@@ -39,18 +41,22 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
def
corners
(
self
):
"""Calculate the coordinates of corners of all the boxes.
Convert the boxes to
the
form of
Convert the boxes to
corners in clockwise order, in
form of
(x0y0z0, x0y0z1, x0y1z1, x0y1z0, x1y0z0, x1y0z1, x1y1z0, x1y1z1)
.. code-block:: none
(x0, y0, z1) + ----------- + (x1, y1, z1)
/| / |
/ | / |
(x0, y0, z1) + ----------- + + (x1, y1, z0)
| / . | /
| / oriign | /
(x0, y0, z0) + ----------- + (x1, y0, z0)
up z
front x ^
/ |
/ |
(x1, y0, z1) + ----------- + (x1, y1, z1)
/| / |
/ | / |
(x0, y0, z1) + ----------- + + (x1, y1, z0)
| / . | /
| / oriign | /
left y<-------- + ----------- + (x0, y1, z0)
(x0, y0, z0)
Returns:
torch.Tensor: corners of each box with size (N, 8, 3)
"""
...
...
@@ -60,24 +66,15 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
device
=
dims
.
device
,
dtype
=
dims
.
dtype
)
corners_norm
=
corners_norm
[[
0
,
1
,
3
,
2
,
4
,
5
,
7
,
6
]]
# use relative origin [0.5, 0.5, 0]
corners_norm
=
corners_norm
-
dims
.
new_tensor
([
0.5
,
0.5
,
0
])
corners
=
dims
.
view
([
-
1
,
1
,
3
])
*
corners_norm
.
reshape
([
1
,
8
,
3
])
# rotate around z axis
corners
=
rotation_3d_in_axis
(
corners
,
self
.
tensor
[:,
6
],
axis
=
2
)
corners
+=
self
.
tensor
[:,
:
3
].
view
(
-
1
,
1
,
3
)
return
corners
@
property
def
dims
(
self
):
"""Calculate the length in each dimension of all the boxes.
Convert the boxes to the form of (x_size, y_size, z_size)
Returns:
torch.Tensor: corners of each box with size (N, 8, 3)
"""
return
self
.
tensor
[:,
3
:
6
]
@
property
def
nearset_bev
(
self
):
"""Calculate the 2D bounding boxes in BEV without rotation
...
...
@@ -123,44 +120,12 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
self
.
tensor
[:,
6
]
+=
angle
def
flip
(
self
):
self
.
tensor
[:,
1
::
7
]
=
-
self
.
tensor
[:,
1
::
7
]
self
.
tensor
[:,
6
]
=
-
self
.
tensor
[:,
6
]
+
np
.
pi
def
translate
(
self
,
trans_vector
):
"""Calculate whether the points is in any of the boxes
Args:
trans_vector (torch.Tensor): translation vector of size 1x3
"""Flip the boxes in horizontal direction
In LIDAR coordinates, it flips the y axis.
"""
if
not
isinstance
(
trans_vector
,
torch
.
Tensor
):
trans_vector
=
self
.
tensor
.
new_tensor
(
trans_vector
)
self
.
tensor
[:,
:
3
]
+=
trans_vector
def
in_range_3d
(
self
,
box_range
):
"""Check whether the boxes are in the given range
Args:
box_range (list | torch.Tensor): the range of box
(x_min, y_min, z_min, x_max, y_max, z_max)
Note:
In the original implementation of SECOND, checking whether
a box in the range checks whether the points are in a convex
polygon, we try to reduce the burdun for simpler cases.
TODO: check whether this will effect the performance
Returns:
a binary vector, indicating whether each box is inside
the reference range.
"""
in_range_flags
=
((
self
.
tensor
[:,
0
]
>
box_range
[
0
])
&
(
self
.
tensor
[:,
1
]
>
box_range
[
1
])
&
(
self
.
tensor
[:,
2
]
>
box_range
[
2
])
&
(
self
.
tensor
[:,
0
]
<
box_range
[
3
])
&
(
self
.
tensor
[:,
1
]
<
box_range
[
4
])
&
(
self
.
tensor
[:,
2
]
<
box_range
[
5
]))
return
in_range_flags
self
.
tensor
[:,
1
::
7
]
=
-
self
.
tensor
[:,
1
::
7
]
self
.
tensor
[:,
6
]
=
-
self
.
tensor
[:,
6
]
+
np
.
pi
def
in_range_bev
(
self
,
box_range
):
"""Check whether the boxes are in the given range
...
...
@@ -184,22 +149,3 @@ class LiDARInstance3DBoxes(BaseInstance3DBoxes):
&
(
self
.
tensor
[:,
0
]
<
box_range
[
2
])
&
(
self
.
tensor
[:,
1
]
<
box_range
[
3
]))
return
in_range_flags
def
scale
(
self
,
scale_factor
):
"""Scale the box with horizontal and vertical scaling factors
Args:
scale_factors (float):
scale factors to scale the boxes.
"""
self
.
tensor
[:,
:
6
]
*=
scale_factor
self
.
tensor
[:,
7
:]
*=
scale_factor
def
limit_yaw
(
self
,
offset
=
0.5
,
period
=
np
.
pi
):
"""Limit the yaw to a given period and offset
Args:
offset (float): the offset of the yaw
period (float): the expected period
"""
self
.
tensor
[:,
6
]
=
limit_period
(
self
.
tensor
[:,
6
],
offset
,
period
)
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