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
31b3505d
"test/vscode:/vscode.git/clone" did not exist on "6cb4fc21c2cd2f9bbc59b42bae64831cecdb45a4"
Commit
31b3505d
authored
Jul 10, 2020
by
wuyuefeng
Committed by
zhangwenwei
Jul 10, 2020
Browse files
Core unittest
parent
ce4f66b6
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
412 additions
and
16 deletions
+412
-16
docs/benchmarks.md
docs/benchmarks.md
+70
-0
mmdet3d/core/bbox/box_np_ops.py
mmdet3d/core/bbox/box_np_ops.py
+211
-14
mmdet3d/core/evaluation/kitti_utils/eval.py
mmdet3d/core/evaluation/kitti_utils/eval.py
+22
-0
mmdet3d/core/evaluation/kitti_utils/rotate_iou.py
mmdet3d/core/evaluation/kitti_utils/rotate_iou.py
+41
-2
tests/test_box_np_ops.py
tests/test_box_np_ops.py
+68
-0
No files found.
docs/benchmarks.md
View file @
31b3505d
...
@@ -129,6 +129,76 @@ We compare the training speed (samples/s) with other codebases if they implement
...
@@ -129,6 +129,76 @@ We compare the training speed (samples/s) with other codebases if they implement
python train.py
--dataset
sunrgbd
--batch_size
16
python train.py
--dataset
sunrgbd
--batch_size
16
```
```
Then benchmark the test speed by running
```
bash
python eval.py
--dataset
sunrgbd
--checkpoint_path
log_sunrgbd/checkpoint.tar
--batch_size
1
--dump_dir
eval_sunrgbd
--cluster_sampling
seed_fps
--use_3d_nms
--use_cls_nms
--per_class_proposal
```
Note that eval.py is modified to compute inference time.
<details>
<summary>
(diff to benchmark the similar models - click to expand)
</summary>
```
diff
diff --git a/eval.py b/eval.py
index c0b2886..04921e9 100644
--- a/eval.py
+++ b/eval.py
@@ -10,6 +10,7 @@ import os
import sys
import numpy as np
from datetime import datetime
+import time
import argparse
import importlib
import torch
@@ -28,7 +29,7 @@ parser.add_argument('--checkpoint_path', default=None, help='Model checkpoint pa
parser.add_argument('--dump_dir', default=None, help='Dump dir to save sample outputs [default: None]')
parser.add_argument('--num_point', type=int, default=20000, help='Point Number [default: 20000]')
parser.add_argument('--num_target', type=int, default=256, help='Point Number [default: 256]')
-parser.add_argument('--batch_size', type=int, default=8, help='Batch Size during training [default: 8]')
+parser.add_argument('--batch_size', type=int, default=1, help='Batch Size during training [default: 8]')
parser.add_argument('--vote_factor', type=int, default=1, help='Number of votes generated from each seed [default: 1]')
parser.add_argument('--cluster_sampling', default='vote_fps', help='Sampling strategy for vote clusters: vote_fps, seed_fps, random [default: vote_fps]')
parser.add_argument('--ap_iou_thresholds', default='0.25,0.5', help='A list of AP IoU thresholds [default: 0.25,0.5]')
@@ -132,6 +133,7 @@ CONFIG_DICT = {'remove_empty_box': (not FLAGS.faster_eval), 'use_3d_nms': FLAGS.
# ------------------------------------------------------------------------- GLOBAL CONFIG END
def evaluate_one_epoch():
+ time_list = list()
stat_dict = {}
ap_calculator_list = [APCalculator(iou_thresh, DATASET_CONFIG.class2type) \
for iou_thresh in AP_IOU_THRESHOLDS]
@@ -144,6 +146,8 @@ def evaluate_one_epoch():
# Forward pass
inputs = {'point_clouds': batch_data_label['point_clouds']}
+ torch.cuda.synchronize()
+ start_time = time.perf_counter()
with torch.no_grad():
end_points = net(inputs)
@@ -161,6 +165,12 @@ def evaluate_one_epoch():
batch_pred_map_cls = parse_predictions(end_points, CONFIG_DICT)
batch_gt_map_cls = parse_groundtruths(end_points, CONFIG_DICT)
+ torch.cuda.synchronize()
+ elapsed = time.perf_counter() - start_time
+ time_list.append(elapsed)
+
+ if len(time_list==200):
+ print("average inference time: %4f"%(sum(time_list[5:])/len(time_list[5:])))
for ap_calculator in ap_calculator_list:
ap_calculator.step(batch_pred_map_cls, batch_gt_map_cls)
```
### PointPillars-car
### PointPillars-car
*
__MMDetection3D__: With release v0.1.0, run
*
__MMDetection3D__: With release v0.1.0, run
...
...
mmdet3d/core/bbox/box_np_ops.py
View file @
31b3505d
...
@@ -6,6 +6,18 @@ import numpy as np
...
@@ -6,6 +6,18 @@ import numpy as np
def
camera_to_lidar
(
points
,
r_rect
,
velo2cam
):
def
camera_to_lidar
(
points
,
r_rect
,
velo2cam
):
"""Convert points in camera coordinate to lidar coordinate.
Args:
points (np.ndarray, shape=[N, 3]): Points in camera coordinate.
r_rect (np.ndarray, shape=[4, 4]): Matrix to project points in
specific camera coordinate (e.g. CAM2) to CAM0.
velo2cam (np.ndarray, shape=[4, 4]): Matrix to project points in
camera coordinate to lidar coordinate.
Returns:
np.ndarray, shape=[N, 3]: Points in lidar coordinate.
"""
points_shape
=
list
(
points
.
shape
[
0
:
-
1
])
points_shape
=
list
(
points
.
shape
[
0
:
-
1
])
if
points
.
shape
[
-
1
]
==
3
:
if
points
.
shape
[
-
1
]
==
3
:
points
=
np
.
concatenate
([
points
,
np
.
ones
(
points_shape
+
[
1
])],
axis
=-
1
)
points
=
np
.
concatenate
([
points
,
np
.
ones
(
points_shape
+
[
1
])],
axis
=-
1
)
...
@@ -14,6 +26,18 @@ def camera_to_lidar(points, r_rect, velo2cam):
...
@@ -14,6 +26,18 @@ def camera_to_lidar(points, r_rect, velo2cam):
def
box_camera_to_lidar
(
data
,
r_rect
,
velo2cam
):
def
box_camera_to_lidar
(
data
,
r_rect
,
velo2cam
):
"""Covert boxes in camera coordinate to lidar coordinate.
Args:
data (np.ndarray, shape=[N, 7]): Boxes in camera coordinate.
r_rect (np.ndarray, shape=[4, 4]): Matrix to project points in
specific camera coordinate (e.g. CAM2) to CAM0.
velo2cam (np.ndarray, shape=[4, 4]): Matrix to project points in
camera coordinate to lidar coordinate.
Returns:
np.ndarray, shape=[N, 3]: Boxes in lidar coordinate.
"""
xyz
=
data
[:,
0
:
3
]
xyz
=
data
[:,
0
:
3
]
l
,
h
,
w
=
data
[:,
3
:
4
],
data
[:,
4
:
5
],
data
[:,
5
:
6
]
l
,
h
,
w
=
data
[:,
3
:
4
],
data
[:,
4
:
5
],
data
[:,
5
:
6
]
r
=
data
[:,
6
:
7
]
r
=
data
[:,
6
:
7
]
...
@@ -96,6 +120,16 @@ def center_to_corner_box2d(centers, dims, angles=None, origin=0.5):
...
@@ -96,6 +120,16 @@ def center_to_corner_box2d(centers, dims, angles=None, origin=0.5):
@
numba
.
jit
(
nopython
=
True
)
@
numba
.
jit
(
nopython
=
True
)
def
depth_to_points
(
depth
,
trunc_pixel
):
def
depth_to_points
(
depth
,
trunc_pixel
):
"""Convert depth map to points.
Args:
depth (np.array, shape=[H, W]): Depth map which
the row of [0~`trunc_pixel`] are truncated.
trunc_pixel (int): The number of truncated row.
Returns:
np.ndarray: Points in camera coordinates.
"""
num_pts
=
np
.
sum
(
depth
[
trunc_pixel
:,
]
>
0.1
)
num_pts
=
np
.
sum
(
depth
[
trunc_pixel
:,
]
>
0.1
)
points
=
np
.
zeros
((
num_pts
,
3
),
dtype
=
depth
.
dtype
)
points
=
np
.
zeros
((
num_pts
,
3
),
dtype
=
depth
.
dtype
)
x
=
np
.
array
([
0
,
0
,
1
],
dtype
=
depth
.
dtype
)
x
=
np
.
array
([
0
,
0
,
1
],
dtype
=
depth
.
dtype
)
...
@@ -110,6 +144,21 @@ def depth_to_points(depth, trunc_pixel):
...
@@ -110,6 +144,21 @@ def depth_to_points(depth, trunc_pixel):
def
depth_to_lidar_points
(
depth
,
trunc_pixel
,
P2
,
r_rect
,
velo2cam
):
def
depth_to_lidar_points
(
depth
,
trunc_pixel
,
P2
,
r_rect
,
velo2cam
):
"""Convert depth map to points in lidar coordinate.
Args:
depth (np.array, shape=[H, W]): Depth map which
the row of [0~`trunc_pixel`] are truncated.
trunc_pixel (int): The number of truncated row.
P2 (p.array, shape=[4, 4]): Intrinsics of Camera2.
r_rect (np.ndarray, shape=[4, 4]): Matrix to project points in
specific camera coordinate (e.g. CAM2) to CAM0.
velo2cam (np.ndarray, shape=[4, 4]): Matrix to project points in
camera coordinate to lidar coordinate.
Returns:
np.ndarray: Points in lidar coordinates.
"""
pts
=
depth_to_points
(
depth
,
trunc_pixel
)
pts
=
depth_to_points
(
depth
,
trunc_pixel
)
points_shape
=
list
(
pts
.
shape
[
0
:
-
1
])
points_shape
=
list
(
pts
.
shape
[
0
:
-
1
])
points
=
np
.
concatenate
([
pts
,
np
.
ones
(
points_shape
+
[
1
])],
axis
=-
1
)
points
=
np
.
concatenate
([
pts
,
np
.
ones
(
points_shape
+
[
1
])],
axis
=-
1
)
...
@@ -119,6 +168,16 @@ def depth_to_lidar_points(depth, trunc_pixel, P2, r_rect, velo2cam):
...
@@ -119,6 +168,16 @@ def depth_to_lidar_points(depth, trunc_pixel, P2, r_rect, velo2cam):
def
rotation_3d_in_axis
(
points
,
angles
,
axis
=
0
):
def
rotation_3d_in_axis
(
points
,
angles
,
axis
=
0
):
"""Rotate points in specific axis.
Args:
points (np.ndarray, shape=[N, point_size, 3]]):
angles (np.ndarray, shape=[N]]):
axis (int): Axis to rotate at.
Returns:
np.ndarray: Rotated points.
"""
# points: [N, point_size, 3]
# points: [N, point_size, 3]
rot_sin
=
np
.
sin
(
angles
)
rot_sin
=
np
.
sin
(
angles
)
rot_cos
=
np
.
cos
(
angles
)
rot_cos
=
np
.
cos
(
angles
)
...
@@ -170,6 +229,14 @@ def center_to_corner_box3d(centers,
...
@@ -170,6 +229,14 @@ def center_to_corner_box3d(centers,
@
numba
.
jit
(
nopython
=
True
)
@
numba
.
jit
(
nopython
=
True
)
def
box2d_to_corner_jit
(
boxes
):
def
box2d_to_corner_jit
(
boxes
):
"""Convert box2d to corner.
Args:
boxes (np.ndarray, shape=[N, 5]): Boxes2d with rotation.
Returns:
box_corners (np.ndarray, shape=[N, 4, 2]): Box corners.
"""
num_box
=
boxes
.
shape
[
0
]
num_box
=
boxes
.
shape
[
0
]
corners_norm
=
np
.
zeros
((
4
,
2
),
dtype
=
boxes
.
dtype
)
corners_norm
=
np
.
zeros
((
4
,
2
),
dtype
=
boxes
.
dtype
)
corners_norm
[
1
,
1
]
=
1.0
corners_norm
[
1
,
1
]
=
1.0
...
@@ -193,6 +260,14 @@ def box2d_to_corner_jit(boxes):
...
@@ -193,6 +260,14 @@ def box2d_to_corner_jit(boxes):
@
numba
.
njit
@
numba
.
njit
def
corner_to_standup_nd_jit
(
boxes_corner
):
def
corner_to_standup_nd_jit
(
boxes_corner
):
"""Convert boxes_corner to aligned (min-max) boxes.
Args:
boxes_corner (np.ndarray, shape=[N, 2**dim, dim]): Boxes corners.
Returns:
np.ndarray, shape=[N, dim*2]: Aligned (min-max) boxes.
"""
num_boxes
=
boxes_corner
.
shape
[
0
]
num_boxes
=
boxes_corner
.
shape
[
0
]
ndim
=
boxes_corner
.
shape
[
-
1
]
ndim
=
boxes_corner
.
shape
[
-
1
]
result
=
np
.
zeros
((
num_boxes
,
ndim
*
2
),
dtype
=
boxes_corner
.
dtype
)
result
=
np
.
zeros
((
num_boxes
,
ndim
*
2
),
dtype
=
boxes_corner
.
dtype
)
...
@@ -229,6 +304,16 @@ def corner_to_surfaces_3d_jit(corners):
...
@@ -229,6 +304,16 @@ def corner_to_surfaces_3d_jit(corners):
def
rotation_points_single_angle
(
points
,
angle
,
axis
=
0
):
def
rotation_points_single_angle
(
points
,
angle
,
axis
=
0
):
"""Rotate points with a single angle.
Args:
points (np.ndarray, shape=[N, 3]]):
angles (np.ndarray, shape=[1]]):
axis (int): Axis to rotate at.
Returns:
np.ndarray: Rotated points.
"""
# points: [N, 3]
# points: [N, 3]
rot_sin
=
np
.
sin
(
angle
)
rot_sin
=
np
.
sin
(
angle
)
rot_cos
=
np
.
cos
(
angle
)
rot_cos
=
np
.
cos
(
angle
)
...
@@ -251,6 +336,15 @@ def rotation_points_single_angle(points, angle, axis=0):
...
@@ -251,6 +336,15 @@ def rotation_points_single_angle(points, angle, axis=0):
def
points_cam2img
(
points_3d
,
proj_mat
):
def
points_cam2img
(
points_3d
,
proj_mat
):
"""Project points in camera coordinates to image coordinates.
Args:
points_3d (np.ndarray): Points in shape (N, 3)
proj_mat (np.ndarray): Transformation matrix between coordinates.
Returns:
np.ndarray: Points in image coordinates with shape [N, 2].
"""
points_shape
=
list
(
points_3d
.
shape
)
points_shape
=
list
(
points_3d
.
shape
)
points_shape
[
-
1
]
=
1
points_shape
[
-
1
]
=
1
points_4
=
np
.
concatenate
([
points_3d
,
np
.
zeros
(
points_shape
)],
axis
=-
1
)
points_4
=
np
.
concatenate
([
points_3d
,
np
.
zeros
(
points_shape
)],
axis
=-
1
)
...
@@ -259,7 +353,16 @@ def points_cam2img(points_3d, proj_mat):
...
@@ -259,7 +353,16 @@ def points_cam2img(points_3d, proj_mat):
return
point_2d_res
return
point_2d_res
def
box3d_to_bbox
(
box3d
,
rect
,
Trv2c
,
P2
):
def
box3d_to_bbox
(
box3d
,
P2
):
"""Convert box3d in camera coordinates to bbox in image coordinates.
Args:
box3d (np.ndarray, shape=[N, 7]): Boxes in camera coordinate.
P2 (np.array, shape=[4, 4]): Intrinsics of Camera2.
Returns:
np.ndarray, shape=[N, 4]: Boxes 2d in image coordinates.
"""
box_corners
=
center_to_corner_box3d
(
box_corners
=
center_to_corner_box3d
(
box3d
[:,
:
3
],
box3d
[:,
3
:
6
],
box3d
[:,
6
],
[
0.5
,
1.0
,
0.5
],
axis
=
1
)
box3d
[:,
:
3
],
box3d
[:,
3
:
6
],
box3d
[:,
6
],
[
0.5
,
1.0
,
0.5
],
axis
=
1
)
box_corners_in_image
=
points_cam2img
(
box_corners
,
P2
)
box_corners_in_image
=
points_cam2img
(
box_corners
,
P2
)
...
@@ -293,6 +396,17 @@ def corner_to_surfaces_3d(corners):
...
@@ -293,6 +396,17 @@ def corner_to_surfaces_3d(corners):
def
points_in_rbbox
(
points
,
rbbox
,
z_axis
=
2
,
origin
=
(
0.5
,
0.5
,
0
)):
def
points_in_rbbox
(
points
,
rbbox
,
z_axis
=
2
,
origin
=
(
0.5
,
0.5
,
0
)):
"""Check points in rotated bbox and return indicces.
Args:
points (np.ndarray, shape=[N, 3+dim]): Points to query.
rbbox (np.ndarray, shape=[M, 7]): Boxes3d with rotation.
z_axis (int): Indicate which axis is height.
origin (tuple[int]): Indicate the position of box center.
Returns:
np.ndarray, shape=[N, M]: Indices of points in each box.
"""
# TODO: this function is different from PointCloud3D, be careful
# TODO: this function is different from PointCloud3D, be careful
# when start to use nuscene, check the input
# when start to use nuscene, check the input
rbbox_corners
=
center_to_corner_box3d
(
rbbox_corners
=
center_to_corner_box3d
(
...
@@ -303,6 +417,14 @@ def points_in_rbbox(points, rbbox, z_axis=2, origin=(0.5, 0.5, 0)):
...
@@ -303,6 +417,14 @@ def points_in_rbbox(points, rbbox, z_axis=2, origin=(0.5, 0.5, 0)):
def
minmax_to_corner_2d
(
minmax_box
):
def
minmax_to_corner_2d
(
minmax_box
):
"""Convert minmax box to corners2d.
Args:
minmax_box (np.ndarray, shape=[N, dims]): minmax boxes.
Returns:
np.ndarray: 2d corners of boxes
"""
ndim
=
minmax_box
.
shape
[
-
1
]
//
2
ndim
=
minmax_box
.
shape
[
-
1
]
//
2
center
=
minmax_box
[...,
:
ndim
]
center
=
minmax_box
[...,
:
ndim
]
dims
=
minmax_box
[...,
ndim
:]
-
center
dims
=
minmax_box
[...,
ndim
:]
-
center
...
@@ -310,6 +432,18 @@ def minmax_to_corner_2d(minmax_box):
...
@@ -310,6 +432,18 @@ def minmax_to_corner_2d(minmax_box):
def
limit_period
(
val
,
offset
=
0.5
,
period
=
np
.
pi
):
def
limit_period
(
val
,
offset
=
0.5
,
period
=
np
.
pi
):
"""Limit the value into a period for periodic function.
Args:
val (np.ndarray): The value to be converted.
offset (float, optional): Offset to set the value range.
\
Defaults to 0.5.
period (float, optional): Period of the value. Defaults to np.pi.
Returns:
torch.Tensor: Value in the range of
\
[-offset * period, (1-offset) * period]
"""
return
val
-
np
.
floor
(
val
/
period
+
offset
)
*
period
return
val
-
np
.
floor
(
val
/
period
+
offset
)
*
period
...
@@ -318,7 +452,8 @@ def create_anchors_3d_range(feature_size,
...
@@ -318,7 +452,8 @@ def create_anchors_3d_range(feature_size,
sizes
=
((
1.6
,
3.9
,
1.56
),
),
sizes
=
((
1.6
,
3.9
,
1.56
),
),
rotations
=
(
0
,
np
.
pi
/
2
),
rotations
=
(
0
,
np
.
pi
/
2
),
dtype
=
np
.
float32
):
dtype
=
np
.
float32
):
"""
"""Create anchors 3d by range.
Args:
Args:
feature_size (list[float] | tuple[float]): Feature map size. It is
feature_size (list[float] | tuple[float]): Feature map size. It is
either a list of a tuple of [D, H, W](in order of z, y, and x).
either a list of a tuple of [D, H, W](in order of z, y, and x).
...
@@ -360,13 +495,20 @@ def create_anchors_3d_range(feature_size,
...
@@ -360,13 +495,20 @@ def create_anchors_3d_range(feature_size,
return
np
.
transpose
(
ret
,
[
2
,
1
,
0
,
3
,
4
,
5
])
return
np
.
transpose
(
ret
,
[
2
,
1
,
0
,
3
,
4
,
5
])
def
center_to_minmax_2d
_0_5
(
centers
,
dims
):
def
center_to_minmax_2d
(
centers
,
dims
,
origin
=
0.5
):
return
np
.
concatenate
([
centers
-
dims
/
2
,
centers
+
dims
/
2
],
axis
=-
1
)
"""Center to minmax.
Args:
centers (np.ndarray): Center points.
dims (np.ndarray): Dimensions.
origin (list or array or float): origin point relate to smallest point.
def
center_to_minmax_2d
(
centers
,
dims
,
origin
=
0.5
):
Returns:
np.ndarray: Minmax points.
"""
if
origin
==
0.5
:
if
origin
==
0.5
:
return
center_to_minmax_2d_0_5
(
centers
,
dims
)
return
np
.
concatenate
([
centers
-
dims
/
2
,
centers
+
dims
/
2
],
axis
=-
1
)
corners
=
center_to_corner_box2d
(
centers
,
dims
,
origin
=
origin
)
corners
=
center_to_corner_box2d
(
centers
,
dims
,
origin
=
origin
)
return
corners
[:,
[
0
,
2
]].
reshape
([
-
1
,
4
])
return
corners
[:,
[
0
,
2
]].
reshape
([
-
1
,
4
])
...
@@ -429,16 +571,20 @@ def iou_jit(boxes, query_boxes, mode='iou', eps=0.0):
...
@@ -429,16 +571,20 @@ def iou_jit(boxes, query_boxes, mode='iou', eps=0.0):
return
overlaps
return
overlaps
def
change_box3d_center_
(
box3d
,
src
,
dst
):
def
projection_matrix_to_CRT_kitti
(
proj
):
dst
=
np
.
array
(
dst
,
dtype
=
box3d
.
dtype
)
"""Split projection matrix of kitti.
src
=
np
.
array
(
src
,
dtype
=
box3d
.
dtype
)
box3d
[...,
:
3
]
+=
box3d
[...,
3
:
6
]
*
(
dst
-
src
)
P = C @ [R|T]
C is upper triangular matrix, so we need to inverse CR and use QR
stable for all kitti camera projection matrix.
Args:
proj (p.array, shape=[4, 4]): Intrinsics of camera.
Returns:
tuple[np.ndarray]: Splited matrix of C, R and T.
"""
def
projection_matrix_to_CRT_kitti
(
proj
):
# P = C @ [R|T]
# C is upper triangular matrix, so we need to inverse CR and use QR
# stable for all kitti camera projection matrix
CR
=
proj
[
0
:
3
,
0
:
3
]
CR
=
proj
[
0
:
3
,
0
:
3
]
CT
=
proj
[
0
:
3
,
3
]
CT
=
proj
[
0
:
3
,
3
]
RinvCinv
=
np
.
linalg
.
inv
(
CR
)
RinvCinv
=
np
.
linalg
.
inv
(
CR
)
...
@@ -450,6 +596,20 @@ def projection_matrix_to_CRT_kitti(proj):
...
@@ -450,6 +596,20 @@ def projection_matrix_to_CRT_kitti(proj):
def
remove_outside_points
(
points
,
rect
,
Trv2c
,
P2
,
image_shape
):
def
remove_outside_points
(
points
,
rect
,
Trv2c
,
P2
,
image_shape
):
"""Remove points which are outside of image.
Args:
points (np.ndarray, shape=[N, 3+dims]): Total points.
rect (np.ndarray, shape=[4, 4]): Matrix to project points in
specific camera coordinate (e.g. CAM2) to CAM0.
Trv2c (np.ndarray, shape=[4, 4]): Matrix to project points in
camera coordinate to lidar coordinate.
P2 (p.array, shape=[4, 4]): Intrinsics of Camera2.
image_shape (list[int]): Shape of image.
Returns:
np.ndarray, shape=[N, 3+dims]: Filtered points.
"""
# 5x faster than remove_outside_points_v1(2ms vs 10ms)
# 5x faster than remove_outside_points_v1(2ms vs 10ms)
C
,
R
,
T
=
projection_matrix_to_CRT_kitti
(
P2
)
C
,
R
,
T
=
projection_matrix_to_CRT_kitti
(
P2
)
image_bbox
=
[
0
,
0
,
image_shape
[
1
],
image_shape
[
0
]]
image_bbox
=
[
0
,
0
,
image_shape
[
1
],
image_shape
[
0
]]
...
@@ -464,6 +624,17 @@ def remove_outside_points(points, rect, Trv2c, P2, image_shape):
...
@@ -464,6 +624,17 @@ def remove_outside_points(points, rect, Trv2c, P2, image_shape):
def
get_frustum
(
bbox_image
,
C
,
near_clip
=
0.001
,
far_clip
=
100
):
def
get_frustum
(
bbox_image
,
C
,
near_clip
=
0.001
,
far_clip
=
100
):
"""Get frustum corners in camera coordinates.
Args:
bbox_image (list[int]): box in image coordinates.
C (np.ndarray): Intrinsics.
near_clip (float): Nearest distance of frustum.
far_clip (float): Farthest distance of frustum.
Returns:
np.ndarray, shape=[8, 3]: coordinates of frustum corners.
"""
fku
=
C
[
0
,
0
]
fku
=
C
[
0
,
0
]
fkv
=
-
C
[
1
,
1
]
fkv
=
-
C
[
1
,
1
]
u0v0
=
C
[
0
:
2
,
2
]
u0v0
=
C
[
0
:
2
,
2
]
...
@@ -484,6 +655,17 @@ def get_frustum(bbox_image, C, near_clip=0.001, far_clip=100):
...
@@ -484,6 +655,17 @@ def get_frustum(bbox_image, C, near_clip=0.001, far_clip=100):
def
surface_equ_3d
(
polygon_surfaces
):
def
surface_equ_3d
(
polygon_surfaces
):
"""
Args:
polygon_surfaces (np.ndarray): Polygon surfaces with shape of
[num_polygon, max_num_surfaces, max_num_points_of_surface, 3].
All surfaces' normal vector must direct to internal.
Max_num_points_of_surface must at least 3.
Returns:
tuple: normal vector and its direction.
"""
# return [a, b, c], d in ax+by+cz+d=0
# return [a, b, c], d in ax+by+cz+d=0
# polygon_surfaces: [num_polygon, num_surfaces, num_points_of_polygon, 3]
# polygon_surfaces: [num_polygon, num_surfaces, num_points_of_polygon, 3]
surface_vec
=
polygon_surfaces
[:,
:,
:
2
,
:]
-
\
surface_vec
=
polygon_surfaces
[:,
:,
:
2
,
:]
-
\
...
@@ -499,6 +681,21 @@ def surface_equ_3d(polygon_surfaces):
...
@@ -499,6 +681,21 @@ def surface_equ_3d(polygon_surfaces):
@
numba
.
njit
@
numba
.
njit
def
_points_in_convex_polygon_3d_jit
(
points
,
polygon_surfaces
,
normal_vec
,
d
,
def
_points_in_convex_polygon_3d_jit
(
points
,
polygon_surfaces
,
normal_vec
,
d
,
num_surfaces
):
num_surfaces
):
"""
Args:
points (np.ndarray): Input points with shape of (num_points, 3).
polygon_surfaces (np.ndarray): Polygon surfaces with shape of
(num_polygon, max_num_surfaces, max_num_points_of_surface, 3).
All surfaces' normal vector must direct to internal.
Max_num_points_of_surface must at least 3.
normal_vec (np.ndarray): Normal vector of polygon_surfaces.
d (int): Directions of normal vector.
num_surfaces (np.ndarray): Number of surfaces a polygon contains
shape of (num_polygon).
Returns:
np.ndarray: Result matrix with the shape of [num_points, num_polygon].
"""
max_num_surfaces
,
max_num_points_of_surface
=
polygon_surfaces
.
shape
[
1
:
3
]
max_num_surfaces
,
max_num_points_of_surface
=
polygon_surfaces
.
shape
[
1
:
3
]
num_points
=
points
.
shape
[
0
]
num_points
=
points
.
shape
[
0
]
num_polygons
=
polygon_surfaces
.
shape
[
0
]
num_polygons
=
polygon_surfaces
.
shape
[
0
]
...
...
mmdet3d/core/evaluation/kitti_utils/eval.py
View file @
31b3505d
...
@@ -640,6 +640,18 @@ def kitti_eval(gt_annos,
...
@@ -640,6 +640,18 @@ def kitti_eval(gt_annos,
dt_annos
,
dt_annos
,
current_classes
,
current_classes
,
eval_types
=
[
'bbox'
,
'bev'
,
'3d'
]):
eval_types
=
[
'bbox'
,
'bev'
,
'3d'
]):
"""KITTI evaluation.
Args:
gt_annos (list[dict]): Contain gt information of each sample.
dt_annos (list[dict]): Contain detected information of each sample.
current_classes (list[str]): Classes to evaluation.
eval_types (list[str], optional): Types to eval.
Defaults to ['bbox', 'bev', '3d'].
Returns:
tuple: String and dict of evaluation results.
"""
assert
'bbox'
in
eval_types
,
'must evaluate bbox at least'
assert
'bbox'
in
eval_types
,
'must evaluate bbox at least'
overlap_0_7
=
np
.
array
([[
0.7
,
0.5
,
0.5
,
0.7
,
overlap_0_7
=
np
.
array
([[
0.7
,
0.5
,
0.5
,
0.7
,
0.5
],
[
0.7
,
0.5
,
0.5
,
0.7
,
0.5
],
0.5
],
[
0.7
,
0.5
,
0.5
,
0.7
,
0.5
],
...
@@ -749,6 +761,16 @@ def kitti_eval(gt_annos,
...
@@ -749,6 +761,16 @@ def kitti_eval(gt_annos,
def
kitti_eval_coco_style
(
gt_annos
,
dt_annos
,
current_classes
):
def
kitti_eval_coco_style
(
gt_annos
,
dt_annos
,
current_classes
):
"""coco style evaluation of kitti.
Args:
gt_annos (list[dict]): Contain gt information of each sample.
dt_annos (list[dict]): Contain detected information of each sample.
current_classes (list[str]): Classes to evaluation.
Returns:
string: Evaluation results.
"""
class_to_name
=
{
class_to_name
=
{
0
:
'Car'
,
0
:
'Car'
,
1
:
'Pedestrian'
,
1
:
'Pedestrian'
,
...
...
mmdet3d/core/evaluation/kitti_utils/rotate_iou.py
View file @
31b3505d
...
@@ -229,6 +229,15 @@ def rbbox_to_corners(corners, rbbox):
...
@@ -229,6 +229,15 @@ def rbbox_to_corners(corners, rbbox):
@
cuda
.
jit
(
'(float32[:], float32[:])'
,
device
=
True
,
inline
=
True
)
@
cuda
.
jit
(
'(float32[:], float32[:])'
,
device
=
True
,
inline
=
True
)
def
inter
(
rbbox1
,
rbbox2
):
def
inter
(
rbbox1
,
rbbox2
):
"""Compute intersection of two rotated boxes.
Args:
rbox1 (np.ndarray, shape=[5]): Rotated 2d box.
rbox2 (np.ndarray, shape=[5]): Rotated 2d box.
Returns:
float: Intersection of two rotated boxes.
"""
corners1
=
cuda
.
local
.
array
((
8
,
),
dtype
=
numba
.
float32
)
corners1
=
cuda
.
local
.
array
((
8
,
),
dtype
=
numba
.
float32
)
corners2
=
cuda
.
local
.
array
((
8
,
),
dtype
=
numba
.
float32
)
corners2
=
cuda
.
local
.
array
((
8
,
),
dtype
=
numba
.
float32
)
intersection_corners
=
cuda
.
local
.
array
((
16
,
),
dtype
=
numba
.
float32
)
intersection_corners
=
cuda
.
local
.
array
((
16
,
),
dtype
=
numba
.
float32
)
...
@@ -246,6 +255,19 @@ def inter(rbbox1, rbbox2):
...
@@ -246,6 +255,19 @@ def inter(rbbox1, rbbox2):
@
cuda
.
jit
(
'(float32[:], float32[:], int32)'
,
device
=
True
,
inline
=
True
)
@
cuda
.
jit
(
'(float32[:], float32[:], int32)'
,
device
=
True
,
inline
=
True
)
def
devRotateIoUEval
(
rbox1
,
rbox2
,
criterion
=-
1
):
def
devRotateIoUEval
(
rbox1
,
rbox2
,
criterion
=-
1
):
"""Compute rotated iou on device.
Args:
rbox1 (np.ndarray, shape=[5]): Rotated 2d box.
rbox2 (np.ndarray, shape=[5]): Rotated 2d box.
criterion (int, optional): Indicate different type of iou.
-1 indicate `area_inter / (area1 + area2 - area_inter)`,
0 indicate `area_inter / area1`,
1 indicate `area_inter / area2`.
Returns:
float: iou between two input boxes.
"""
area1
=
rbox1
[
2
]
*
rbox1
[
3
]
area1
=
rbox1
[
2
]
*
rbox1
[
3
]
area2
=
rbox2
[
2
]
*
rbox2
[
3
]
area2
=
rbox2
[
2
]
*
rbox2
[
3
]
area_inter
=
inter
(
rbox1
,
rbox2
)
area_inter
=
inter
(
rbox1
,
rbox2
)
...
@@ -268,6 +290,19 @@ def rotate_iou_kernel_eval(N,
...
@@ -268,6 +290,19 @@ def rotate_iou_kernel_eval(N,
dev_query_boxes
,
dev_query_boxes
,
dev_iou
,
dev_iou
,
criterion
=-
1
):
criterion
=-
1
):
"""Kernel of computing rotated iou.
Args:
N (int): The number of boxes.
K (int): The number of query boxes.
dev_boxes (np.ndarray): Boxes on device.
dev_query_boxes (np.ndarray): Query boxes on device.
dev_iou (np.ndarray): Computed iou to return.
criterion (int, optional): Indicate different type of iou.
-1 indicate `area_inter / (area1 + area2 - area_inter)`,
0 indicate `area_inter / area1`,
1 indicate `area_inter / area2`.
"""
threadsPerBlock
=
8
*
8
threadsPerBlock
=
8
*
8
row_start
=
cuda
.
blockIdx
.
x
row_start
=
cuda
.
blockIdx
.
x
col_start
=
cuda
.
blockIdx
.
y
col_start
=
cuda
.
blockIdx
.
y
...
@@ -310,8 +345,12 @@ def rotate_iou_gpu_eval(boxes, query_boxes, criterion=-1, device_id=0):
...
@@ -310,8 +345,12 @@ def rotate_iou_gpu_eval(boxes, query_boxes, criterion=-1, device_id=0):
Args:
Args:
boxes (torch.Tensor): rbboxes. format: centers, dims,
boxes (torch.Tensor): rbboxes. format: centers, dims,
angles(clockwise when positive) with the shape of [N, 5].
angles(clockwise when positive) with the shape of [N, 5].
query_boxes (float tensor: [K, 5]): [description]
query_boxes (float tensor: [K, 5]): rbboxes to compute iou with boxes.
device_id (int, optional): Defaults to 0. [description]
device_id (int, optional): Defaults to 0. Device to use.
criterion (int, optional): Indicate different type of iou.
-1 indicate `area_inter / (area1 + area2 - area_inter)`,
0 indicate `area_inter / area1`,
1 indicate `area_inter / area2`.
Returns:
Returns:
np.ndarray: IoU results.
np.ndarray: IoU results.
...
...
tests/test_box_np_ops.py
0 → 100644
View file @
31b3505d
import
numpy
as
np
def
test_camera_to_lidar
():
from
mmdet3d.core.bbox.box_np_ops
import
camera_to_lidar
points
=
np
.
array
([[
1.84
,
1.47
,
8.41
]])
rect
=
np
.
array
([[
0.9999128
,
0.01009263
,
-
0.00851193
,
0.
],
[
-
0.01012729
,
0.9999406
,
-
0.00403767
,
0.
],
[
0.00847068
,
0.00412352
,
0.9999556
,
0.
],
[
0.
,
0.
,
0.
,
1.
]])
Trv2c
=
np
.
array
([[
0.00692796
,
-
0.9999722
,
-
0.00275783
,
-
0.02457729
],
[
-
0.00116298
,
0.00274984
,
-
0.9999955
,
-
0.06127237
],
[
0.9999753
,
0.00693114
,
-
0.0011439
,
-
0.3321029
],
[
0.
,
0.
,
0.
,
1.
]])
points_lidar
=
camera_to_lidar
(
points
,
rect
,
Trv2c
)
expected_points
=
np
.
array
([[
8.73138192
,
-
1.85591746
,
-
1.59969933
]])
assert
np
.
allclose
(
points_lidar
,
expected_points
)
def
test_box_camera_to_lidar
():
from
mmdet3d.core.bbox.box_np_ops
import
box_camera_to_lidar
box
=
np
.
array
([[
1.84
,
1.47
,
8.41
,
1.2
,
1.89
,
0.48
,
0.01
]])
rect
=
np
.
array
([[
0.9999128
,
0.01009263
,
-
0.00851193
,
0.
],
[
-
0.01012729
,
0.9999406
,
-
0.00403767
,
0.
],
[
0.00847068
,
0.00412352
,
0.9999556
,
0.
],
[
0.
,
0.
,
0.
,
1.
]])
Trv2c
=
np
.
array
([[
0.00692796
,
-
0.9999722
,
-
0.00275783
,
-
0.02457729
],
[
-
0.00116298
,
0.00274984
,
-
0.9999955
,
-
0.06127237
],
[
0.9999753
,
0.00693114
,
-
0.0011439
,
-
0.3321029
],
[
0.
,
0.
,
0.
,
1.
]])
box_lidar
=
box_camera_to_lidar
(
box
,
rect
,
Trv2c
)
expected_box
=
np
.
array
(
[[
8.73138192
,
-
1.85591746
,
-
1.59969933
,
0.48
,
1.2
,
1.89
,
0.01
]])
assert
np
.
allclose
(
box_lidar
,
expected_box
)
def
test_corners_nd
():
from
mmdet3d.core.bbox.box_np_ops
import
corners_nd
dims
=
np
.
array
([[
0.47
,
0.98
]])
corners
=
corners_nd
(
dims
)
expected_corners
=
np
.
array
([[[
-
0.235
,
-
0.49
],
[
-
0.235
,
0.49
],
[
0.235
,
0.49
],
[
0.235
,
-
0.49
]]])
assert
np
.
allclose
(
corners
,
expected_corners
)
def
test_center_to_corner_box2d
():
from
mmdet3d.core.bbox.box_np_ops
import
center_to_corner_box2d
center
=
np
.
array
([[
9.348705
,
-
3.6271024
]])
dims
=
np
.
array
([[
0.47
,
0.98
]])
angles
=
np
.
array
([
-
3.14
])
corner
=
center_to_corner_box2d
(
center
,
dims
,
angles
)
expected_corner
=
np
.
array
([[[
9.584485
,
-
3.1374772
],
[
9.582925
,
-
4.117476
],
[
9.112926
,
-
4.1167274
],
[
9.114486
,
-
3.1367288
]]])
assert
np
.
allclose
(
corner
,
expected_corner
)
def
test_rotation_2d
():
from
mmdet3d.core.bbox.box_np_ops
import
rotation_2d
angles
=
np
.
array
([
-
3.14
])
corners
=
np
.
array
([[[
-
0.235
,
-
0.49
],
[
-
0.235
,
0.49
],
[
0.235
,
0.49
],
[
0.235
,
-
0.49
]]])
corners_rotated
=
rotation_2d
(
corners
,
angles
)
expected_corners
=
np
.
array
([[[
0.2357801
,
0.48962511
],
[
0.2342193
,
-
0.49037365
],
[
-
0.2357801
,
-
0.48962511
],
[
-
0.2342193
,
0.49037365
]]])
assert
np
.
allclose
(
corners_rotated
,
expected_corners
)
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