Skip to content

Commit 1a365cd

Browse files
author
Dan Jia
committed
Merge remote-tracking branch 'origin/master'
2 parents a2396df + bd12747 commit 1a365cd

File tree

6 files changed

+607
-52
lines changed

6 files changed

+607
-52
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
# Person Detection in 2D Range Data
2-
This repository implements DROW3 [(arXiv)](https://arxiv.org/abs/1804.02463) and DR-SPAAM [(arXiv)](https://arxiv.org/abs/2004.14079), real-time person detectors using 2D LiDARs mounted at ankle or knee height.
3-
Also included are experiments from *Self-Supervised Person Detection in 2D Range Data using a Calibrated Camera* [(arXiv)](https://arxiv.org/abs/2012.08890).
2+
This repository implements DROW3 ([arXiv](https://arxiv.org/abs/1804.02463)) and DR-SPAAM ([arXiv](https://arxiv.org/abs/2004.14079)), real-time person detectors using 2D LiDARs mounted at ankle or knee height.
3+
Also included are experiments from *Self-Supervised Person Detection in 2D Range Data using a Calibrated Camera* ([arXiv](https://arxiv.org/abs/2012.08890)).
44
Pre-trained models (using PyTorch 1.6) can be found in this [Google drive](https://drive.google.com/drive/folders/1Wl2nC8lJ6s9NI1xtWwmxeAUnuxDiiM4W?usp=sharing).
55

66
![](imgs/teaser_1.gif)
77

8+
## News
9+
10+
[06-03-2021] Our work has been accepted to ICRA'21! Checkout the presentation video [here](https://www.youtube.com/watch?v=f5U1ZfqXtc0).
11+
812
## Quick start
913

1014
First clone and install the repository
@@ -114,7 +118,7 @@ If your robot has a calibrated camera (i.e. the transformation between the camer
114118
you can generate pseudo labels automatically during deployment and fine-tune the detector (no manual labeling needed).
115119
We provide a wrapper function `dr_spaam.pseudo_labels.get_regression_target_using_bounding_boxes()` for generating pseudo labels conveniently.
116120
For experiments using pseudo labels,
117-
checkout our paper *Self-Supervised Person Detection in 2D Range Data using a Calibrated Camera* [(arXiv)](https://arxiv.org/abs/2012.08890).
121+
checkout our paper *Self-Supervised Person Detection in 2D Range Data using a Calibrated Camera* ([arXiv](https://arxiv.org/abs/2012.08890)).
118122
Use checkpoints in this [Google drive](https://drive.google.com/drive/folders/1Wl2nC8lJ6s9NI1xtWwmxeAUnuxDiiM4W?usp=sharing) to reproduce our results.
119123

120124
## Inference time

dr_spaam/bin/analyze_pseudo_labels.py renamed to dr_spaam/bin/plotting/analyze_pseudo_labels.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import matplotlib.pyplot as plt
99
from matplotlib.gridspec import GridSpec
1010

11-
from dr_spaam.dataset.get_dataloader import get_dataloader
11+
from dr_spaam.dataset import get_dataloader
1212
import dr_spaam.utils.jrdb_transforms as jt
1313
import dr_spaam.utils.precision_recall as pru
1414
import dr_spaam.utils.utils as u
@@ -254,7 +254,7 @@ def _write_file_make_dir(f_name, f_str):
254254

255255

256256
def generate_pseudo_labels():
257-
with open("./base_dr_spaam_jrdb_cfg.yaml", "r") as f:
257+
with open("./cfgs/base_dr_spaam_jrdb_cfg.yaml", "r") as f:
258258
cfg = yaml.safe_load(f)
259259
cfg["dataset"]["pseudo_label"] = True
260260
cfg["dataset"]["pl_correction_level"] = 0
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pickle
2+
import numpy as np
3+
4+
p1 = "/home/jia/git/awesome_repos/2D_lidar_person_detection/dr_spaam/logs/20210520_224024_drow_jrdb_EVAL/output/val/e000000/evaluation/all/result_r05.pkl"
5+
p2 = "/home/jia/git/awesome_repos/2D_lidar_person_detection/dr_spaam/logs/20210520_231344_drow_jrdb_EVAL/output/val/e000000/evaluation/all/result_r05.pkl"
6+
7+
for p in (p1, p2):
8+
with open(p, "rb") as f:
9+
res = pickle.load(f)
10+
11+
eer = res["eer"]
12+
arg = np.argmin(np.abs(res["precisions"] - eer))
13+
print(res["thresholds"][arg], " ", res["precisions"][arg], " ", res["recalls"][arg])

dr_spaam/bin/get_pseudo_label_videos.py renamed to dr_spaam/bin/plotting/get_pseudo_label_videos.py

Lines changed: 125 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,25 @@
77

88
import torch
99

10-
from dr_spaam.dataset.get_dataloader import get_dataloader
10+
from dr_spaam.dataset import get_dataloader
1111
import dr_spaam.utils.jrdb_transforms as jt
1212
import dr_spaam.utils.utils as u
1313

1414
from dr_spaam.pipeline.logger import Logger
1515
from dr_spaam.model.get_model import get_model
1616

17+
# for _PLOTTING_INTERVAL = 2
18+
# 000579 = 14s
19+
# ffmpeg -r 20 -pattern_type glob -i 'packard-poster-session-2019-03-20_1/scan_pl_*.png' -c:v libx264 -vf fps=30 -pix_fmt yuv420p out_pl.mp4
20+
1721
_X_LIM = (-15, 15)
1822
# _Y_LIM = (-10, 4)
1923
_Y_LIM = (-7, 7)
2024

2125
_PLOTTING_INTERVAL = 2
2226
_MAX_COUNT = 1e9
27+
# _MAX_COUNT = 1e1
28+
_SEQ_MAX_COUNT = 2000
2329

2430
# _COLOR_CLOSE_HSV = (1.0, 0.59, 0.75)
2531
_COLOR_CLOSE_HSV = (0.0, 1.0, 1.0)
@@ -52,7 +58,7 @@ def _distance_to_bgr_color(dist):
5258
return c_bgr[0]
5359

5460

55-
def _plot_frame_im(batch_dict, ib):
61+
def _plot_frame_im(batch_dict, ib, show_pseudo_labels=False):
5662
frame_id = f"{batch_dict['frame_id'][ib]:06d}"
5763
sequence = batch_dict["sequence"][ib]
5864

@@ -82,50 +88,65 @@ def _plot_frame_im(batch_dict, ib):
8288
scan_xyz_laser = np.stack((scan_x, -scan_y, scan_z), axis=0) # in JRDB laser frame
8389
p_xy, ib_mask = jt.transform_pts_laser_to_stitched_im(scan_xyz_laser)
8490

85-
# detection bounding box
86-
for box_dict in batch_dict["im_dets"][ib]:
87-
x0, y0, w, h = box_dict["box"]
88-
x1 = x0 + w
89-
y1 = y0 + h
90-
verts = _get_bounding_box_plotting_vertices(x0, y0, x1, y1)
91-
ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1], c=(0.0, 0.0, 1.0), alpha=0.3)
92-
# c = max(float(box_dict["score"]) - 0.5, 0) * 2.0
93-
# ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1], c=(1.0 - c, 1.0 - c, 1.0))
94-
# ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1],
95-
# c=(0.0, 0.0, 1.0), alpha=1.0)
96-
97-
# x1_large = x1 + 0.05 * w
98-
# x0_large = x0 - 0.05 * w
99-
# y1_large = y1 + 0.05 * w
100-
# y0_large = y0 - 0.05 * w
101-
# in_box_mask = np.logical_and(
102-
# np.logical_and(p_xy[0] > x0_large, p_xy[0] < x1_large),
103-
# np.logical_and(p_xy[1] > y0_large, p_xy[1] < y1_large)
104-
# )
105-
# neg_mask[in_box_mask] = False
106-
107-
for box in batch_dict["pseudo_label_boxes"][ib]:
108-
x0, y0, x1, y1 = box
109-
verts = _get_bounding_box_plotting_vertices(x0, y0, x1, y1)
110-
ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1], c="green")
111-
112-
# overlay laser points on image
113-
c_bgr = _distance_to_bgr_color(scan_r)
114-
ax_im.scatter(
115-
p_xy[0, ib_mask] - crop_min_x, p_xy[1, ib_mask], s=1, color=c_bgr[ib_mask]
116-
)
117-
# neg_mask = np.ones(p_xy.shape[1], dtype=np.bool)
118-
# ax_im.scatter(p_xy[0, neg_mask] - crop_min_x, p_xy[1, neg_mask], s=1,
119-
# color=c_bgr[neg_mask])
91+
if show_pseudo_labels:
92+
# detection bounding box
93+
for box_dict in batch_dict["im_dets"][ib]:
94+
x0, y0, w, h = box_dict["box"]
95+
x1 = x0 + w
96+
y1 = y0 + h
97+
verts = _get_bounding_box_plotting_vertices(x0, y0, x1, y1)
98+
ax_im.plot(
99+
verts[:, 0] - crop_min_x, verts[:, 1], c=(0.0, 0.0, 1.0), alpha=0.3
100+
)
101+
# c = max(float(box_dict["score"]) - 0.5, 0) * 2.0
102+
# ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1], c=(1.0 - c, 1.0 - c, 1.0))
103+
# ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1],
104+
# c=(0.0, 0.0, 1.0), alpha=1.0)
105+
106+
# x1_large = x1 + 0.05 * w
107+
# x0_large = x0 - 0.05 * w
108+
# y1_large = y1 + 0.05 * w
109+
# y0_large = y0 - 0.05 * w
110+
# in_box_mask = np.logical_and(
111+
# np.logical_and(p_xy[0] > x0_large, p_xy[0] < x1_large),
112+
# np.logical_and(p_xy[1] > y0_large, p_xy[1] < y1_large)
113+
# )
114+
# neg_mask[in_box_mask] = False
115+
116+
for box in batch_dict["pseudo_label_boxes"][ib]:
117+
x0, y0, x1, y1 = box
118+
verts = _get_bounding_box_plotting_vertices(x0, y0, x1, y1)
119+
ax_im.plot(verts[:, 0] - crop_min_x, verts[:, 1], c="green")
120+
121+
# overlay only pseudo-label laser points on image
122+
pl_pos_mask = np.logical_and(batch_dict["target_cls"][ib] == 1, ib_mask)
123+
pl_neg_mask = np.logical_and(batch_dict["target_cls"][ib] == 0, ib_mask)
124+
ax_im.scatter(
125+
p_xy[0, pl_pos_mask] - crop_min_x, p_xy[1, pl_pos_mask], s=1, color="green",
126+
)
127+
ax_im.scatter(
128+
p_xy[0, pl_neg_mask] - crop_min_x,
129+
p_xy[1, pl_neg_mask],
130+
s=1,
131+
color="orange",
132+
)
133+
134+
fig_file = os.path.join(_SAVE_DIR, f"figs/{sequence}/im_pl_{frame_id}.png")
135+
else:
136+
# overlay all laser points on image
137+
c_bgr = _distance_to_bgr_color(scan_r)
138+
ax_im.scatter(
139+
p_xy[0, ib_mask] - crop_min_x, p_xy[1, ib_mask], s=1, color=c_bgr[ib_mask]
140+
)
141+
fig_file = os.path.join(_SAVE_DIR, f"figs/{sequence}/im_raw_{frame_id}.png")
120142

121143
# save fig
122-
fig_file = os.path.join(_SAVE_DIR, f"figs/{sequence}/im_{frame_id}.png")
123144
os.makedirs(os.path.dirname(fig_file), exist_ok=True)
124145
fig.savefig(fig_file, dpi=dpi)
125146
plt.close(fig)
126147

127148

128-
def _plot_frame_pts(batch_dict, ib, pred_cls, pred_reg):
149+
def _plot_frame_pts(batch_dict, ib, pred_cls, pred_reg, pred_cls_p, pred_reg_p):
129150
frame_id = f"{batch_dict['frame_id'][ib]:06d}"
130151
sequence = batch_dict["sequence"][ib]
131152

@@ -159,18 +180,46 @@ def _plot_frame_pts(batch_dict, ib, pred_cls, pred_reg):
159180
)
160181
ax.add_artist(c)
161182

162-
# inference result or pseudo-labels
183+
# plot detections
163184
if pred_cls is not None and pred_reg is not None:
164185
dets_xy, dets_cls, _ = u.nms_predicted_center(
165186
scan_r, scan_phi, pred_cls[ib].reshape(-1), pred_reg[ib]
166187
)
167-
dets_xy = dets_xy[dets_cls > 0.15]
188+
dets_xy = dets_xy[dets_cls >= 0.9438938] # at EER
168189
if len(dets_xy) > 0:
169190
for x, y in dets_xy:
170-
c = plt.Circle((x, y), radius=0.4, color=(0.0, 0.56, 0.56), fill=False)
191+
c = plt.Circle((x, y), radius=0.4, color="green", fill=False)
171192
ax.add_artist(c)
172193
fig_file = os.path.join(_SAVE_DIR, f"figs/{sequence}/scan_det_{frame_id}.png")
194+
195+
# plot in addition detections from a pre-trained
196+
if pred_cls_p is not None and pred_reg_p is not None:
197+
dets_xy, dets_cls, _ = u.nms_predicted_center(
198+
scan_r, scan_phi, pred_cls_p[ib].reshape(-1), pred_reg_p[ib]
199+
)
200+
dets_xy = dets_xy[dets_cls > 0.29919282] # at EER
201+
if len(dets_xy) > 0:
202+
for x, y in dets_xy:
203+
c = plt.Circle((x, y), radius=0.4, color="green", fill=False)
204+
ax.add_artist(c)
205+
# plot pre-trained detections only
206+
elif pred_cls_p is not None and pred_reg_p is not None:
207+
dets_xy, dets_cls, _ = u.nms_predicted_center(
208+
scan_r, scan_phi, pred_cls_p[ib].reshape(-1), pred_reg_p[ib]
209+
)
210+
dets_xy = dets_xy[dets_cls > 0.29919282] # at EER
211+
if len(dets_xy) > 0:
212+
for x, y in dets_xy:
213+
c = plt.Circle((x, y), radius=0.4, color="green", fill=False)
214+
ax.add_artist(c)
215+
fig_file = os.path.join(
216+
_SAVE_DIR, f"figs/{sequence}/scan_pretrain_{frame_id}.png"
217+
)
218+
# plot pseudo-labels only
173219
else:
220+
pl_neg_mask = batch_dict["target_cls"][ib] == 0
221+
ax.scatter(scan_x[pl_neg_mask], scan_y[pl_neg_mask], s=0.5, c="orange")
222+
174223
pl_xy = batch_dict["pseudo_label_loc_xy"][ib]
175224
if len(pl_xy) > 0:
176225
for x, y in pl_xy:
@@ -185,7 +234,7 @@ def _plot_frame_pts(batch_dict, ib, pred_cls, pred_reg):
185234

186235

187236
def plot_pseudo_label_for_all_frames():
188-
with open("./base_drow_jrdb_cfg.yaml", "r") as f:
237+
with open("./cfgs/base_drow_jrdb_cfg.yaml", "r") as f:
189238
cfg = yaml.safe_load(f)
190239
cfg["dataset"]["pseudo_label"] = True
191240
cfg["dataset"]["pl_correction_level"] = 0
@@ -203,10 +252,25 @@ def plot_pseudo_label_for_all_frames():
203252
model.eval()
204253

205254
logger = Logger(cfg["pipeline"]["Logger"])
206-
logger.load_ckpt("./ckpts/ckpt_phce_drow_e40.pth", model)
255+
logger.load_ckpt("./ckpts/ckpt_jrdb_pl_drow3_phce_e40.pth", model)
256+
257+
model_pretrain = get_model(cfg["model"])
258+
model_pretrain.cuda()
259+
model_pretrain.eval()
260+
logger.load_ckpt("./ckpts/ckpt_drow_drow3_e40.pth", model_pretrain)
207261

208262
# generate pseudo labels for all sample
263+
seq_count = 0
209264
for count, batch_dict in enumerate(tqdm(test_loader)):
265+
if batch_dict["first_frame"][0]:
266+
print(f"new seq, reset count, idx {count}")
267+
seq_count = 0
268+
269+
if seq_count > _SEQ_MAX_COUNT:
270+
continue
271+
else:
272+
seq_count += 1
273+
210274
if count >= _MAX_COUNT:
211275
break
212276

@@ -216,11 +280,25 @@ def plot_pseudo_label_for_all_frames():
216280
pred_cls = torch.sigmoid(pred_cls).data.cpu().numpy()
217281
pred_reg = pred_reg.data.cpu().numpy()
218282

283+
pred_cls_p, pred_reg_p = model_pretrain(net_input)
284+
pred_cls_p = torch.sigmoid(pred_cls_p).data.cpu().numpy()
285+
pred_reg_p = pred_reg_p.data.cpu().numpy()
286+
219287
if count % _PLOTTING_INTERVAL == 0:
220288
for ib in range(len(batch_dict["input"])):
221-
_plot_frame_im(batch_dict, ib)
222-
_plot_frame_pts(batch_dict, ib, None, None)
223-
_plot_frame_pts(batch_dict, ib, pred_cls, pred_reg)
289+
# generate sequence videos
290+
_plot_frame_im(batch_dict, ib, False) # image
291+
_plot_frame_im(batch_dict, ib, True) # image
292+
_plot_frame_pts(
293+
batch_dict, ib, None, None, None, None
294+
) # pseudo-label
295+
_plot_frame_pts(
296+
batch_dict, ib, pred_cls, pred_reg, None, None
297+
) # detections
298+
299+
# # use to generate comparsion between pre-trained and pseudo-label trained # noqa
300+
# _plot_frame_pts(batch_dict, ib, pred_cls, pred_reg, None, None)
301+
# _plot_frame_pts(batch_dict, ib, None, None, pred_cls_p, pred_reg_p)
224302

225303

226304
def plot_color_bar():

dr_spaam/bin/plotting/make_videos.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
for DIR in figs/*; do
2+
if [[ ! -d $DIR ]]; then
3+
continue
4+
fi
5+
6+
if [[ ! -d videos ]]; then
7+
mkdir videos
8+
fi
9+
10+
seq=$(basename -- $DIR)
11+
12+
ffmpeg -r 20 -pattern_type glob -i "${DIR}/im_raw_*.png" -c:v libx264 -vf fps=30 -pix_fmt yuv420p "videos/${seq}__im_raw.mp4"
13+
ffmpeg -r 20 -pattern_type glob -i "${DIR}/im_pl_*.png" -c:v libx264 -vf fps=30 -pix_fmt yuv420p "videos/${seq}__im_pl.mp4"
14+
ffmpeg -r 20 -pattern_type glob -i "${DIR}/scan_det_*.png" -c:v libx264 -vf fps=30 -pix_fmt yuv420p "videos/${seq}__det.mp4"
15+
ffmpeg -r 20 -pattern_type glob -i "${DIR}/scan_pl_*.png" -c:v libx264 -vf fps=30 -pix_fmt yuv420p "videos/${seq}__pl.mp4"
16+
done

0 commit comments

Comments
 (0)