Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jsk_perception] Add Lidar person detection Node #2703

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c49e824
[jsk_perception] Add lidar person detection
iory Jun 17, 2022
0b90571
[jsk_recognition_utils] Add visualization marker library.
iory Jun 24, 2022
39e0209
[jsk_perception/lidar_person_detection] Install sample data (bagfile)
iory Jun 24, 2022
2395686
[jsk_perception/lidar_person_detection] Add sample files
iory Jun 24, 2022
e018ef0
[jsk_perception/lidar_person_detection] Fixed invalid orientation.
iory Jun 24, 2022
04d40a3
[jsk_perception/lidar_person_detection] Modified visualization marker…
iory Jun 24, 2022
cea659f
[jsk_perception/lidar_person_detection] Add docs.
iory Jun 24, 2022
ad9f796
[jsk_recognition_utils] Merge duplicated code to jsk_recognition_util…
iory Jun 24, 2022
d1ab414
[jsk_recognition_utils/geometry] Add exception for avoid nan.
iory Jun 24, 2022
fd023b6
[jsk_perception/lidar_person_detection] Add orientation from tracking
iory Jun 24, 2022
325be13
[jsk_perception/lidar_person_detection/doc] Fixed wrong descriptions
iory Jun 25, 2022
2d9792e
[jsk_perception/lidar_person_detection] Drop tracker
iory Jun 25, 2022
3622a54
[jsk_recognition_utils] Add pairwise_distance functions
iory Jun 25, 2022
2c99d1f
[jsk_recognition_utils] Add Sort Tracker
iory Jun 25, 2022
5d3b5e8
[jsk_recognition_utils] Add min_cost_matching function to match detec…
iory Jun 25, 2022
be46e72
[jsk_perception/lidar_person_detection] Fixed the behaviour of tracker.
iory Jun 25, 2022
ebbc048
[jsk_perception/lidar_person_detection] Add docs about tracking
iory Jun 25, 2022
8f6a464
[jsk_perception/lidar_person_detection] Enable gpu option
iory Jun 25, 2022
f639d4c
[jsk_perception/lidar_person_detection] Use absolute import
iory Jun 25, 2022
b5b6f8a
Update jsk_recognition_utils/python/jsk_recognition_utils/visualizati…
iory Jun 26, 2022
0bf4bc3
Update jsk_recognition_utils/python/jsk_recognition_utils/visualizati…
iory Jun 26, 2022
b5ee0e3
[jsk_perception/lidar_person_detection] Add test
iory Jun 27, 2022
6247a1a
Merge branch 'master' into lidar-person-detection
k-okada Nov 10, 2023
7f25e64
fix file path changed by #2642
k-okada Nov 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
[submodule "jsk_perception/node_scripts/deep_sort/deep_sort"]
path = jsk_perception/node_scripts/deep_sort/deep_sort
url = https://github.com/nwojke/deep_sort.git
[submodule "jsk_perception/node_scripts/dr_spaam_libs/dr_spaam"]
path = jsk_perception/node_scripts/dr_spaam_libs/dr_spaam
url = https://github.com/VisualComputingInstitute/2D_lidar_person_detection
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions doc/jsk_perception/nodes/lidar_person_detection_node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# lidar_person_detection_node.py

![](images/lidar_person_detection_node.gif)

Detect person from lidar sensor.

For more detail, please see the thesis `DR-SPAAM: A Spatial-Attention and Auto-regressive Model for Person Detection in 2D Range Data`.

In order to use this feature, you need to install `pytorch <https://pytorch.org/get-started/locally/>`_ (pytorch >= 1.4.0 is recommended).


## Subscribing Topic

* `~input` (`sensor_msgs/LaserScan`)

Input laser scan.


## Publishing Topic

* `~output` (`geometry_msgs/PoseArray`)

Position of detected people.

Based on the result of tracking, the direction of movement is the x direction.

* `~output/markers` (`visualization_msgs/MarkerArray`)

MakerArray of detected people.

The color of the marker is determined based on the tracking result.

## Parameters

* `~queue_size` (`Int`, default: `1`)

Input queue size.

* `~conf_thresh` (`Double`, default: `0.8`)

Threshold for confidence.

* `~weight_file` (`String`, required)

Trained model's weight file path.

* `~detector_model` (`String`, default: `DR-SPAAM`)

Detector model. Current only `DR-SPAAM` is supported.

* `~stride` (`Int`, default: `1`)

Use this to skip laser points.

* `~panoramic_scan` (`Bool`, default: `false`)

Set to true if the scan covers 360 degree.

* `~gpu` (`Int`, default: `-1`)

Index of gpu used for prediction. Set `-1` for using CPU.

* `~max_distance` (`Double`, default: `0.5`)

Threshold for tracking max distance.

If the position in the previous frame is farther than this distance, it will be excluded from the tracking candidates.

* `~n_previous` (`Int`, default: `10`)

Determine the moving direction from the previous position and the current position.

* `~map_link` (`String`, default: `None` optional)

If this value is specified, markers are published in `~map_link` frame.

* `~duration_timeout` (`Double`, default: `0.05`)

Duration of timeout for lookup transform in case of specifying `~map_link`.

* `~color_alpha` (`Double`, default: `0.8`)

Alpha value of visualization marker.

* `~people_height` (`Double`, default: `1.6`)

Height of visualization marker.

* `~people_head_radius` (`Double`, default: `0.3`)

Head radius of visualization marker.

* `~people_body_radius` (`Double`, default: `0.3`)

Body radius of visualization marker.

## Sample

```bash
roslaunch jsk_perception sample_lidar_person_detection.launch
```
8 changes: 8 additions & 0 deletions jsk_perception/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ generate_dynamic_reconfigure_options(
cfg/OverlayImageColorOnMono.cfg
cfg/SelectiveSearch.cfg
cfg/LabelToMaskImage.cfg
cfg/LidarPersonDetection.cfg
cfg/FlowVelocityThresholding.cfg
cfg/FilterMaskImageWithSize.cfg
cfg/FastRCNN.cfg
Expand Down Expand Up @@ -201,6 +202,12 @@ if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/node_scripts/deep_sort/deep_sort/READM
execute_process(COMMAND git submodule update deep_sort WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/node_scripts/deep_sort)
endif()

if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/node_scripts/dr_spaam_libs/dr_spaam/README.md)
message(WARNING "node_scripts/dr_spaam_libs/dr_spaam is not exists, download this")
execute_process(COMMAND git submodule init dr_spaam WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/node_scripts/dr_spaam_libs)
execute_process(COMMAND git submodule update dr_spaam WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/node_scripts/dr_spaam_libs)
endif()

# Build nodelet executables
include_directories(include ${catkin_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} slic ${libcmt_INCLUDE_DIRS})
if(robot_self_filter_FOUND)
Expand Down Expand Up @@ -510,6 +517,7 @@ if(CATKIN_ENABLE_TESTING)
if("$ENV{ROS_DISTRO}" STRGREATER "indigo")
jsk_add_rostest(test/craft_node.test)
jsk_add_rostest(test/deep_sort_tracker.test)
jsk_add_rostest(test/lidar_person_detection.test)
jsk_add_rostest(test/ocr_node.test)
endif()
jsk_add_rostest(test/draw_rects.test)
Expand Down
19 changes: 19 additions & 0 deletions jsk_perception/cfg/LidarPersonDetection.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python

PACKAGE = 'jsk_perception'

from dynamic_reconfigure.parameter_generator_catkin import *

gen = ParameterGenerator()

gen.add("conf_thresh", double_t, 0, "Threshold for confidence", 0.8, 0.0, 1.0)
gen.add("max_distance", double_t, 0, "Threshold for tracking max distance", 0.5, 0.0, 100.0)
gen.add("n_previous", int_t, 0, "Determine the moving direction from the previous position and the current position", 10, 1, 1000)

viz_group = gen.add_group("VisualizationMarker")
viz_group.add("color_alpha", double_t, 0, "Alpha value of visualization marker.", 0.8, 0.0, 1.0)
viz_group.add("people_height", double_t, 0, "Height of visualization marker.", 1.6, 0.0, 10.0)
viz_group.add("people_head_radius", double_t, 0, "Head radius of visualization marker.", 0.3, 0.0, 10.0)
viz_group.add("people_body_radius", double_t, 0, "Body radius of visualization marker.", 0.3, 0.0, 10.0)

exit(gen.generate(PACKAGE, PACKAGE, "LidarPersonDetection"))
Empty file.
118 changes: 118 additions & 0 deletions jsk_perception/node_scripts/dr_spaam_libs/detector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from __future__ import absolute_import

import torch
import numpy as np

from .import_dr_spaam import dr_spaam
from dr_spaam.model.drow_net import DrowNet
from dr_spaam.model.dr_spaam import DrSpaam
from dr_spaam.utils import utils as u


class DRSpaamDetector(object):

def __init__(
self, ckpt_file, model="DROW3", gpu=-1, stride=1, panoramic_scan=False
):
"""A warpper class around DROW3 or DR-SPAAM network for end-to-end inference.

Args:
ckpt_file (str): Path to checkpoint
model (str): Model name, "DROW3" or "DR-SPAAM".
gpu (Int): If greater equal than 0, use gpu.
stride (int): Downsample scans for faster inference.
panoramic_scan (bool): True if the scan covers 360 degree.
"""
if gpu >= 0:
torch.backends.cudnn.benchmark = True
self.device = torch.device('cuda:{}'.format(gpu))
else:
self.device = torch.device('cpu')
self._stride = stride
self._use_dr_spaam = model == "DR-SPAAM"

self._scan_phi = None
self._laser_fov_deg = None

if model == "DROW3":
self._model = DrowNet(
dropout=0.5, cls_loss=None, mixup_alpha=0.0, mixup_w=0.0
)
elif model == "DR-SPAAM":
self._model = DrSpaam(
dropout=0.5,
num_pts=56,
embedding_length=128,
alpha=0.5,
window_size=17,
panoramic_scan=panoramic_scan,
cls_loss=None,
mixup_alpha=0.0,
mixup_w=0.0,
)
else:
raise NotImplementedError(
"model should be 'DROW3' or 'DR-SPAAM', received {} instead.".format(
model
)
)

ckpt = torch.load(ckpt_file, map_location=torch.device('cpu'))
self._model.load_state_dict(ckpt["model_state"])

self._model.eval()
self._model = self._model.to(self.device)

def __call__(self, scan):
if self._scan_phi is None:
assert self.is_ready(), "Call set_laser_fov() first."
half_fov_rad = 0.5 * np.deg2rad(self._laser_fov_deg)
self._scan_phi = np.linspace(
-half_fov_rad, half_fov_rad, len(scan), dtype=np.float32
)

# preprocess
ct = u.scans_to_cutout(
scan[None, ...],
self._scan_phi,
stride=self._stride,
centered=True,
fixed=True,
window_width=1.0,
window_depth=0.5,
num_cutout_pts=56,
padding_val=29.99,
area_mode=True,
)
ct = torch.from_numpy(ct).float()
ct = ct.to(self.device)

# inference
sim = None
with torch.no_grad():
# one extra dimension for batch
if self._use_dr_spaam:
pred_cls, pred_reg, sim = self._model(ct.unsqueeze(dim=0), inference=True)
else:
pred_cls, pred_reg = self._model(ct.unsqueeze(dim=0))
if sim is not None:
sim = sim.data.cpu().numpy()

pred_cls = torch.sigmoid(pred_cls[0]).data.cpu().numpy()
pred_reg = pred_reg[0].data.cpu().numpy()

# postprocess
dets_xy, dets_cls, instance_mask = u.nms_predicted_center(
scan[:: self._stride],
self._scan_phi[:: self._stride],
pred_cls[:, 0],
pred_reg,
)

return dets_xy, dets_cls, instance_mask, sim

def set_laser_fov(self, fov_deg):
self._laser_fov_deg = fov_deg

def is_ready(self):
return self._laser_fov_deg is not None
1 change: 1 addition & 0 deletions jsk_perception/node_scripts/dr_spaam_libs/dr_spaam
Submodule dr_spaam added at 1a365c
9 changes: 9 additions & 0 deletions jsk_perception/node_scripts/dr_spaam_libs/import_dr_spaam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import imp
import os.path as osp


abs_path = osp.dirname(osp.abspath(__file__))


dr_spaam = imp.load_package(
'dr_spaam', osp.join(abs_path, 'dr_spaam/dr_spaam/dr_spaam'))
Loading