Skip to content

Commit 5301a4a

Browse files
committed
ready to release
1 parent 7924105 commit 5301a4a

9 files changed

+456
-13
lines changed

README.md

+39-6
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
*Yu Yao, Mingze Xu, Yuchen Wang, David Crandall and Ella Atkins*
44

5-
This repo contains the code for our [paper](https://arxiv.org/pdf/1903.00618.pdf) on unsupervised traffic accident detection.
5+
This repo contains the code for our [IROS2019 paper](https://arxiv.org/pdf/1903.00618.pdf) on unsupervised traffic accident detection.
66

7-
:boom: The full code will be released upon the acceptance of our paper.
7+
:boom: The code and A3D dataset is released here!
88

9-
:boom: So far we have released the pytorch implementation of our ICRA paper [*Egocentric Vision-based Future Vehicle Localization for Intelligent Driving Assistance Systems*](https://arxiv.org/pdf/1809.07408.pdf), which is an important building block for the traffic accident detection. The original project repo is https://github.com/MoonBlvd/fvl-ICRA2019
9+
This code also contains a improved pytorch implementation of our ICRA paper [*Egocentric Vision-based Future Vehicle Localization for Intelligent Driving Assistance Systems*](https://arxiv.org/pdf/1809.07408.pdf), which is an important building block for the traffic accident detection. The original project repo is https://github.com/MoonBlvd/fvl-ICRA2019
1010

1111
<img src="figures/teaser.png" width="400">
1212

@@ -17,9 +17,44 @@ To run the code on feature-ready HEV-I dataset or dataset prepared in HEV-I styl
1717
pytorch 1.0
1818
torchsummaryX
1919
tensorboardX
20+
## Train and test
21+
Note that we apply a FOL and ego-motion prediction model to do unsupervised anomaly detection. Thus model training is to train the FOL and ego-motion prediction model on normal driving dataset. We haved used HEV-I as the training set.
22+
### Train
23+
The training script and a config file template are provided:
24+
25+
python train.py --load_config config/fol_ego_train.yaml
26+
27+
### Run FOL on test set and then Anomaly Detection
28+
For evaluation purpose, we firstly run our fol_ego model on test dataset, e.g. A3D to generate all predictions
29+
30+
python run_fol_for_AD.py --load_config config/test_A3D.yaml
31+
32+
This will save one ```.pkl``` file for each video clip. Then we can use the saved predictions to calculate anomaly detection metrics. The following command will print results similar to the paper.
33+
34+
python run_AD.py --load_config config/test_A3D.yaml
35+
36+
The online anomaly detection script is not provided, but the users are free to write another script to do FOL and anomaly detection online.
37+
2038
## Dataset and features
39+
## A3D dataset
40+
The A3D dataset contains videos from YouTube and a ```.pkl``` file including human annotated video start/end time and anomaly start/end time. We provide scripts and url files to download the videos and run pre-process to get the same images we haved used in the paper.
41+
42+
Download the videos from YouTube:
43+
44+
python datasets/A3D_download.py --download_dir VIDEO_DIR --url_file datasets/A3D_urls.txt
45+
46+
Then convert the videos to images in 10Hz
47+
48+
python scripts/video2frames.py -v VIDEO_DIR -f 10 -o IMAGE_DIR -e jpg
49+
50+
Note that each downloaded video is a combination of several short clips, to split them into clips we used, run:
51+
52+
python datasets/A3D_split.py --root_dir DATA_ROOT --label_dir DIR_TO_PKL_LABEL
53+
54+
The annotations can be downloaded from here.
55+
2156
### HEV-I dataset
22-
**Note:** Honda Research Institute is still working on preparing the videos in HEV-I dataset. The planned release date will be around May 20 2019 during the ICRA.
57+
[Honda Egocentric View-Intersection (HEV-I)](https://usa.honda-ri.com/ca/hevi) dataset is owned by HRI and the users can follow the link to request the dataset.
2358

2459
However, we provide the newly generated features here in case you are interested in just using the input features to test your models:
2560

@@ -40,8 +75,6 @@ To prepare the features used in this work, we used:
4075
* Dense optical flow: [FlowNet2.0](https://github.com/NVIDIA/flownet2-pytorch)
4176
* Ego motion: [ORBSLAM2](https://github.com/raulmur/ORB_SLAM2)
4277

43-
### A3D dataset
44-
The A3D dataset will be released upon the acceptance of our IROS submission.
4578

4679
## Future Object Localization
4780

config/test_A3D.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@ best_fol_model: '/home/brianyao/Documents/tad-IROS2019/checkpoints/fvl_ego_check
1010
best_ego_pred_model: '/home/brianyao/Documents/tad-IROS2019/checkpoints/fvl_ego_checkpoints/ego_pred_epoch_055_loss_0.0016.pt'
1111

1212
test_dataset: "A3D"
13-
test_root: "../data/A3D/frames"
14-
label_file: '../data/A3D/A3D_labels.pkl'
13+
label_file: '/home/brianyao/Documents/tad-IROS2019/datasets/A3D_labels.pkl'
1514

1615
track_dir: "/media/DATA/A3D/deep_sort_clear"
1716
flow_dir: "/media/DATA/A3D/flownet2"
1817
ego_motion_dir: "/media/DATA/A3D/ego_motion"
1918
img_dir: "/media/DATA/A3D/frames"
20-
save_dir: "/media/DATA/A3D/multi_prediction_results"
19+
save_dir: "/media/DATA/A3D/fvl_ego_results"
2120

2221
# dataset arguments
2322
seed_max: 5

datasets/A3D_download.py

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import sys
2+
import os
3+
import glob
4+
import argparse
5+
import yaml
6+
import cv2
7+
import youtube_dl
8+
9+
parser = argparse.ArgumentParser(description='AnAnXingChe video downloader parameters.')
10+
parser.add_argument('--download_dir', required=True, help='target directory to save downloaded videos')
11+
parser.add_argument('--url_file', required=True, help='a .txt file saving urls to all videos')
12+
parser.add_argument('--to_images', type=bool, default=False, help='downsample the video and save image frames, default is false')
13+
parser.add_argument('--img_dir', help='target directory to save downsampled')
14+
parser.add_argument('--img_ext', default='jpg', help='image extension')
15+
parser.add_argument('--downsample_rate', default=3.0, type=float, help='downsample rate')
16+
17+
args = parser.parse_args()
18+
19+
DOWNLOAD_DIR = args.download_dir
20+
21+
22+
# Download videos
23+
if not os.path.isdir(DOWNLOAD_DIR):
24+
print("The indicated download directory does not exist!")
25+
print("Directory made!")
26+
os.makedirs(DOWNLOAD_DIR)
27+
28+
'''Download videos'''
29+
ydl_opt = {'outtmpl': DOWNLOAD_DIR + '%(id)s.%(ext)s',
30+
'format': 'mp4'}
31+
ydl = youtube_dl.YoutubeDL(ydl_opt)
32+
'''
33+
with ydl:
34+
result = ydl.extract_info(
35+
'https://www.youtube.com/channel/UC-Oa3wml6F3YcptlFwaLgDA',
36+
download=True # We just want to extract the info
37+
)
38+
'''
39+
url_list = open(args.url_file,'r').readlines()
40+
ydl.download(url_list)
41+
print("Download finished!")
42+
43+
all_videos = sorted(glob.glob(DOWNLOAD_DIR + '*.mp4'))
44+
print("Number of videos: ", len(all_videos))
45+
46+
if args.to_images:
47+
IMAGE_DIR = args.img_dir
48+
# Downsample the saved videos and save images to another directory
49+
try:
50+
os.stat(IMAGE_DIR)
51+
except:
52+
print("The indicated image directory does not exist!")
53+
print("Directory made!")
54+
os.mkdir(IMAGE_DIR)
55+
56+
downsample_rate = args.downsample_rate
57+
for video_idx, file_name in enumerate(all_videos):
58+
video_name = file_name.split('/')[-1][:-4]
59+
image_dir = OUT_DIR + video_name + '/'
60+
try:
61+
os.stat(image_dir)
62+
except:
63+
os.mkdir(image_dir)
64+
65+
cap = cv2.VideoCapture(file_name)
66+
length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
67+
fps = float(cap.get(cv2.CAP_PROP_FPS))
68+
print("Number of frames: ", length)
69+
print("FPS: ", fps)
70+
i = 0
71+
j = 0
72+
while True:
73+
# Capture frame-by-frame
74+
ret, image = cap.read()
75+
if not ret:
76+
break
77+
if i%downsample_rate == 0:
78+
img_name = str(format(j,'06')) + '.' + args.img_ext
79+
j += 1
80+
cv2.imwrite(image_dir + img_name, image)
81+
i += 1

datasets/A3D_labels.pkl

1.23 MB
Binary file not shown.

datasets/A3D_split.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'''
2+
Read the pickle file that saves label of A3D dataset.
3+
Save the images of each short video clip separately and prepare to run MaskRCNN and flownet2
4+
5+
Feb 19 2019
6+
7+
Assume each video's frames are saved in: ROOT_DIR + '/images/xxxxxx'
8+
9+
'''
10+
import os
11+
import pickle as pkl
12+
import shutil
13+
import argparse
14+
15+
parser = argparse.ArgumentParser(description='A3D video split parameters.')
16+
parser.add_argument('--root_dir', required=True, help='the root directory of the dataset')
17+
parser.add_argument('--label_dir', required=True, help='the pkl label file')
18+
args = parser.parse_args()
19+
20+
data = pkl.load(open(args.label_dir,'rb'))
21+
for key, value in data.items():
22+
video_name = key
23+
video_dir = os.path.join(args.root_dir, 'images', value['video_name'])
24+
25+
out_dir = os.path.join(args.root_dir, 'frames', video_name)
26+
if not os.path.isdir(out_dir):
27+
os.mkdir(out_dir)
28+
29+
out_dir = os.path.join(out_dir, 'images')
30+
if not os.path.isdir(out_dir):
31+
os.mkdir(out_dir)
32+
33+
start = value['clip_start']
34+
end = value['clip_end']
35+
for new_i, old_i in enumerate(range(int(start), int(end)+1)):
36+
img_name = str(old_i).zfill(6) + '.jpg'
37+
old_img_path = os.path.join(video_dir, img_name)
38+
new_img_path = os.path.join(out_dir, str(new_i + 1).zfill(6) + '.jpg')
39+
shutil.copy(old_img_path, new_img_path)
40+
41+

0 commit comments

Comments
 (0)