├── .gitignore
├── README.md
├── data
├── __init__.py
├── config.py
├── egohand.py
├── factory.py
├── vochead.py
└── widerface.py
├── demo.py
├── eval_tools
├── boxoverlap.m
├── evaluation.m
├── ground_truth
│ ├── wider_easy_val.mat
│ ├── wider_face_val.mat
│ ├── wider_hard_val.mat
│ └── wider_medium_val.mat
├── nms.m
├── norm_score.m
├── plot
│ ├── VOCap.m
│ ├── baselines
│ │ ├── Test
│ │ │ ├── setting_ext
│ │ │ │ ├── acf
│ │ │ │ │ ├── wider_pr_info_acf_easy.mat
│ │ │ │ │ ├── wider_pr_info_acf_hard.mat
│ │ │ │ │ └── wider_pr_info_acf_medium.mat
│ │ │ │ ├── dpm
│ │ │ │ │ ├── wider_pr_info_dpm_easy.mat
│ │ │ │ │ ├── wider_pr_info_dpm_hard.mat
│ │ │ │ │ └── wider_pr_info_dpm_medium.mat
│ │ │ │ ├── faceness
│ │ │ │ │ ├── wider_pr_info_faceness_easy.mat
│ │ │ │ │ ├── wider_pr_info_faceness_hard.mat
│ │ │ │ │ └── wider_pr_info_faceness_medium.mat
│ │ │ │ └── vj
│ │ │ │ │ ├── wider_pr_info_vj_easy.mat
│ │ │ │ │ ├── wider_pr_info_vj_hard.mat
│ │ │ │ │ └── wider_pr_info_vj_medium.mat
│ │ │ └── setting_int
│ │ │ │ ├── DSFD
│ │ │ │ ├── wider_pr_info_DSFD_easy.mat
│ │ │ │ ├── wider_pr_info_DSFD_hard.mat
│ │ │ │ └── wider_pr_info_DSFD_medium.mat
│ │ │ │ ├── FAN
│ │ │ │ ├── wider_pr_info_FAN_easy.mat
│ │ │ │ ├── wider_pr_info_FAN_hard.mat
│ │ │ │ └── wider_pr_info_FAN_medium.mat
│ │ │ │ ├── FANet
│ │ │ │ ├── wider_pr_info_FANet_easy.mat
│ │ │ │ ├── wider_pr_info_FANet_hard.mat
│ │ │ │ └── wider_pr_info_FANet_medium.mat
│ │ │ │ ├── FDNet
│ │ │ │ ├── wider_pr_info_FDNet_easy.mat
│ │ │ │ ├── wider_pr_info_FDNet_hard.mat
│ │ │ │ └── wider_pr_info_FDNet_medium.mat
│ │ │ │ ├── Face R-CNN
│ │ │ │ ├── wider_pr_info_Face R-CNN_easy.mat
│ │ │ │ ├── wider_pr_info_Face R-CNN_hard.mat
│ │ │ │ └── wider_pr_info_Face R-CNN_medium.mat
│ │ │ │ ├── Face R-FCN
│ │ │ │ ├── wider_pr_info_Face R-FCN_easy.mat
│ │ │ │ ├── wider_pr_info_Face R-FCN_hard.mat
│ │ │ │ └── wider_pr_info_Face R-FCN_medium.mat
│ │ │ │ ├── HR
│ │ │ │ ├── wider_pr_info_HR_easy.mat
│ │ │ │ ├── wider_pr_info_HR_hard.mat
│ │ │ │ └── wider_pr_info_HR_medium.mat
│ │ │ │ ├── LDCF+
│ │ │ │ ├── .DS_Store
│ │ │ │ ├── wider_pr_info_LDCF+_easy.mat
│ │ │ │ ├── wider_pr_info_LDCF+_hard.mat
│ │ │ │ └── wider_pr_info_LDCF+_medium.mat
│ │ │ │ ├── MSCNN
│ │ │ │ ├── wider_pr_info_MSCNN_easy.mat
│ │ │ │ ├── wider_pr_info_MSCNN_hard.mat
│ │ │ │ └── wider_pr_info_MSCNN_medium.mat
│ │ │ │ ├── PyramidBox
│ │ │ │ ├── wider_pr_info_PyramidBox_easy.mat
│ │ │ │ ├── wider_pr_info_PyramidBox_hard.mat
│ │ │ │ └── wider_pr_info_PyramidBox_medium.mat
│ │ │ │ ├── SFD
│ │ │ │ ├── wider_pr_info_SFD_easy.mat
│ │ │ │ ├── wider_pr_info_SFD_hard.mat
│ │ │ │ └── wider_pr_info_SFD_medium.mat
│ │ │ │ ├── SRN
│ │ │ │ ├── wider_pr_info_SRN_easy.mat
│ │ │ │ ├── wider_pr_info_SRN_hard.mat
│ │ │ │ └── wider_pr_info_SRN_medium.mat
│ │ │ │ ├── SSH
│ │ │ │ ├── wider_pr_info_SSH_easy.mat
│ │ │ │ ├── wider_pr_info_SSH_hard.mat
│ │ │ │ └── wider_pr_info_SSH_medium.mat
│ │ │ │ ├── ScaleFace
│ │ │ │ ├── wider_pr_info_ScaleFace_easy.mat
│ │ │ │ ├── wider_pr_info_ScaleFace_hard.mat
│ │ │ │ └── wider_pr_info_ScaleFace_medium.mat
│ │ │ │ ├── ZCC
│ │ │ │ ├── wider_pr_info_ZCC_easy.mat
│ │ │ │ ├── wider_pr_info_ZCC_hard.mat
│ │ │ │ └── wider_pr_info_ZCC_medium.mat
│ │ │ │ ├── acf
│ │ │ │ ├── wider_pr_info_acf_easy.mat
│ │ │ │ ├── wider_pr_info_acf_hard.mat
│ │ │ │ └── wider_pr_info_acf_medium.mat
│ │ │ │ ├── cms-rcnn
│ │ │ │ ├── wider_pr_info_cms-rcnn_easy.mat
│ │ │ │ ├── wider_pr_info_cms-rcnn_hard.mat
│ │ │ │ └── wider_pr_info_cms-rcnn_medium.mat
│ │ │ │ ├── faceness
│ │ │ │ ├── wider_pr_info_faceness_easy.mat
│ │ │ │ ├── wider_pr_info_faceness_hard.mat
│ │ │ │ └── wider_pr_info_faceness_medium.mat
│ │ │ │ ├── multiscale_cascade
│ │ │ │ ├── wider_pr_info_multiscale_cascade_easy.mat
│ │ │ │ ├── wider_pr_info_multiscale_cascade_hard.mat
│ │ │ │ └── wider_pr_info_multiscale_cascade_medium.mat
│ │ │ │ ├── multitask-cascade-cnn
│ │ │ │ ├── wider_pr_info_multitask-cascade-cnn_easy.mat
│ │ │ │ ├── wider_pr_info_multitask-cascade-cnn_hard.mat
│ │ │ │ └── wider_pr_info_multitask-cascade-cnn_medium.mat
│ │ │ │ └── two_stage_cnn
│ │ │ │ ├── wider_pr_info_two_stage_cnn_easy.mat
│ │ │ │ ├── wider_pr_info_two_stage_cnn_hard.mat
│ │ │ │ └── wider_pr_info_two_stage_cnn_medium.mat
│ │ └── Val
│ │ │ └── setting_int
│ │ │ ├── DSFD
│ │ │ ├── wider_pr_info_DSFD_easy_val.mat
│ │ │ ├── wider_pr_info_DSFD_hard_val.mat
│ │ │ └── wider_pr_info_DSFD_medium_val.mat
│ │ │ ├── FAN
│ │ │ ├── wider_pr_info_fan_easy_val.mat
│ │ │ ├── wider_pr_info_fan_hard_val.mat
│ │ │ └── wider_pr_info_fan_medium_val.mat
│ │ │ ├── FANet
│ │ │ ├── .DS_Store
│ │ │ ├── wider_pr_info_FANet_easy_val.mat
│ │ │ ├── wider_pr_info_FANet_hard_val.mat
│ │ │ └── wider_pr_info_FANet_medium_val.mat
│ │ │ ├── FDNet
│ │ │ ├── wider_pr_info_FDNet_easy_val.mat
│ │ │ ├── wider_pr_info_FDNet_hard_val.mat
│ │ │ └── wider_pr_info_FDNet_medium_val.mat
│ │ │ ├── Face R-CNN
│ │ │ ├── wider_pr_info_Face R-CNN_easy_val.mat
│ │ │ ├── wider_pr_info_Face R-CNN_hard_val.mat
│ │ │ └── wider_pr_info_Face R-CNN_medium_val.mat
│ │ │ ├── Face R-FCN
│ │ │ ├── wider_pr_info_Face R-FCN_easy_val.mat
│ │ │ ├── wider_pr_info_Face R-FCN_hard_val.mat
│ │ │ └── wider_pr_info_Face R-FCN_medium_val.mat
│ │ │ ├── HR
│ │ │ ├── wider_pr_info_HR_easy_val.mat
│ │ │ ├── wider_pr_info_HR_hard_val.mat
│ │ │ └── wider_pr_info_HR_medium_val.mat
│ │ │ ├── LDCF+
│ │ │ ├── wider_pr_info_LDCF+_easy_val.mat
│ │ │ ├── wider_pr_info_LDCF+_hard_val.mat
│ │ │ └── wider_pr_info_LDCF+_medium_val.mat
│ │ │ ├── MSCNN
│ │ │ ├── wider_pr_info_MSCNN_easy_val.mat
│ │ │ ├── wider_pr_info_MSCNN_hard_val.mat
│ │ │ └── wider_pr_info_MSCNN_medium_val.mat
│ │ │ ├── PyramidBox
│ │ │ ├── wider_pr_info_PyramidBox_easy_val.mat
│ │ │ ├── wider_pr_info_PyramidBox_hard_val.mat
│ │ │ └── wider_pr_info_PyramidBox_medium_val.mat
│ │ │ ├── SFD
│ │ │ ├── wider_pr_info_SFD_easy_val.mat
│ │ │ ├── wider_pr_info_SFD_hard_val.mat
│ │ │ └── wider_pr_info_SFD_medium_val.mat
│ │ │ ├── SRN
│ │ │ ├── wider_pr_info_SRN_easy_val.mat
│ │ │ ├── wider_pr_info_SRN_hard_val.mat
│ │ │ └── wider_pr_info_SRN_medium_val.mat
│ │ │ ├── SSH
│ │ │ ├── wider_pr_info_SSH_easy_val.mat
│ │ │ ├── wider_pr_info_SSH_hard_val.mat
│ │ │ └── wider_pr_info_SSH_medium_val.mat
│ │ │ ├── ScaleFace
│ │ │ ├── wider_pr_info_ScaleFace_easy_val.mat
│ │ │ ├── wider_pr_info_ScaleFace_hard_val.mat
│ │ │ └── wider_pr_info_ScaleFace_medium_val.mat
│ │ │ ├── ZCC
│ │ │ ├── wider_pr_info_ZCC_easy_val.mat
│ │ │ ├── wider_pr_info_ZCC_hard_val.mat
│ │ │ └── wider_pr_info_ZCC_medium_val.mat
│ │ │ ├── acf
│ │ │ ├── wider_pr_info_acf_easy_val.mat
│ │ │ ├── wider_pr_info_acf_hard_val.mat
│ │ │ └── wider_pr_info_acf_medium_val.mat
│ │ │ ├── cms-rcnn
│ │ │ ├── wider_pr_info_cms-rcnn_easy_val.mat
│ │ │ ├── wider_pr_info_cms-rcnn_hard_val.mat
│ │ │ └── wider_pr_info_cms-rcnn_medium_val.mat
│ │ │ ├── faceness
│ │ │ ├── wider_pr_info_faceness_easy_val.mat
│ │ │ ├── wider_pr_info_faceness_hard_val.mat
│ │ │ └── wider_pr_info_faceness_medium_val.mat
│ │ │ ├── multiscale_cascade
│ │ │ ├── wider_pr_info_multiscale_cascade_easy_val.mat
│ │ │ ├── wider_pr_info_multiscale_cascade_hard_val.mat
│ │ │ └── wider_pr_info_multiscale_cascade_medium_val.mat
│ │ │ ├── multitask-cascade-cnn
│ │ │ ├── wider_pr_info_multitask-cascade-cnn_easy_val.mat
│ │ │ ├── wider_pr_info_multitask-cascade-cnn_hard_val.mat
│ │ │ └── wider_pr_info_multitask-cascade-cnn_medium_val.mat
│ │ │ ├── s3fd.pytorch
│ │ │ ├── wider_pr_info_s3fd.pytorch_easy_val.mat
│ │ │ ├── wider_pr_info_s3fd.pytorch_hard_val.mat
│ │ │ └── wider_pr_info_s3fd.pytorch_medium_val.mat
│ │ │ └── two_stage_cnn
│ │ │ ├── wider_pr_info_two_stage_cnn_easy_val.mat
│ │ │ ├── wider_pr_info_two_stage_cnn_hard_val.mat
│ │ │ └── wider_pr_info_two_stage_cnn_medium_val.mat
│ ├── figure
│ │ ├── Test
│ │ │ ├── wider_pr_cruve_ext_easy.pdf
│ │ │ ├── wider_pr_cruve_ext_hard.pdf
│ │ │ ├── wider_pr_cruve_ext_medium.pdf
│ │ │ ├── wider_pr_cruve_int_easy.pdf
│ │ │ ├── wider_pr_cruve_int_hard.pdf
│ │ │ └── wider_pr_cruve_int_medium.pdf
│ │ └── Val
│ │ │ ├── wider_pr_cruve_int_easy_val.pdf
│ │ │ ├── wider_pr_cruve_int_hard_val.pdf
│ │ │ └── wider_pr_cruve_int_medium_val.pdf
│ ├── plot_pr.m
│ ├── saveTightFigure.m
│ └── wider_plot.m
├── read_pred.m
├── wider_eval.m
├── wider_face_test.mat
└── wider_face_val.mat
├── img
├── 0_Parade_marchingband_1_465.jpg
├── AFW.png
├── FDDB.png
├── anchor_match.png
├── pascal.png
├── test.jpg
└── test2.jpg
├── layers
├── __init__.py
├── bbox_utils.py
├── functions
│ ├── __init__.py
│ ├── detection.py
│ └── prior_box.py
└── modules
│ ├── __init__.py
│ ├── l2norm.py
│ └── multibox_loss.py
├── prepare_hand_dataset.py
├── prepare_wider_data.py
├── s3fd.py
├── tmp
├── match_anchor.pkl
├── test.jpg
└── test2.jpg
├── tools
├── afw_img_list.txt
├── afw_test.py
├── anchor_matching_test.py
├── detect.py
├── eval_hand.py
├── eval_head.py
├── fddb_test.py
├── pascal_img_list.txt
├── pascal_test.py
└── wider_test.py
├── train.py
└── utils
├── __init__.py
└── augmentations.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.pth
3 | log/
4 | eval_tools/s3fd_val/
5 | eval_tools/sfd_val/
6 | data/train.txt
7 | data/val.txt
8 | data/*.txt
9 | img/02*.jpg
10 | img/tj*.jpg
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## S³FD: Single Shot Scale-invariant Face Detector ##
2 | A PyTorch Implementation of Single Shot Scale-invariant Face Detector
3 |
4 | ### Description
5 | Meanwhile train hand and head with S3FD,hand dataset is [Egohands Dataset](http://vision.soic.indiana.edu/projects/egohands/),head dataset is [SCUT-HEAD](https://github.com/HCIILAB/SCUT-HEAD-Dataset-Release),we can download [hand model](https://pan.baidu.com/s/1_d4HqioBJknGj2ypwtYaXg) and [face model](https://pan.baidu.com/s/1epyTAUc6qSt3oZ7veK4oEw)
6 |
7 | ### Requirement
8 | * pytorch 0.3
9 | * opencv
10 | * numpy
11 | * easydict
12 |
13 | ### Prepare data
14 | 1. download WIDER face dataset、Egohands dataset and SCUT-HEAD
15 | 2. modify data/config.py
16 | 3. ``` python prepare_wider_data.py ```
17 | 4 ``` python prepare_handataset.py ```
18 |
19 |
20 | ### Train
21 | We can choose different dataset to train different target[face,head,hand]
22 | ```
23 | python train.py --batch_size 4 --dataset face\hand\head
24 | ```
25 |
26 | ### Evalution
27 | according to yourself dataset path,modify data/config.py
28 | 1. Evaluate on AFW.
29 | ```
30 | python afw_test.py
31 | ```
32 | 2. Evaluate on FDDB
33 | ```
34 | python fddb_test.py
35 | ```
36 | 3. Evaluate on PASCAL face
37 | ```
38 | python pascal_test.py
39 | ```
40 | 4. test on WIDER FACE
41 | ```
42 | python wider_test.py
43 | ```
44 | ### Demo
45 | you can test yourself image
46 | ```
47 | python demo.py
48 | ```
49 |
50 | ### Result
51 | 1. AFW PASCAL FDDB
52 |
57 |
58 | AFW AP=99.81 paper=99.85
59 | PASCAL AP=98.77 paper=98.49
60 | FDDB AP=0.975 paper=0.983
61 | WIDER FACE:
62 | Easy AP=0.925 paper = 0.927
63 | Medium AP=0.925 paper = 0.924
64 | Hard AP=0.854 paper = 0.852
65 |
66 | 2. demo
67 |
68 |

69 |
70 |
71 |
72 | ### References
73 | * [S³FD: Single Shot Scale-invariant Face Detector](https://arxiv.org/abs/1708.05237)
74 | * [ssd.pytorch](https://github.com/amdegroot/ssd.pytorch)
--------------------------------------------------------------------------------
/data/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/data/__init__.py
--------------------------------------------------------------------------------
/data/config.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | from easydict import EasyDict
9 | import numpy as np
10 |
11 |
12 | _C = EasyDict()
13 | cfg = _C
14 | # data augument config
15 | _C.expand_prob = 0.5
16 | _C.expand_max_ratio = 4
17 | _C.hue_prob = 0.5
18 | _C.hue_delta = 18
19 | _C.contrast_prob = 0.5
20 | _C.contrast_delta = 0.5
21 | _C.saturation_prob = 0.5
22 | _C.saturation_delta = 0.5
23 | _C.brightness_prob = 0.5
24 | _C.brightness_delta = 0.125
25 | _C.data_anchor_sampling_prob = 0.5
26 | _C.min_face_size = 6.0
27 | _C.apply_distort = True
28 | _C.apply_expand = False
29 | _C.img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype(
30 | 'float32')
31 | _C.resize_width = 640
32 | _C.resize_height = 640
33 | _C.scale = 1 / 127.0
34 | _C.anchor_sampling = True
35 | _C.filter_min_face = True
36 |
37 | # train config
38 | #_C.LR_STEPS = (120, 198, 250)
39 | _C.MAX_STEPS = 200000
40 | _C.LR_STEPS = (80000,100000,120000)
41 | _C.EPOCHES = 300
42 |
43 | # anchor config
44 | _C.FEATURE_MAPS = [160, 80, 40, 20, 10, 5]
45 | _C.INPUT_SIZE = 640
46 | _C.STEPS = [4, 8, 16, 32, 64, 128]
47 | _C.ANCHOR_SIZES = [16, 32, 64, 128, 256, 512]
48 | _C.CLIP = False
49 | _C.VARIANCE = [0.1, 0.2]
50 |
51 | # detection config
52 | _C.NMS_THRESH = 0.3
53 | _C.NMS_TOP_K = 5000
54 | _C.TOP_K = 750
55 | _C.CONF_THRESH = 0.05
56 |
57 | # loss config
58 | _C.NEG_POS_RATIOS = 3
59 | _C.NUM_CLASSES = 2
60 | _C.USE_NMS = True
61 |
62 | # dataset config
63 | _C.HOME = '/home/data/lj/'
64 |
65 | # hand config
66 | _C.HAND = EasyDict()
67 | _C.HAND.TRAIN_FILE = './data/hand_train.txt'
68 | _C.HAND.VAL_FILE = './data/hand_val.txt'
69 | _C.HAND.DIR = '/home/data/lj/egohands/'
70 | _C.HAND.OVERLAP_THRESH = 0.35
71 |
72 | # face config
73 | _C.FACE = EasyDict()
74 | _C.FACE.TRAIN_FILE = './data/face_train.txt'
75 | _C.FACE.VAL_FILE = './data/face_val.txt'
76 | _C.FACE.FDDB_DIR = '/home/data/lj/FDDB'
77 | _C.FACE.WIDER_DIR = '/home/data/lj/WIDER'
78 | _C.FACE.AFW_DIR = '/home/data/lj/AFW'
79 | _C.FACE.PASCAL_DIR = '/home/data/lj/PASCAL_FACE'
80 | _C.FACE.OVERLAP_THRESH = [0.1, 0.35, 0.5]
81 |
82 | # head config
83 | _C.HEAD = EasyDict()
84 | _C.HEAD.DIR = '/home/data/lj/VOCHead/'
85 | _C.HEAD.OVERLAP_THRESH = [0.1, 0.35, 0.5]
86 |
--------------------------------------------------------------------------------
/data/egohand.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import absolute_import
4 | from __future__ import division
5 | from __future__ import print_function
6 |
7 | import torch
8 | from PIL import Image, ImageDraw
9 | import torch.utils.data as data
10 | import numpy as np
11 | import random
12 | from utils.augmentations import preprocess
13 |
14 |
15 | class HandDetection(data.Dataset):
16 | """docstring for WIDERDetection"""
17 |
18 | def __init__(self, list_file, mode='train'):
19 | super(HandDetection, self).__init__()
20 | self.mode = mode
21 | self.fnames = []
22 | self.boxes = []
23 | self.labels = []
24 |
25 | with open(list_file) as f:
26 | lines = f.readlines()
27 |
28 | for line in lines:
29 | line = line.strip().split()
30 | num_faces = int(line[1])
31 | box = []
32 | label = []
33 | for i in xrange(num_faces):
34 | xmin = float(line[2 + 4 * i])
35 | ymin = float(line[3 + 4 * i])
36 | xmax = float(line[4 + 4 * i])
37 | ymax = float(line[5 + 4 * i])
38 | box.append([xmin, ymin, xmax, ymax])
39 | label.append(1)
40 | self.fnames.append(line[0])
41 | self.boxes.append(box)
42 | self.labels.append(label)
43 |
44 | self.num_samples = len(self.boxes)
45 |
46 | def __len__(self):
47 | return self.num_samples
48 |
49 | def __getitem__(self, index):
50 | img, target, h, w = self.pull_item(index)
51 | return img, target
52 |
53 | def pull_item(self, index):
54 | while True:
55 | image_path = self.fnames[index]
56 | img = Image.open(image_path)
57 | if img.mode == 'L':
58 | img = img.convert('RGB')
59 |
60 | im_width, im_height = img.size
61 | boxes = self.annotransform(
62 | np.array(self.boxes[index]), im_width, im_height)
63 | label = np.array(self.labels[index])
64 | bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist()
65 | img, sample_labels = preprocess(
66 | img, bbox_labels, self.mode, image_path)
67 | sample_labels = np.array(sample_labels)
68 | if len(sample_labels) > 0:
69 | target = np.hstack(
70 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis]))
71 |
72 | assert (target[:, 2] > target[:, 0]).any()
73 | assert (target[:, 3] > target[:, 1]).any()
74 | break
75 | else:
76 | index = random.randrange(0, self.num_samples)
77 |
78 | '''
79 | #img = Image.fromarray(img)
80 | draw = ImageDraw.Draw(img)
81 | w,h = img.size
82 | for bbox in target:
83 | bbox = (bbox[:-1] * np.array([w, h, w, h])).tolist()
84 |
85 | draw.rectangle(bbox,outline='red')
86 | img.show()
87 | '''
88 | return torch.from_numpy(img), target, im_height, im_width
89 |
90 |
91 | def annotransform(self, boxes, im_width, im_height):
92 | boxes[:, 0] /= im_width
93 | boxes[:, 1] /= im_height
94 | boxes[:, 2] /= im_width
95 | boxes[:, 3] /= im_height
96 | return boxes
97 |
98 |
99 | def pull_image(self,index):
100 | img_path = self.fnames[index]
101 | img = Image.open(img_path)
102 | if img.mode=='L':
103 | img.convert('RGB')
104 | img = np.array(img)
105 | return img
106 |
107 |
108 | if __name__ == '__main__':
109 | from data.config import cfg
110 | dataset = HandDetection(cfg.TRAIN_FILE)
111 | #for i in range(len(dataset)):
112 | dataset.pull_item(2)
113 |
--------------------------------------------------------------------------------
/data/factory.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | from .egohand import HandDetection
9 | from .widerface import WIDERDetection
10 | from .vochead import VOCDetection, VOCAnnotationTransform
11 | from .config import cfg
12 |
13 | import torch
14 |
15 |
16 | def dataset_factory(dataset):
17 | if dataset == 'face':
18 | train_dataset = WIDERDetection(cfg.FACE.TRAIN_FILE, mode='train')
19 | val_dataset = WIDERDetection(cfg.FACE.VAL_FILE, mode='val')
20 | if dataset == 'hand':
21 | train_dataset = WIDERDetection(cfg.HAND.TRAIN_FILE, mode='train')
22 | val_dataset = WIDERDetection(cfg.HAND.VAL_FILE, mode='val')
23 | if dataset == 'head':
24 | train_dataset = VOCDetection(cfg.HEAD.DIR, image_sets=[
25 | ('PartA', 'trainval'), ('PartB', 'trainval')],
26 | target_transform=VOCAnnotationTransform(),
27 | mode='train',
28 | dataset_name='VOCPartAB')
29 | val_dataset = VOCDetection(cfg.HEAD.DIR, image_sets=[('PartA', 'test'), ('PartB', 'test')],
30 | target_transform=VOCAnnotationTransform(),
31 | mode='test',
32 | dataset_name='VOCPartAB')
33 | return train_dataset, val_dataset
34 |
35 |
36 | def detection_collate(batch):
37 | """Custom collate fn for dealing with batches of images that have a different
38 | number of associated object annotations (bounding boxes).
39 |
40 | Arguments:
41 | batch: (tuple) A tuple of tensor images and lists of annotations
42 |
43 | Return:
44 | A tuple containing:
45 | 1) (tensor) batch of images stacked on their 0 dim
46 | 2) (list of tensors) annotations for a given image are stacked on
47 | 0 dim
48 | """
49 | targets = []
50 | imgs = []
51 | for sample in batch:
52 | imgs.append(sample[0])
53 | targets.append(torch.FloatTensor(sample[1]))
54 | return torch.stack(imgs, 0), targets
55 |
--------------------------------------------------------------------------------
/data/vochead.py:
--------------------------------------------------------------------------------
1 | """VOC Dataset Classes
2 |
3 | Original author: Francisco Massa
4 | https://github.com/fmassa/vision/blob/voc_dataset/torchvision/datasets/voc.py
5 |
6 | Updated by: Ellis Brown, Max deGroot
7 | """
8 | from __future__ import division
9 | from __future__ import print_function
10 | from __future__ import absolute_import
11 |
12 | import os.path as osp
13 | import sys
14 | import torch
15 | import torch.utils.data as data
16 | import cv2
17 | import numpy as np
18 | import random
19 |
20 | if sys.version_info[0] == 2:
21 | import xml.etree.cElementTree as ET
22 | else:
23 | import xml.etree.ElementTree as ET
24 | from utils.augmentations import preprocess
25 | from PIL import ImageDraw, Image
26 |
27 |
28 | class VOCAnnotationTransform(object):
29 | """Transforms a VOC annotation into a Tensor of bbox coords and label index
30 | Initilized with a dictionary lookup of classnames to indexes
31 |
32 | Arguments:
33 | class_to_ind (dict, optional): dictionary lookup of classnames -> indexes
34 | (default: alphabetic indexing of VOC's 20 classes)
35 | keep_difficult (bool, optional): keep difficult instances or not
36 | (default: False)
37 | height (int): height
38 | width (int): width
39 | """
40 |
41 | def __init__(self, keep_difficult=False):
42 | self.keep_difficult = keep_difficult
43 |
44 | def __call__(self, target, width, height):
45 | """
46 | Arguments:
47 | target (annotation) : the target annotation to be made usable
48 | will be an ET.Element
49 | Returns:
50 | a list containing lists of bounding boxes [bbox coords, class name]
51 | """
52 | res = []
53 | for obj in target.iter('object'):
54 | difficult = int(obj.find('difficult').text) == 1
55 | if not self.keep_difficult and difficult:
56 | continue
57 | name = obj.find('name').text.lower().strip()
58 | bbox = obj.find('bndbox')
59 |
60 | pts = ['xmin', 'ymin', 'xmax', 'ymax']
61 | bndbox = [1]
62 | for i, pt in enumerate(pts):
63 | cur_pt = int(bbox.find(pt).text) - 1
64 | # scale height or width
65 | cur_pt = cur_pt / width if i % 2 == 0 else cur_pt / height
66 | bndbox.append(cur_pt)
67 | #label_idx = 1
68 | # bndbox.append(label_idx)
69 | res += [bndbox] # [xmin, ymin, xmax, ymax, label_ind]
70 | # img_id = target.find('filename').text[:-4]
71 | return res # [[xmin, ymin, xmax, ymax, label_ind], ... ]
72 |
73 |
74 | class VOCDetection(data.Dataset):
75 | """VOC Detection Dataset Object
76 |
77 | input is image, target is annotation
78 |
79 | Arguments:
80 | root (string): filepath to VOCdevkit folder.
81 | image_set (string): imageset to use (eg. 'train', 'val', 'test')
82 | transform (callable, optional): transformation to perform on the
83 | input image
84 | target_transform (callable, optional): transformation to perform on the
85 | target `annotation`
86 | (eg: take in caption string, return tensor of word indices)
87 | dataset_name (string, optional): which dataset to load
88 | (default: 'VOC2007')
89 | """
90 |
91 | def __init__(self, root,
92 | image_sets=[('PartA', 'trainval'),
93 | ('PartB', 'trainval')],
94 | target_transform=VOCAnnotationTransform(),
95 | mode='train',
96 | dataset_name='VOCPartAB'):
97 |
98 | self.root = root
99 | self.mode = mode
100 | self.image_set = image_sets
101 | self.target_transform = target_transform
102 | self.name = dataset_name
103 | self._annopath = osp.join('%s', 'Annotations', '%s.xml')
104 | self._imgpath = osp.join('%s', 'JPEGImages', '%s.jpg')
105 | self.ids = list()
106 | for (part, name) in image_sets:
107 | rootpath = osp.join(self.root, 'VOC' + part)
108 | for line in open(osp.join(rootpath, 'ImageSets', 'Main', name + '.txt')):
109 | self.ids.append((rootpath, line.strip()))
110 |
111 | def __getitem__(self, index):
112 | im, gt = self.pull_item(index)
113 |
114 | return im, gt
115 |
116 | def __len__(self):
117 | return len(self.ids)
118 |
119 | def pull_item(self, index):
120 | while True:
121 | img_id = self.ids[index]
122 | img_path = self._imgpath % img_id
123 | target = ET.parse(self._annopath % img_id).getroot()
124 | img = Image.open(img_path)
125 |
126 | if img.mode == 'L':
127 | img = img.convert('RGB')
128 |
129 | width, height = img.size
130 |
131 | if self.target_transform is not None:
132 | target = self.target_transform(target, width, height)
133 | bbox_labels = target
134 | target = np.array(target)
135 | if target.ndim!=2:
136 | index = random.randrange(0, len(self.ids))
137 | continue
138 | img, sample_labels = preprocess(
139 | img, bbox_labels, self.mode, img_path)
140 | sample_labels = np.array(sample_labels)
141 | if len(sample_labels) > 0:
142 | target = np.hstack(
143 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis]))
144 |
145 | assert (target[:, 2] > target[:, 0]).any()
146 | assert (target[:, 3] > target[:, 1]).any()
147 | break
148 | else:
149 | index = random.randrange(0, len(self.ids))
150 |
151 | return torch.from_numpy(img), target
152 |
153 | def pull_image(self, index):
154 | '''Returns the original image object at index in PIL form
155 |
156 | Note: not using self.__getitem__(), as any transformations passed in
157 | could mess up this functionality.
158 |
159 | Argument:
160 | index (int): index of img to show
161 | Return:
162 | PIL img
163 | '''
164 | img_id = self.ids[index]
165 | img_path = self._imgpath % img_id
166 | img = Image.open(img_path)
167 | if img.mode=='L':
168 | img.convert('RGB')
169 | img = np.array(img)
170 | return img
171 |
172 | def pull_anno(self, index):
173 | '''Returns the original annotation of image at index
174 |
175 | Note: not using self.__getitem__(), as any transformations passed in
176 | could mess up this functionality.
177 |
178 | Argument:
179 | index (int): index of img to get annotation of
180 | Return:
181 | list: [img_id, [(label, bbox coords),...]]
182 | eg: ('001718', [('dog', (96, 13, 438, 332))])
183 | '''
184 | img_id = self.ids[index]
185 | anno = ET.parse(self._annopath % img_id).getroot()
186 | gt = self.target_transform(anno, 1, 1)
187 | return img_id[1], gt
188 |
189 | def pull_tensor(self, index):
190 | '''Returns the original image at an index in tensor form
191 |
192 | Note: not using self.__getitem__(), as any transformations passed in
193 | could mess up this functionality.
194 |
195 | Argument:
196 | index (int): index of img to show
197 | Return:
198 | tensorized version of img, squeezed
199 | '''
200 | return torch.Tensor(self.pull_image(index)).unsqueeze_(0)
201 |
202 |
203 | if __name__ == '__main__':
204 | from config import cfg
205 | dataset = VOCDetection(cfg.HEAD.DIR)
206 | dataset.pull_item(0)
207 |
--------------------------------------------------------------------------------
/data/widerface.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import absolute_import
4 | from __future__ import division
5 | from __future__ import print_function
6 |
7 | import torch
8 | from PIL import Image, ImageDraw
9 | import torch.utils.data as data
10 | import numpy as np
11 | import random
12 | from utils.augmentations import preprocess
13 |
14 |
15 | class WIDERDetection(data.Dataset):
16 | """docstring for WIDERDetection"""
17 |
18 | def __init__(self, list_file, mode='train'):
19 | super(WIDERDetection, self).__init__()
20 | self.mode = mode
21 | self.fnames = []
22 | self.boxes = []
23 | self.labels = []
24 |
25 | with open(list_file) as f:
26 | lines = f.readlines()
27 |
28 | for line in lines:
29 | line = line.strip().split()
30 | num_faces = int(line[1])
31 | box = []
32 | label = []
33 | for i in xrange(num_faces):
34 | x = float(line[2 + 5 * i])
35 | y = float(line[3 + 5 * i])
36 | w = float(line[4 + 5 * i])
37 | h = float(line[5 + 5 * i])
38 | c = int(line[6 + 5 * i])
39 | if w <= 0 or h <= 0:
40 | continue
41 | box.append([x, y, x + w, y + h])
42 | label.append(c)
43 | if len(box) > 0:
44 | self.fnames.append(line[0])
45 | self.boxes.append(box)
46 | self.labels.append(label)
47 |
48 | self.num_samples = len(self.boxes)
49 |
50 | def __len__(self):
51 | return self.num_samples
52 |
53 | def __getitem__(self, index):
54 | img, target, h, w = self.pull_item(index)
55 | return img, target
56 |
57 | def pull_item(self, index):
58 | while True:
59 | image_path = self.fnames[index]
60 | img = Image.open(image_path)
61 | if img.mode == 'L':
62 | img = img.convert('RGB')
63 |
64 | im_width, im_height = img.size
65 | boxes = self.annotransform(
66 | np.array(self.boxes[index]), im_width, im_height)
67 | label = np.array(self.labels[index])
68 | bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist()
69 | img, sample_labels = preprocess(
70 | img, bbox_labels, self.mode, image_path)
71 | sample_labels = np.array(sample_labels)
72 | if len(sample_labels) > 0:
73 | target = np.hstack(
74 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis]))
75 |
76 | assert (target[:, 2] > target[:, 0]).any()
77 | assert (target[:, 3] > target[:, 1]).any()
78 | break
79 | else:
80 | index = random.randrange(0, self.num_samples)
81 |
82 |
83 | #img = Image.fromarray(img)
84 | '''
85 | draw = ImageDraw.Draw(img)
86 | w,h = img.size
87 | for bbox in sample_labels:
88 | bbox = (bbox[1:] * np.array([w, h, w, h])).tolist()
89 |
90 | draw.rectangle(bbox,outline='red')
91 | img.save('image.jpg')
92 | '''
93 | return torch.from_numpy(img), target, im_height, im_width
94 |
95 |
96 | def annotransform(self, boxes, im_width, im_height):
97 | boxes[:, 0] /= im_width
98 | boxes[:, 1] /= im_height
99 | boxes[:, 2] /= im_width
100 | boxes[:, 3] /= im_height
101 | return boxes
102 |
103 |
104 | def detection_collate(batch):
105 | """Custom collate fn for dealing with batches of images that have a different
106 | number of associated object annotations (bounding boxes).
107 |
108 | Arguments:
109 | batch: (tuple) A tuple of tensor images and lists of annotations
110 |
111 | Return:
112 | A tuple containing:
113 | 1) (tensor) batch of images stacked on their 0 dim
114 | 2) (list of tensors) annotations for a given image are stacked on
115 | 0 dim
116 | """
117 | targets = []
118 | imgs = []
119 | for sample in batch:
120 | imgs.append(sample[0])
121 | targets.append(torch.FloatTensor(sample[1]))
122 | return torch.stack(imgs, 0), targets
123 |
124 |
125 | if __name__ == '__main__':
126 | from config import cfg
127 | dataset = WIDERDetection(cfg.FACE.TRAIN_FILE)
128 | #for i in range(len(dataset)):
129 | dataset.pull_item(14)
130 |
--------------------------------------------------------------------------------
/demo.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import torch
9 | import argparse
10 | import torch.nn as nn
11 | import torch.utils.data as data
12 | import torch.backends.cudnn as cudnn
13 | import torchvision.transforms as transforms
14 |
15 | import cv2
16 | import time
17 | import numpy as np
18 | from PIL import Image
19 |
20 | from data.config import cfg
21 | from s3fd import build_s3fd
22 | from torch.autograd import Variable
23 | from utils.augmentations import to_chw_bgr
24 |
25 |
26 | parser = argparse.ArgumentParser(description='s3df demo')
27 | parser.add_argument('--save_dir', type=str, default='tmp/',
28 | help='Directory for detect result')
29 | parser.add_argument('--model', type=str,
30 | default='weights/s3fd.pth', help='trained model')
31 | parser.add_argument('--thresh', default=0.6, type=float,
32 | help='Final confidence threshold')
33 | args = parser.parse_args()
34 |
35 |
36 | if not os.path.exists(args.save_dir):
37 | os.makedirs(args.save_dir)
38 |
39 | use_cuda = torch.cuda.is_available()
40 |
41 | if use_cuda:
42 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
43 | else:
44 | torch.set_default_tensor_type('torch.FloatTensor')
45 |
46 |
47 | def detect(net, img_path, thresh):
48 | #img = cv2.imread(img_path, cv2.IMREAD_COLOR)
49 | img = Image.open(img_path)
50 | if img.mode == 'L':
51 | img = img.convert('RGB')
52 |
53 | img = np.array(img)
54 | height, width, _ = img.shape
55 | max_im_shrink = np.sqrt(
56 | 1700 * 1200 / (img.shape[0] * img.shape[1]))
57 | image = cv2.resize(img, None, None, fx=max_im_shrink,
58 | fy=max_im_shrink, interpolation=cv2.INTER_LINEAR)
59 | #image = cv2.resize(img, (640, 640))
60 | x = to_chw_bgr(image)
61 | x = x.astype('float32')
62 | x -= cfg.img_mean
63 | x = x[[2, 1, 0], :, :]
64 |
65 | x = Variable(torch.from_numpy(x).unsqueeze(0))
66 | if use_cuda:
67 | x = x.cuda()
68 | t1 = time.time()
69 | y = net(x)
70 | detections = y.data
71 | scale = torch.Tensor([img.shape[1], img.shape[0],
72 | img.shape[1], img.shape[0]])
73 |
74 | img = cv2.imread(img_path, cv2.IMREAD_COLOR)
75 |
76 | for i in range(detections.size(1)):
77 | j = 0
78 | while detections[0, i, j, 0] >= thresh:
79 | score = detections[0, i, j, 0]
80 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy()
81 | left_up, right_bottom = (pt[0], pt[1]), (pt[2], pt[3])
82 | j += 1
83 | cv2.rectangle(img, left_up, right_bottom, (0, 0, 255), 2)
84 | conf = "{:.3f}".format(score)
85 | point = (int(left_up[0]), int(left_up[1] - 5))
86 | #cv2.putText(img, conf, point, cv2.FONT_HERSHEY_COMPLEX,
87 | # 0.6, (0, 255, 0), 1)
88 |
89 | t2 = time.time()
90 | print('detect:{} timer:{}'.format(img_path, t2 - t1))
91 |
92 | cv2.imwrite(os.path.join(args.save_dir, os.path.basename(img_path)), img)
93 |
94 |
95 | if __name__ == '__main__':
96 | net = build_s3fd('test', cfg.NUM_CLASSES)
97 | net.load_state_dict(torch.load(args.model))
98 | net.eval()
99 |
100 | if use_cuda:
101 | net.cuda()
102 | cudnn.benckmark = True
103 |
104 | img_path = './img'
105 | img_list = [os.path.join(img_path, x)
106 | for x in os.listdir(img_path) if x.endswith('jpg')]
107 | for path in img_list:
108 | detect(net, path, args.thresh)
109 |
--------------------------------------------------------------------------------
/eval_tools/boxoverlap.m:
--------------------------------------------------------------------------------
1 | function o = boxoverlap(a, b)
2 | % Compute the symmetric intersection over union overlap between a set of
3 | % bounding boxes in a and a single bounding box in b.
4 | %
5 | % a a matrix where each row specifies a bounding box
6 | % b a single bounding box
7 |
8 | % AUTORIGHTS
9 | % -------------------------------------------------------
10 | % Copyright (C) 2011-2012 Ross Girshick
11 | % Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick
12 | %
13 | % This file is part of the voc-releaseX code
14 | % (http://people.cs.uchicago.edu/~rbg/latent/)
15 | % and is available under the terms of an MIT-like license
16 | % provided in COPYING. Please retain this notice and
17 | % COPYING if you use this file (or a portion of it) in
18 | % your project.
19 | % -------------------------------------------------------
20 |
21 | x1 = max(a(:,1), b(1));
22 | y1 = max(a(:,2), b(2));
23 | x2 = min(a(:,3), b(3));
24 | y2 = min(a(:,4), b(4));
25 |
26 | w = x2-x1+1;
27 | h = y2-y1+1;
28 | inter = w.*h;
29 | aarea = (a(:,3)-a(:,1)+1) .* (a(:,4)-a(:,2)+1);
30 | barea = (b(3)-b(1)+1) * (b(4)-b(2)+1);
31 | % intersection over union overlap
32 | o = inter ./ (aarea+barea-inter);
33 | % set invalid entries to 0 overlap
34 | o(w <= 0) = 0;
35 | o(h <= 0) = 0;
36 |
--------------------------------------------------------------------------------
/eval_tools/evaluation.m:
--------------------------------------------------------------------------------
1 | function evaluation(norm_pred_list,gt_dir,setting_name,setting_class,legend_name)
2 | load(gt_dir);
3 | if ~exist(sprintf('./plot/baselines/Val/%s/%s',setting_class,legend_name),'dir')
4 | mkdir(sprintf('./plot/baselines/Val/%s/%s',setting_class,legend_name));
5 | end
6 | IoU_thresh = 0.5;
7 | event_num = 61;
8 | thresh_num = 1000;
9 | org_pr_cruve = zeros(thresh_num,2);
10 | count_face = 0;
11 |
12 | for i = 1:event_num
13 | img_list = file_list{i};
14 | gt_bbx_list = face_bbx_list{i};
15 | pred_list = norm_pred_list{i};
16 | sub_gt_list = gt_list{i};
17 | img_pr_info_list = cell(length(img_list),1);
18 |
19 | fprintf('%s, current event %d\n',setting_name,i);
20 | for j = 1:length(img_list)
21 | gt_bbx = gt_bbx_list{j};
22 | pred_info = pred_list{j};
23 | keep_index = sub_gt_list{j};
24 | count_face = count_face + length(keep_index);
25 |
26 | if isempty(gt_bbx) || isempty(pred_info)
27 | continue;
28 | end
29 | ignore = zeros(size(gt_bbx,1),1);
30 | if ~isempty(keep_index)
31 | ignore(keep_index) = 1;
32 | end
33 |
34 | [pred_recall, proposal_list] = image_evaluation(pred_info, gt_bbx, ignore, IoU_thresh);
35 |
36 | img_pr_info = image_pr_info(thresh_num, pred_info, proposal_list, pred_recall);
37 | img_pr_info_list{j} = img_pr_info;
38 | end
39 | for j = 1:length(img_list)
40 | img_pr_info = img_pr_info_list{j};
41 | if ~isempty(img_pr_info)
42 | org_pr_cruve(:,1) = org_pr_cruve(:,1) + img_pr_info(:,1);
43 | org_pr_cruve(:,2) = org_pr_cruve(:,2) + img_pr_info(:,2);
44 | end
45 | end
46 | end
47 | pr_cruve = dataset_pr_info(thresh_num, org_pr_cruve, count_face);
48 | save(sprintf('./plot/baselines/Val/%s/%s/wider_pr_info_%s_%s.mat',setting_class,legend_name,legend_name,setting_name),'pr_cruve','legend_name','-v7.3');
49 | end
50 |
51 | function [pred_recall,proposal_list] = image_evaluation(pred_info, gt_bbx, ignore, IoU_thresh)
52 | pred_recall = zeros(size(pred_info,1),1);
53 | recall_list = zeros(size(gt_bbx,1),1);
54 | proposal_list = zeros(size(pred_info,1),1);
55 | proposal_list = proposal_list + 1;
56 | pred_info(:,3) = pred_info(:,1) + pred_info(:,3);
57 | pred_info(:,4) = pred_info(:,2) + pred_info(:,4);
58 | gt_bbx(:,3) = gt_bbx(:,1) + gt_bbx(:,3);
59 | gt_bbx(:,4) = gt_bbx(:,2) + gt_bbx(:,4);
60 | for h = 1:size(pred_info,1)
61 | overlap_list = boxoverlap(gt_bbx, pred_info(h,1:4));
62 | [max_overlap, idx] = max(overlap_list);
63 | if max_overlap >= IoU_thresh
64 | if (ignore(idx) == 0)
65 | recall_list(idx) = -1;
66 | proposal_list(h) = -1;
67 | elseif (recall_list(idx)==0)
68 | recall_list(idx) = 1;
69 | end
70 | end
71 | r_keep_index = find(recall_list == 1);
72 | pred_recall(h) = length(r_keep_index);
73 | end
74 | end
75 |
76 | function img_pr_info = image_pr_info(thresh_num, pred_info, proposal_list, pred_recall)
77 | img_pr_info = zeros(thresh_num,2);
78 | for t = 1:thresh_num
79 | thresh = 1-t/thresh_num;
80 | r_index = find(pred_info(:,5)>=thresh,1,'last');
81 | if (isempty(r_index))
82 | img_pr_info(t,2) = 0;
83 | img_pr_info(t,1) = 0;
84 | else
85 | p_index = find(proposal_list(1:r_index) == 1);
86 | img_pr_info(t,1) = length(p_index);
87 | img_pr_info(t,2) = pred_recall(r_index);
88 | end
89 | end
90 | end
91 |
92 | function pr_cruve = dataset_pr_info(thresh_num, org_pr_cruve, count_face)
93 | pr_cruve = zeros(thresh_num,2);
94 | for i = 1:thresh_num
95 | pr_cruve(i,1) = org_pr_cruve(i,2)/org_pr_cruve(i,1);
96 | pr_cruve(i,2) = org_pr_cruve(i,2)/count_face;
97 | end
98 | end
99 |
--------------------------------------------------------------------------------
/eval_tools/ground_truth/wider_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/ground_truth/wider_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/ground_truth/wider_face_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/ground_truth/wider_face_val.mat
--------------------------------------------------------------------------------
/eval_tools/ground_truth/wider_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/ground_truth/wider_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/ground_truth/wider_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/ground_truth/wider_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/nms.m:
--------------------------------------------------------------------------------
1 | function pick = nms(boxes, overlap)
2 | % top = nms(boxes, overlap)
3 | % Non-maximum suppression. (FAST VERSION)
4 | % Greedily select high-scoring detections and skip detections
5 | % that are significantly covered by a previously selected
6 | % detection.
7 | %
8 | % NOTE: This is adapted from Pedro Felzenszwalb's version (nms.m),
9 | % but an inner loop has been eliminated to significantly speed it
10 | % up in the case of a large number of boxes
11 |
12 | % Copyright (C) 2011-12 by Tomasz Malisiewicz
13 | % All rights reserved.
14 | %
15 | % This file is part of the Exemplar-SVM library and is made
16 | % available under the terms of the MIT license (see COPYING file).
17 | % Project homepage: https://github.com/quantombone/exemplarsvm
18 |
19 |
20 | if isempty(boxes)
21 | pick = [];
22 | return;
23 | end
24 |
25 | x1 = boxes(:,1);
26 | y1 = boxes(:,2);
27 | x2 = boxes(:,3);
28 | y2 = boxes(:,4);
29 | s = boxes(:,end);
30 |
31 | area = (x2-x1+1) .* (y2-y1+1);
32 | [vals, I] = sort(s);
33 |
34 | pick = s*0;
35 | counter = 1;
36 | while ~isempty(I)
37 | last = length(I);
38 | i = I(last);
39 | pick(counter) = i;
40 | counter = counter + 1;
41 |
42 | xx1 = max(x1(i), x1(I(1:last-1)));
43 | yy1 = max(y1(i), y1(I(1:last-1)));
44 | xx2 = min(x2(i), x2(I(1:last-1)));
45 | yy2 = min(y2(i), y2(I(1:last-1)));
46 |
47 | w = max(0.0, xx2-xx1+1);
48 | h = max(0.0, yy2-yy1+1);
49 |
50 | inter = w.*h;
51 | o = inter ./ (area(i) + area(I(1:last-1)) - inter);
52 |
53 | I = I(find(o<=overlap));
54 | end
55 |
56 | pick = pick(1:(counter-1));
--------------------------------------------------------------------------------
/eval_tools/norm_score.m:
--------------------------------------------------------------------------------
1 | function norm_pred_list = norm_score(org_pred_list)
2 |
3 | event_num = 61;
4 | norm_pred_list = cell(event_num,1);
5 | max_score = realmin('single');
6 | min_score = realmax('single');
7 | parfor i = 1:event_num
8 | pred_list = org_pred_list{i};
9 | for j = 1:size(pred_list,1)
10 | if(isempty(pred_list{j}))
11 | continue;
12 | end
13 | score_list = pred_list{j}(:,5);
14 | max_score = max(max_score,max(score_list));
15 | min_score = min(min_score,min(score_list));
16 | end
17 | end
18 |
19 | parfor i = 1:event_num
20 | fprintf('Norm prediction: current event %d\n',i);
21 | pred_list = org_pred_list{i};
22 | for j = 1:size(pred_list,1)
23 | if(isempty(pred_list{j}))
24 | continue;
25 | end
26 | score_list = pred_list{j}(:,5);
27 | norm_score_list = (score_list - min_score)/(max_score - min_score);
28 | pred_list{j}(:,5) = norm_score_list;
29 | end
30 | norm_pred_list{i} = pred_list;
31 | end
32 |
--------------------------------------------------------------------------------
/eval_tools/plot/VOCap.m:
--------------------------------------------------------------------------------
1 | function ap = VOCap(rec,prec)
2 |
3 | mrec=[0 ; rec ; 1];
4 | mpre=[0 ; prec ; 0];
5 | for i=numel(mpre)-1:-1:1
6 | mpre(i)=max(mpre(i),mpre(i+1));
7 | end
8 | i=find(mrec(2:end)~=mrec(1:end-1))+1;
9 | ap=sum((mrec(i)-mrec(i-1)).*mpre(i));
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/LDCF+/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/LDCF+/.DS_Store
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FANet/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FANet/.DS_Store
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium_val.mat
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_ext_easy.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_ext_easy.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_ext_hard.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_ext_hard.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_ext_medium.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_ext_medium.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_int_easy.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_int_easy.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_int_hard.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_int_hard.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Test/wider_pr_cruve_int_medium.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Test/wider_pr_cruve_int_medium.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Val/wider_pr_cruve_int_easy_val.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Val/wider_pr_cruve_int_easy_val.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Val/wider_pr_cruve_int_hard_val.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Val/wider_pr_cruve_int_hard_val.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/figure/Val/wider_pr_cruve_int_medium_val.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/plot/figure/Val/wider_pr_cruve_int_medium_val.pdf
--------------------------------------------------------------------------------
/eval_tools/plot/plot_pr.m:
--------------------------------------------------------------------------------
1 | function plot_pr(propose,recall,lendge_name,seting_class,setting_name,dateset_class)
2 | model_num = size(propose,1);
3 | figure1 = figure('PaperSize',[20.98 29.68],'Color',[1 1 1], 'rend','painters','pos',[1 1 800 400]);
4 | axes1 = axes('Parent',figure1,...
5 | 'LineWidth',2,...
6 | 'FontSize',10,...
7 | 'FontName','Times New Roman',...
8 | 'FontWeight','bold');
9 | box(axes1,'on');
10 | hold on;
11 |
12 | LineColor = colormap(hsv(model_num));
13 | for i=1:model_num
14 | plot(propose{i},recall{i},...
15 | 'MarkerEdgeColor',LineColor(i,:),...
16 | 'MarkerFaceColor',LineColor(i,:),...
17 | 'LineWidth',3,...
18 | 'Color',LineColor(i,:))
19 | grid on;
20 | hold on;
21 | end
22 | legend1 = legend(lendge_name,'show');
23 | set(legend1,'Location','EastOutside');
24 |
25 | xlim([0,1]);
26 | ylim([0,1]);
27 | xlabel('Recall');
28 | ylabel('Precision');
29 |
30 | savename = sprintf('./plot/figure/%s/wider_pr_cruve_%s_%s.pdf',dateset_class,seting_class,setting_name);
31 | saveTightFigure(gcf,savename);
32 | clear gcf;
33 | hold off;
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/eval_tools/plot/saveTightFigure.m:
--------------------------------------------------------------------------------
1 | function saveTightFigure(h,outfilename)
2 | % SAVETIGHTFIGURE(OUTFILENAME) Saves the current figure without the white
3 | % space/margin around it to the file OUTFILENAME. Output file type is
4 | % determined by the extension of OUTFILENAME. All formats that are
5 | % supported by MATLAB's "saveas" are supported.
6 | %
7 | % SAVETIGHTFIGURE(H, OUTFILENAME) Saves the figure with handle H.
8 | %
9 | % E Akbas (c) Aug 2010
10 | % * Updated to handle subplots and multiple axes. March 2014.
11 | %
12 |
13 | if nargin==1
14 | hfig = gcf;
15 | outfilename = h;
16 | else
17 | hfig = h;
18 | end
19 |
20 | %% find all the axes in the figure
21 | hax = findall(hfig, 'type', 'axes');
22 |
23 | %% compute the tighest box that includes all axes
24 | tighest_box = [Inf Inf -Inf -Inf]; % left bottom right top
25 | for i=1:length(hax)
26 | set(hax(i), 'units', 'centimeters');
27 |
28 | p = get(hax(i), 'position');
29 | ti = get(hax(i), 'tightinset');
30 |
31 | % get position as left, bottom, right, top
32 | p = [p(1) p(2) p(1)+p(3) p(2)+p(4)] + ti.*[-1 -1 1 1];
33 |
34 | tighest_box(1) = min(tighest_box(1), p(1));
35 | tighest_box(2) = min(tighest_box(2), p(2));
36 | tighest_box(3) = max(tighest_box(3), p(3));
37 | tighest_box(4) = max(tighest_box(4), p(4));
38 | end
39 |
40 | %% move all axes to left-bottom
41 | for i=1:length(hax)
42 | if strcmp(get(hax(i),'tag'),'legend')
43 | continue
44 | end
45 | p = get(hax(i), 'position');
46 | set(hax(i), 'position', [p(1)-tighest_box(1) p(2)-tighest_box(2) p(3) p(4)]);
47 | end
48 |
49 | %% resize figure to fit tightly
50 | set(hfig, 'units', 'centimeters');
51 | p = get(hfig, 'position');
52 |
53 | width = tighest_box(3)-tighest_box(1);
54 | height = tighest_box(4)-tighest_box(2);
55 | set(hfig, 'position', [p(1) p(2) p(3) p(4)]);
56 |
57 | %% set papersize
58 | set(hfig,'PaperUnits','centimeters');
59 | set(hfig,'PaperSize', [width height]);
60 | set(hfig,'PaperPositionMode', 'manual');
61 | set(hfig,'PaperPosition',[0 0 width height]);
62 |
63 |
64 | %% save
65 | saveas(hfig,outfilename);
66 |
--------------------------------------------------------------------------------
/eval_tools/plot/wider_plot.m:
--------------------------------------------------------------------------------
1 | function wider_plot(set_list,dir_ext,seting_class,dateset_class)
2 |
3 | method_list = dir(dir_ext);
4 | model_num = size(method_list,1) - 2;
5 | model_name = cell(model_num,1);
6 |
7 | for i = 3:size(method_list,1)
8 | model_name{i-2} = method_list(i).name;
9 | end
10 |
11 | for i = 1:size(set_list,1)
12 | propose = cell(model_num,1);
13 | recall = cell(model_num,1);
14 | name_list = cell(model_num,1);
15 | ap_list = zeros(model_num,1);
16 | for j = 1:model_num
17 | load(sprintf('%s/%s/wider_pr_info_%s_%s.mat',dir_ext, model_name{j}, model_name{j}, set_list{i}));
18 | propose{j} = pr_cruve(:,2);
19 | recall{j} = pr_cruve(:,1);
20 | ap = VOCap(propose{j},recall{j});
21 | ap_list(j) = ap;
22 | ap = num2str(ap);
23 | if length(ap) < 5
24 | name_list{j} = [legend_name '-' ap];
25 | else
26 | name_list{j} = [legend_name '-' ap(1:5)];
27 | end
28 | end
29 | [~,index] = sort(ap_list,'descend');
30 | propose = propose(index);
31 | recall = recall(index);
32 | name_list = name_list(index);
33 | plot_pr(propose, recall, name_list, seting_class, set_list{i},dateset_class);
34 | end
35 |
--------------------------------------------------------------------------------
/eval_tools/read_pred.m:
--------------------------------------------------------------------------------
1 | function pred_list = read_pred(file_dir, gt_dir)
2 |
3 | load(gt_dir);
4 | event_num = 61;
5 | pred_list = cell(event_num,1);
6 |
7 | for i = 1:event_num
8 | fprintf('Read prediction: current event %d\n',i);
9 | img_list = file_list{i};
10 | img_num = size(img_list,1);
11 | bbx_list = cell(img_num,1);
12 | for j = 1:img_num
13 | if ~exist(sprintf('%s/%s/%s.txt',file_dir,event_list{i},img_list{j}),'file')
14 | fprintf('Can not find the prediction file %s %s \n',event_list{i},img_list{j});
15 | continue;
16 | end
17 |
18 | fid = fopen(sprintf('%s/%s/%s.txt',file_dir,event_list{i},img_list{j}),'r');
19 | tmp = textscan(fid,'%s','Delimiter','\n');
20 | tmp = tmp{1};
21 | fclose(fid);
22 | try
23 | bbx_num = tmp{2,1};
24 | bbx_num = str2num(bbx_num);
25 | bbx = zeros(bbx_num,5);
26 | if bbx_num ==0
27 | continue;
28 | end
29 | for k = 1:bbx_num
30 | raw_info = str2num(tmp{k+2,1});
31 | bbx(k,1) = raw_info(1);
32 | bbx(k,2) = raw_info(2);
33 | bbx(k,3) = raw_info(3);
34 | bbx(k,4) = raw_info(4);
35 | bbx(k,5) = raw_info(5);
36 | end
37 | [~, s_index] = sort(bbx(:,5),'descend');
38 | bbx_list{j} = bbx(s_index,:);
39 | catch
40 | fprintf('Invalid format %s %s\n',event_list{i},img_list{j});
41 | end
42 | end
43 | pred_list{i} = bbx_list;
44 | end
45 |
--------------------------------------------------------------------------------
/eval_tools/wider_eval.m:
--------------------------------------------------------------------------------
1 | % WIDER FACE Evaluation
2 | % Conduct the evaluation on the WIDER FACE validation set.
3 | %
4 | % Shuo Yang Dec 2015
5 | %
6 | clear;
7 | close all;
8 | addpath(genpath('./plot'));
9 | %Please specify your prediction directory.
10 | pred_dir = './sfd_val';
11 | gt_dir = './ground_truth/wider_face_val.mat';
12 | %preprocessing
13 | pred_list = read_pred(pred_dir,gt_dir);
14 | norm_pred_list = norm_score(pred_list);
15 |
16 | %evaluate on different settings
17 | setting_name_list = {'easy_val';'medium_val';'hard_val'};
18 | setting_class = 'setting_int';
19 |
20 | %Please specify your algorithm name.
21 | legend_name = 's3fd.pytorch';
22 | for i = 1:size(setting_name_list,1)
23 | fprintf('Current evaluation setting %s\n',setting_name_list{i});
24 | setting_name = setting_name_list{i};
25 | gt_dir = sprintf('./ground_truth/wider_%s.mat',setting_name);
26 | evaluation(norm_pred_list,gt_dir,setting_name,setting_class,legend_name);
27 | end
28 |
29 | fprintf('Plot pr curve under overall setting.\n');
30 | dateset_class = 'Val';
31 |
32 | % scenario-Int:
33 | seting_class = 'int';
34 | dir_int = sprintf('./plot/baselines/%s/setting_%s',dateset_class, seting_class);
35 | wider_plot(setting_name_list,dir_int,seting_class,dateset_class);
36 |
--------------------------------------------------------------------------------
/eval_tools/wider_face_test.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/wider_face_test.mat
--------------------------------------------------------------------------------
/eval_tools/wider_face_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/eval_tools/wider_face_val.mat
--------------------------------------------------------------------------------
/img/0_Parade_marchingband_1_465.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/0_Parade_marchingband_1_465.jpg
--------------------------------------------------------------------------------
/img/AFW.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/AFW.png
--------------------------------------------------------------------------------
/img/FDDB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/FDDB.png
--------------------------------------------------------------------------------
/img/anchor_match.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/anchor_match.png
--------------------------------------------------------------------------------
/img/pascal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/pascal.png
--------------------------------------------------------------------------------
/img/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/test.jpg
--------------------------------------------------------------------------------
/img/test2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/img/test2.jpg
--------------------------------------------------------------------------------
/layers/__init__.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | from .functions import *
9 | from .modules import *
10 |
--------------------------------------------------------------------------------
/layers/bbox_utils.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | import torch
9 |
10 |
11 | def point_form(boxes):
12 | """ Convert prior_boxes to (xmin, ymin, xmax, ymax)
13 | representation for comparison to point form ground truth data.
14 | Args:
15 | boxes: (tensor) center-size default boxes from priorbox layers.
16 | Return:
17 | boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes.
18 | """
19 | return torch.cat((boxes[:, :2] - boxes[:, 2:] / 2, # xmin, ymin
20 | boxes[:, :2] + boxes[:, 2:] / 2), 1) # xmax, ymax
21 |
22 |
23 | def center_size(boxes):
24 | """ Convert prior_boxes to (cx, cy, w, h)
25 | representation for comparison to center-size form ground truth data.
26 | Args:
27 | boxes: (tensor) point_form boxes
28 | Return:
29 | boxes: (tensor) Converted xmin, ymin, xmax, ymax form of boxes.
30 | """
31 | return torch.cat([(boxes[:, 2:] + boxes[:, :2]) / 2, # cx, cy
32 | boxes[:, 2:] - boxes[:, :2]], 1) # w, h
33 |
34 |
35 | def intersect(box_a, box_b):
36 | """ We resize both tensors to [A,B,2] without new malloc:
37 | [A,2] -> [A,1,2] -> [A,B,2]
38 | [B,2] -> [1,B,2] -> [A,B,2]
39 | Then we compute the area of intersect between box_a and box_b.
40 | Args:
41 | box_a: (tensor) bounding boxes, Shape: [A,4].
42 | box_b: (tensor) bounding boxes, Shape: [B,4].
43 | Return:
44 | (tensor) intersection area, Shape: [A,B].
45 | """
46 | A = box_a.size(0)
47 | B = box_b.size(0)
48 | max_xy = torch.min(box_a[:, 2:].unsqueeze(1).expand(A, B, 2),
49 | box_b[:, 2:].unsqueeze(0).expand(A, B, 2))
50 | min_xy = torch.max(box_a[:, :2].unsqueeze(1).expand(A, B, 2),
51 | box_b[:, :2].unsqueeze(0).expand(A, B, 2))
52 | inter = torch.clamp((max_xy - min_xy), min=0)
53 | return inter[:, :, 0] * inter[:, :, 1]
54 |
55 |
56 | def jaccard(box_a, box_b):
57 | """Compute the jaccard overlap of two sets of boxes. The jaccard overlap
58 | is simply the intersection over union of two boxes. Here we operate on
59 | ground truth boxes and default boxes.
60 | E.g.:
61 | A ∩ B / A ∪ B = A ∩ B / (area(A) + area(B) - A ∩ B)
62 | Args:
63 | box_a: (tensor) Ground truth bounding boxes, Shape: [num_objects,4]
64 | box_b: (tensor) Prior boxes from priorbox layers, Shape: [num_priors,4]
65 | Return:
66 | jaccard overlap: (tensor) Shape: [box_a.size(0), box_b.size(0)]
67 | """
68 | inter = intersect(box_a, box_b)
69 | area_a = ((box_a[:, 2] - box_a[:, 0]) *
70 | (box_a[:, 3] - box_a[:, 1])).unsqueeze(1).expand_as(inter) # [A,B]
71 | area_b = ((box_b[:, 2] - box_b[:, 0]) *
72 | (box_b[:, 3] - box_b[:, 1])).unsqueeze(0).expand_as(inter) # [A,B]
73 | union = area_a + area_b - inter
74 | return inter / union # [A,B]
75 |
76 |
77 | def match(threshold, truths, priors, variances, labels, loc_t, conf_t, idx):
78 | """Match each prior box with the ground truth box of the highest jaccard
79 | overlap, encode the bounding boxes, then return the matched indices
80 | corresponding to both confidence and location preds.
81 | Args:
82 | threshold: (float) The overlap threshold used when mathing boxes.
83 | truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors].
84 | priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4].
85 | variances: (tensor) Variances corresponding to each prior coord,
86 | Shape: [num_priors, 4].
87 | labels: (tensor) All the class labels for the image, Shape: [num_obj].
88 | loc_t: (tensor) Tensor to be filled w/ endcoded location targets.
89 | conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds.
90 | idx: (int) current batch index
91 | Return:
92 | The matched indices corresponding to 1)location and 2)confidence preds.
93 | """
94 | # jaccard index
95 | overlaps = jaccard(
96 | truths,
97 | point_form(priors)
98 | )
99 | # (Bipartite Matching)
100 | # [1,num_objects] best prior for each ground truth
101 | best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True)
102 | # [1,num_priors] best ground truth for each prior
103 | best_truth_overlap, best_truth_idx = overlaps.max(
104 | 0, keepdim=True) # 0-2000
105 | best_truth_idx.squeeze_(0)
106 | best_truth_overlap.squeeze_(0)
107 | best_prior_idx.squeeze_(1)
108 | best_prior_overlap.squeeze_(1)
109 | best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior
110 | # TODO refactor: index best_prior_idx with long tensor
111 | # ensure every gt matches with its prior of max overlap
112 | for j in range(best_prior_idx.size(0)):
113 | best_truth_idx[best_prior_idx[j]] = j
114 | _th1, _th2, _th3 = threshold # _th1 = 0.1 ,_th2 = 0.35,_th3 = 0.5
115 |
116 | N = (torch.sum(best_prior_overlap >= _th2) +
117 | torch.sum(best_prior_overlap >= _th3)) // 2
118 | matches = truths[best_truth_idx] # Shape: [num_priors,4]
119 | conf = labels[best_truth_idx] # Shape: [num_priors]
120 | conf[best_truth_overlap < _th2] = 0 # label as background
121 |
122 | best_truth_overlap_clone = best_truth_overlap.clone()
123 | add_idx = best_truth_overlap_clone.gt(
124 | _th1).eq(best_truth_overlap_clone.lt(_th2))
125 | best_truth_overlap_clone[1 - add_idx] = 0
126 | stage2_overlap, stage2_idx = best_truth_overlap_clone.sort(descending=True)
127 |
128 | stage2_overlap = stage2_overlap.gt(_th1)
129 |
130 | if N > 0:
131 | N = torch.sum(stage2_overlap[:N]) if torch.sum(
132 | stage2_overlap[:N]) < N else N
133 | conf[stage2_idx[:N]] += 1
134 |
135 | loc = encode(matches, priors, variances)
136 | loc_t[idx] = loc # [num_priors,4] encoded offsets to learn
137 | conf_t[idx] = conf # [num_priors] top class label for each prior
138 |
139 |
140 | def match_ssd(threshold, truths, priors, variances, labels, loc_t, conf_t, idx):
141 | """Match each prior box with the ground truth box of the highest jaccard
142 | overlap, encode the bounding boxes, then return the matched indices
143 | corresponding to both confidence and location preds.
144 | Args:
145 | threshold: (float) The overlap threshold used when mathing boxes.
146 | truths: (tensor) Ground truth boxes, Shape: [num_obj, num_priors].
147 | priors: (tensor) Prior boxes from priorbox layers, Shape: [n_priors,4].
148 | variances: (tensor) Variances corresponding to each prior coord,
149 | Shape: [num_priors, 4].
150 | labels: (tensor) All the class labels for the image, Shape: [num_obj].
151 | loc_t: (tensor) Tensor to be filled w/ endcoded location targets.
152 | conf_t: (tensor) Tensor to be filled w/ matched indices for conf preds.
153 | idx: (int) current batch index
154 | Return:
155 | The matched indices corresponding to 1)location and 2)confidence preds.
156 | """
157 | # jaccard index
158 | overlaps = jaccard(
159 | truths,
160 | point_form(priors)
161 | )
162 | # (Bipartite Matching)
163 | # [1,num_objects] best prior for each ground truth
164 | best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True)
165 | # [1,num_priors] best ground truth for each prior
166 | best_truth_overlap, best_truth_idx = overlaps.max(
167 | 0, keepdim=True) # 0-2000
168 | best_truth_idx.squeeze_(0)
169 | best_truth_overlap.squeeze_(0)
170 | best_prior_idx.squeeze_(1)
171 | best_prior_overlap.squeeze_(1)
172 | best_truth_overlap.index_fill_(0, best_prior_idx, 2) # ensure best prior
173 | # TODO refactor: index best_prior_idx with long tensor
174 | # ensure every gt matches with its prior of max overlap
175 | for j in range(best_prior_idx.size(0)):
176 | best_truth_idx[best_prior_idx[j]] = j
177 | matches = truths[best_truth_idx] # Shape: [num_priors,4]
178 | conf = labels[best_truth_idx] # Shape: [num_priors]
179 | conf[best_truth_overlap < threshold] = 0 # label as background
180 | loc = encode(matches, priors, variances)
181 | loc_t[idx] = loc # [num_priors,4] encoded offsets to learn
182 | conf_t[idx] = conf # [num_priors] top class label for each prior
183 |
184 |
185 | def encode(matched, priors, variances):
186 | """Encode the variances from the priorbox layers into the ground truth boxes
187 | we have matched (based on jaccard overlap) with the prior boxes.
188 | Args:
189 | matched: (tensor) Coords of ground truth for each prior in point-form
190 | Shape: [num_priors, 4].
191 | priors: (tensor) Prior boxes in center-offset form
192 | Shape: [num_priors,4].
193 | variances: (list[float]) Variances of priorboxes
194 | Return:
195 | encoded boxes (tensor), Shape: [num_priors, 4]
196 | """
197 |
198 | # dist b/t match center and prior's center
199 | g_cxcy = (matched[:, :2] + matched[:, 2:]) / 2 - priors[:, :2]
200 | # encode variance
201 | g_cxcy /= (variances[0] * priors[:, 2:])
202 | # match wh / prior wh
203 | g_wh = (matched[:, 2:] - matched[:, :2]) / priors[:, 2:]
204 | #g_wh = torch.log(g_wh) / variances[1]
205 | g_wh = torch.log(g_wh) / variances[1]
206 | # return target for smooth_l1_loss
207 | return torch.cat([g_cxcy, g_wh], 1) # [num_priors,4]
208 |
209 |
210 | # Adapted from https://github.com/Hakuyume/chainer-ssd
211 | def decode(loc, priors, variances):
212 | """Decode locations from predictions using priors to undo
213 | the encoding we did for offset regression at train time.
214 | Args:
215 | loc (tensor): location predictions for loc layers,
216 | Shape: [num_priors,4]
217 | priors (tensor): Prior boxes in center-offset form.
218 | Shape: [num_priors,4].
219 | variances: (list[float]) Variances of priorboxes
220 | Return:
221 | decoded bounding box predictions
222 | """
223 |
224 | boxes = torch.cat((
225 | priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
226 | priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1])), 1)
227 | boxes[:, :2] -= boxes[:, 2:] / 2
228 | boxes[:, 2:] += boxes[:, :2]
229 | return boxes
230 |
231 |
232 | def log_sum_exp(x):
233 | """Utility function for computing log_sum_exp while determining
234 | This will be used to determine unaveraged confidence loss across
235 | all examples in a batch.
236 | Args:
237 | x (Variable(tensor)): conf_preds from conf layers
238 | """
239 | x_max = x.data.max()
240 | return torch.log(torch.sum(torch.exp(x - x_max), 1, keepdim=True)) + x_max
241 |
242 |
243 | # Original author: Francisco Massa:
244 | # https://github.com/fmassa/object-detection.torch
245 | # Ported to PyTorch by Max deGroot (02/01/2017)
246 | def nms(boxes, scores, overlap=0.5, top_k=200):
247 | """Apply non-maximum suppression at test time to avoid detecting too many
248 | overlapping bounding boxes for a given object.
249 | Args:
250 | boxes: (tensor) The location preds for the img, Shape: [num_priors,4].
251 | scores: (tensor) The class predscores for the img, Shape:[num_priors].
252 | overlap: (float) The overlap thresh for suppressing unnecessary boxes.
253 | top_k: (int) The Maximum number of box preds to consider.
254 | Return:
255 | The indices of the kept boxes with respect to num_priors.
256 | """
257 |
258 | keep = scores.new(scores.size(0)).zero_().long()
259 | if boxes.numel() == 0:
260 | return keep
261 | x1 = boxes[:, 0]
262 | y1 = boxes[:, 1]
263 | x2 = boxes[:, 2]
264 | y2 = boxes[:, 3]
265 | area = torch.mul(x2 - x1, y2 - y1)
266 | v, idx = scores.sort(0) # sort in ascending order
267 | # I = I[v >= 0.01]
268 | idx = idx[-top_k:] # indices of the top-k largest vals
269 | xx1 = boxes.new()
270 | yy1 = boxes.new()
271 | xx2 = boxes.new()
272 | yy2 = boxes.new()
273 | w = boxes.new()
274 | h = boxes.new()
275 |
276 | # keep = torch.Tensor()
277 | count = 0
278 | while idx.numel() > 0:
279 | i = idx[-1] # index of current largest val
280 | # keep.append(i)
281 | keep[count] = i
282 | count += 1
283 | if idx.size(0) == 1:
284 | break
285 | idx = idx[:-1] # remove kept element from view
286 | # load bboxes of next highest vals
287 | torch.index_select(x1, 0, idx, out=xx1)
288 | torch.index_select(y1, 0, idx, out=yy1)
289 | torch.index_select(x2, 0, idx, out=xx2)
290 | torch.index_select(y2, 0, idx, out=yy2)
291 | # store element-wise max with next highest score
292 | xx1 = torch.clamp(xx1, min=x1[i])
293 | yy1 = torch.clamp(yy1, min=y1[i])
294 | xx2 = torch.clamp(xx2, max=x2[i])
295 | yy2 = torch.clamp(yy2, max=y2[i])
296 | w.resize_as_(xx2)
297 | h.resize_as_(yy2)
298 | w = xx2 - xx1
299 | h = yy2 - yy1
300 | # check sizes of xx1 and xx2.. after each iteration
301 | w = torch.clamp(w, min=0.0)
302 | h = torch.clamp(h, min=0.0)
303 | inter = w * h
304 | # IoU = i / (area(a) + area(b) - i)
305 | rem_areas = torch.index_select(area, 0, idx) # load remaining areas)
306 | union = (rem_areas - inter) + area[i]
307 | IoU = inter / union # store result in iou
308 | # keep only elements with an IoU <= overlap
309 | idx = idx[IoU.le(overlap)]
310 | return keep, count
311 |
--------------------------------------------------------------------------------
/layers/functions/__init__.py:
--------------------------------------------------------------------------------
1 | from .prior_box import PriorBox
2 | from detection import Detect
3 |
4 | __all__=['Detect','PriorBox']
5 |
6 |
--------------------------------------------------------------------------------
/layers/functions/detection.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import torch
8 |
9 | from ..bbox_utils import decode, nms
10 | from torch.autograd import Function
11 |
12 |
13 | class Detect(Function):
14 | """At test time, Detect is the final layer of SSD. Decode location preds,
15 | apply non-maximum suppression to location predictions based on conf
16 | scores and threshold to a top_k number of output predictions for both
17 | confidence score and locations.
18 | """
19 |
20 | def __init__(self, cfg):
21 | self.num_classes = cfg.NUM_CLASSES
22 | self.top_k = cfg.TOP_K
23 | self.nms_thresh = cfg.NMS_THRESH
24 | self.conf_thresh = cfg.CONF_THRESH
25 | self.variance = cfg.VARIANCE
26 | self.nms_top_k = cfg.NMS_TOP_K
27 |
28 | def forward(self, loc_data, conf_data, prior_data):
29 | """
30 | Args:
31 | loc_data: (tensor) Loc preds from loc layers
32 | Shape: [batch,num_priors*4]
33 | conf_data: (tensor) Shape: Conf preds from conf layers
34 | Shape: [batch*num_priors,num_classes]
35 | prior_data: (tensor) Prior boxes and variances from priorbox layers
36 | Shape: [1,num_priors,4]
37 | """
38 | num = loc_data.size(0)
39 | num_priors = prior_data.size(0)
40 |
41 | conf_preds = conf_data.view(
42 | num, num_priors, self.num_classes).transpose(2, 1)
43 | batch_priors = prior_data.view(-1, num_priors,
44 | 4).expand(num, num_priors, 4)
45 | batch_priors = batch_priors.contiguous().view(-1, 4)
46 |
47 | decoded_boxes = decode(loc_data.view(-1, 4),
48 | batch_priors, self.variance)
49 | decoded_boxes = decoded_boxes.view(num, num_priors, 4)
50 |
51 | output = torch.zeros(num, self.num_classes, self.top_k, 5)
52 |
53 | for i in range(num):
54 | boxes = decoded_boxes[i].clone()
55 | conf_scores = conf_preds[i].clone()
56 |
57 | for cl in range(1, self.num_classes):
58 | c_mask = conf_scores[cl].gt(self.conf_thresh)
59 | scores = conf_scores[cl][c_mask]
60 |
61 | if scores.dim() == 0:
62 | continue
63 | l_mask = c_mask.unsqueeze(1).expand_as(boxes)
64 | boxes_ = boxes[l_mask].view(-1, 4)
65 | ids, count = nms(
66 | boxes_, scores, self.nms_thresh, self.nms_top_k)
67 | count = count if count < self.top_k else self.top_k
68 |
69 | output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1),
70 | boxes_[ids[:count]]), 1)
71 |
72 | return output
73 |
--------------------------------------------------------------------------------
/layers/functions/prior_box.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import torch
8 | from itertools import product as product
9 | import math
10 |
11 |
12 | class PriorBox(object):
13 | """Compute priorbox coordinates in center-offset form for each source
14 | feature map.
15 | """
16 |
17 | def __init__(self, input_size, feature_maps,cfg):
18 | super(PriorBox, self).__init__()
19 | self.imh = input_size[0]
20 | self.imw = input_size[1]
21 |
22 | # number of priors for feature map location (either 4 or 6)
23 | self.variance = cfg.VARIANCE or [0.1]
24 | #self.feature_maps = cfg.FEATURE_MAPS
25 | self.min_sizes = cfg.ANCHOR_SIZES
26 | self.steps = cfg.STEPS
27 | self.clip = cfg.CLIP
28 | for v in self.variance:
29 | if v <= 0:
30 | raise ValueError('Variances must be greater than 0')
31 | self.feature_maps = feature_maps
32 |
33 |
34 | def forward(self):
35 | mean = []
36 | for k in range(len(self.feature_maps)):
37 | feath = self.feature_maps[k][0]
38 | featw = self.feature_maps[k][1]
39 | for i, j in product(range(feath), range(featw)):
40 | f_kw = self.imw / self.steps[k]
41 | f_kh = self.imh / self.steps[k]
42 |
43 | cx = (j + 0.5) / f_kw
44 | cy = (i + 0.5) / f_kh
45 |
46 | s_kw = self.min_sizes[k] / self.imw
47 | s_kh = self.min_sizes[k] / self.imh
48 |
49 | mean += [cx, cy, s_kw, s_kh]
50 |
51 | output = torch.Tensor(mean).view(-1, 4)
52 | if self.clip:
53 | output.clamp_(max=1, min=0)
54 | return output
55 |
56 |
57 | if __name__ == '__main__':
58 | from data.config import cfg
59 | p = PriorBox([640, 640], cfg)
60 | out = p.forward()
61 | print(out.size())
62 |
--------------------------------------------------------------------------------
/layers/modules/__init__.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | from .l2norm import L2Norm
9 | from .multibox_loss import MultiBoxLoss
10 |
11 | __all__ = ['L2Norm', 'MultiBoxLoss']
12 |
13 |
--------------------------------------------------------------------------------
/layers/modules/l2norm.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | import torch
9 | import torch.nn as nn
10 | import torch.nn.init as init
11 | from torch.autograd import Function
12 | from torch.autograd import Variable
13 |
14 |
15 |
16 | class L2Norm(nn.Module):
17 | def __init__(self,n_channels, scale):
18 | super(L2Norm,self).__init__()
19 | self.n_channels = n_channels
20 | self.gamma = scale or None
21 | self.eps = 1e-10
22 | self.weight = nn.Parameter(torch.Tensor(self.n_channels))
23 | self.reset_parameters()
24 |
25 | def reset_parameters(self):
26 | init.constant(self.weight,self.gamma)
27 |
28 | def forward(self, x):
29 | norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps
30 | #x /= norm
31 | x = torch.div(x,norm)
32 | out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x
33 | return out
34 |
35 |
36 |
--------------------------------------------------------------------------------
/layers/modules/multibox_loss.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import math
8 | import torch
9 | import torch.nn as nn
10 | import torch.nn.functional as F
11 | from torch.autograd import Variable
12 |
13 |
14 | from ..bbox_utils import match, log_sum_exp, match_ssd
15 |
16 |
17 | class MultiBoxLoss(nn.Module):
18 | """SSD Weighted Loss Function
19 | Compute Targets:
20 | 1) Produce Confidence Target Indices by matching ground truth boxes
21 | with (default) 'priorboxes' that have jaccard index > threshold parameter
22 | (default threshold: 0.5).
23 | 2) Produce localization target by 'encoding' variance into offsets of ground
24 | truth boxes and their matched 'priorboxes'.
25 | 3) Hard negative mining to filter the excessive number of negative examples
26 | that comes with using a large number of default bounding boxes.
27 | (default negative:positive ratio 3:1)
28 | Objective Loss:
29 | L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N
30 | Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss
31 | weighted by α which is set to 1 by cross val.
32 | Args:
33 | c: class confidences,
34 | l: predicted boxes,
35 | g: ground truth boxes
36 | N: number of matched default boxes
37 | See: https://arxiv.org/pdf/1512.02325.pdf for more details.
38 | """
39 |
40 | def __init__(self, cfg, dataset, use_gpu=True):
41 | super(MultiBoxLoss, self).__init__()
42 | self.use_gpu = use_gpu
43 | self.num_classes = cfg.NUM_CLASSES
44 | self.negpos_ratio = cfg.NEG_POS_RATIOS
45 | self.variance = cfg.VARIANCE
46 | self.dataset = dataset
47 | if dataset == 'face':
48 | self.threshold = cfg.FACE.OVERLAP_THRESH
49 | self.match = match
50 | elif dataset == 'hand':
51 | self.threshold = cfg.HAND.OVERLAP_THRESH
52 | self.match = match_ssd
53 | else:
54 | self.threshold = cfg.HEAD.OVERLAP_THRESH
55 | self.match = match
56 |
57 | def forward(self, predictions, targets):
58 | """Multibox Loss
59 | Args:
60 | predictions (tuple): A tuple containing loc preds, conf preds,
61 | and prior boxes from SSD net.
62 | conf shape: torch.size(batch_size,num_priors,num_classes)
63 | loc shape: torch.size(batch_size,num_priors,4)
64 | priors shape: torch.size(num_priors,4)
65 |
66 | targets (tensor): Ground truth boxes and labels for a batch,
67 | shape: [batch_size,num_objs,5] (last idx is the label).
68 | """
69 | loc_data, conf_data, priors = predictions
70 | num = loc_data.size(0)
71 | priors = priors[:loc_data.size(1), :]
72 | num_priors = (priors.size(0))
73 | num_classes = self.num_classes
74 |
75 | # match priors (default boxes) and ground truth boxes
76 | loc_t = torch.Tensor(num, num_priors, 4)
77 | conf_t = torch.LongTensor(num, num_priors)
78 | for idx in range(num):
79 | truths = targets[idx][:, :-1].data
80 | labels = targets[idx][:, -1].data
81 | defaults = priors.data
82 | self.match(self.threshold, truths, defaults, self.variance, labels,
83 | loc_t, conf_t, idx)
84 | if self.use_gpu:
85 | loc_t = loc_t.cuda()
86 | conf_t = conf_t.cuda()
87 | # wrap targets
88 | loc_t = Variable(loc_t, requires_grad=False)
89 | conf_t = Variable(conf_t, requires_grad=False)
90 |
91 | pos = conf_t > 0
92 | num_pos = pos.sum(dim=1, keepdim=True)
93 | # Localization Loss (Smooth L1)
94 | # Shape: [batch,num_priors,4]
95 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data)
96 | loc_p = loc_data[pos_idx].view(-1, 4)
97 | loc_t = loc_t[pos_idx].view(-1, 4)
98 | loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False)
99 | # print(loc_p)
100 | # Compute max conf across batch for hard negative mining
101 | batch_conf = conf_data.view(-1, self.num_classes)
102 | loss_c = log_sum_exp(batch_conf) - \
103 | batch_conf.gather(1, conf_t.view(-1, 1))
104 |
105 | # Hard Negative Mining
106 | loss_c[pos.view(-1, 1)] = 0 # filter out pos boxes for now
107 | loss_c = loss_c.view(num, -1)
108 | _, loss_idx = loss_c.sort(1, descending=True)
109 | _, idx_rank = loss_idx.sort(1)
110 | num_pos = pos.long().sum(1, keepdim=True)
111 | num_neg = torch.clamp(self.negpos_ratio *
112 | num_pos, max=pos.size(1) - 1)
113 | neg = idx_rank < num_neg.expand_as(idx_rank)
114 |
115 | # Confidence Loss Including Positive and Negative Examples
116 | pos_idx = pos.unsqueeze(2).expand_as(conf_data)
117 | neg_idx = neg.unsqueeze(2).expand_as(conf_data)
118 | conf_p = conf_data[(pos_idx + neg_idx).gt(0)
119 | ].view(-1, self.num_classes)
120 | targets_weighted = conf_t[(pos + neg).gt(0)]
121 | loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False)
122 |
123 | # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N
124 | N = num_pos.data.sum() if num_pos.data.sum() > 0 else num
125 | loss_l /= N
126 | loss_c /= N
127 | return loss_l, loss_c
128 |
--------------------------------------------------------------------------------
/prepare_hand_dataset.py:
--------------------------------------------------------------------------------
1 | #-*-coding:utf-8 -*-
2 |
3 | from __future__ import print_function
4 | from __future__ import division
5 | from __future__ import absolute_import
6 |
7 | import os
8 | import numpy as np
9 | import csv
10 |
11 | from data.config import cfg
12 |
13 | if not os.path.exists('./data'):
14 | os.makedirs('./data')
15 |
16 | TRAIN_ROOT = os.path.join(cfg.HAND.DIR, 'images', 'train')
17 | TEST_ROOT = os.path.join(cfg.HAND.DIR, 'images', 'test')
18 |
19 |
20 | def generate_file(csv_file, target_file, root):
21 | filenames = []
22 | bboxes = []
23 | with open(csv_file, 'rb') as sd:
24 | lines = csv.DictReader(sd)
25 | for line in lines:
26 | filenames.append(os.path.join(root, line['filename']))
27 | bbox = [int(line['xmin']), int(line['ymin']),
28 | int(line['xmax']), int(line['ymax'])]
29 | bboxes.append(bbox)
30 |
31 | filenames = np.array(filenames)
32 | bboxes = np.array(bboxes)
33 | uniq_filenames = np.unique(filenames)
34 |
35 | fout = open(target_file, 'w')
36 |
37 | for name in uniq_filenames:
38 | idx = np.where(filenames == name)[0]
39 | bbox = bboxes[idx]
40 | fout.write('{} '.format(name))
41 | fout.write(('{} ').format(len(bbox)))
42 | for loc in bbox:
43 | x1, y1, x2, y2 = loc
44 | fout.write('{} {} {} {} '.format(x1, y1, x2, y2))
45 | fout.write('\n')
46 | fout.close()
47 |
48 |
49 | if __name__ == '__main__':
50 | train_csv_file = os.path.join(TRAIN_ROOT, 'train_labels.csv')
51 | test_csv_file = os.path.join(TEST_ROOT, 'test_labels.csv')
52 | generate_file(train_csv_file, cfg.HAND.TRAIN_FILE, TRAIN_ROOT)
53 | generate_file(test_csv_file, cfg.HAND.VAL_FILE, TEST_ROOT)
54 |
--------------------------------------------------------------------------------
/prepare_wider_data.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 |
8 | import os
9 | from data.config import cfg
10 | import cv2
11 |
12 | WIDER_ROOT = os.path.join(cfg.HOME, 'WIDER')
13 | train_list_file = os.path.join(WIDER_ROOT, 'wider_face_split',
14 | 'wider_face_train_bbx_gt.txt')
15 | val_list_file = os.path.join(WIDER_ROOT, 'wider_face_split',
16 | 'wider_face_val_bbx_gt.txt')
17 |
18 | WIDER_TRAIN = os.path.join(WIDER_ROOT, 'WIDER_train', 'images')
19 | WIDER_VAL = os.path.join(WIDER_ROOT, 'WIDER_val', 'images')
20 |
21 |
22 | def parse_wider_file(root, file):
23 | with open(file, 'r') as fr:
24 | lines = fr.readlines()
25 | face_count = []
26 | img_paths = []
27 | face_loc = []
28 | img_faces = []
29 | count = 0
30 | flag = False
31 | for k, line in enumerate(lines):
32 | line = line.strip().strip('\n')
33 | if count > 0:
34 | line = line.split(' ')
35 | count -= 1
36 | loc = [int(line[0]), int(line[1]), int(line[2]), int(line[3])]
37 | face_loc += [loc]
38 | if flag:
39 | face_count += [int(line)]
40 | flag = False
41 | count = int(line)
42 | if 'jpg' in line:
43 | img_paths += [os.path.join(root, line)]
44 | flag = True
45 |
46 | total_face = 0
47 | for k in face_count:
48 | face_ = []
49 | for x in xrange(total_face, total_face + k):
50 | face_.append(face_loc[x])
51 | img_faces += [face_]
52 | total_face += k
53 | return img_paths, img_faces
54 |
55 |
56 | def wider_data_file():
57 | img_paths, bbox = parse_wider_file(WIDER_TRAIN, train_list_file)
58 | fw = open(cfg.FACE.TRAIN_FILE, 'w')
59 | for index in xrange(len(img_paths)):
60 | path = img_paths[index]
61 | boxes = bbox[index]
62 | fw.write(path)
63 | fw.write(' {}'.format(len(boxes)))
64 | for box in boxes:
65 | data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1)
66 | fw.write(data)
67 | fw.write('\n')
68 | fw.close()
69 |
70 | img_paths, bbox = parse_wider_file(WIDER_VAL, val_list_file)
71 | fw = open(cfg.FACE.VAL_FILE, 'w')
72 | for index in xrange(len(img_paths)):
73 | path = img_paths[index]
74 | boxes = bbox[index]
75 | fw.write(path)
76 | fw.write(' {}'.format(len(boxes)))
77 | for box in boxes:
78 | data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1)
79 | fw.write(data)
80 | fw.write('\n')
81 | fw.close()
82 |
83 |
84 | if __name__ == '__main__':
85 | wider_data_file()
86 |
--------------------------------------------------------------------------------
/s3fd.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import torch
9 | import torch.nn as nn
10 | import torch.nn.init as init
11 | import torch.nn.functional as F
12 | from torch.autograd import Variable
13 |
14 | from layers import *
15 | from data.config import cfg
16 | import numpy as np
17 |
18 | class S3FD(nn.Module):
19 | """Single Shot Multibox Architecture
20 | The network is composed of a base VGG network followed by the
21 | added multibox conv layers. Each multibox layer branches into
22 | 1) conv2d for class conf scores
23 | 2) conv2d for localization predictions
24 | 3) associated priorbox layer to produce default bounding
25 | boxes specific to the layer's feature map size.
26 | See: https://arxiv.org/pdf/1512.02325.pdf for more details.
27 |
28 | Args:
29 | phase: (string) Can be "test" or "train"
30 | size: input image size
31 | base: VGG16 layers for input, size of either 300 or 500
32 | extras: extra layers that feed to multibox loc and conf layers
33 | head: "multibox head" consists of loc and conf conv layers
34 | """
35 |
36 | def __init__(self, phase, base, extras, head, num_classes):
37 | super(S3FD, self).__init__()
38 | self.phase = phase
39 | self.num_classes = num_classes
40 | '''
41 | self.priorbox = PriorBox(size,cfg)
42 | self.priors = Variable(self.priorbox.forward(), volatile=True)
43 | '''
44 | # SSD network
45 | self.vgg = nn.ModuleList(base)
46 | # Layer learns to scale the l2 normalized features from conv4_3
47 | self.L2Norm3_3 = L2Norm(256, 10)
48 | self.L2Norm4_3 = L2Norm(512, 8)
49 | self.L2Norm5_3 = L2Norm(512, 5)
50 |
51 | self.extras = nn.ModuleList(extras)
52 |
53 | self.loc = nn.ModuleList(head[0])
54 | self.conf = nn.ModuleList(head[1])
55 |
56 | if self.phase == 'test':
57 | self.softmax = nn.Softmax(dim=-1)
58 | self.detect = Detect(cfg)
59 |
60 |
61 |
62 | def forward(self, x):
63 | """Applies network layers and ops on input image(s) x.
64 |
65 | Args:
66 | x: input image or batch of images. Shape: [batch,3,300,300].
67 |
68 | Return:
69 | Depending on phase:
70 | test:
71 | Variable(tensor) of output class label predictions,
72 | confidence score, and corresponding location predictions for
73 | each object detected. Shape: [batch,topk,7]
74 |
75 | train:
76 | list of concat outputs from:
77 | 1: confidence layers, Shape: [batch*num_priors,num_classes]
78 | 2: localization layers, Shape: [batch,num_priors*4]
79 | 3: priorbox layers, Shape: [2,num_priors*4]
80 | """
81 | size = x.size()[2:]
82 | sources = list()
83 | loc = list()
84 | conf = list()
85 |
86 | # apply vgg up to conv4_3 relu
87 | for k in range(16):
88 | x = self.vgg[k](x)
89 |
90 | s = self.L2Norm3_3(x)
91 | sources.append(s)
92 |
93 | # apply vgg up to fc7
94 | for k in range(16, 23):
95 | x = self.vgg[k](x)
96 |
97 | s = self.L2Norm4_3(x)
98 | sources.append(s)
99 |
100 | for k in range(23, 30):
101 | x = self.vgg[k](x)
102 |
103 | s = self.L2Norm5_3(x)
104 | sources.append(s)
105 |
106 | for k in range(30, len(self.vgg)):
107 | x = self.vgg[k](x)
108 | sources.append(x)
109 |
110 | # apply extra layers and cache source layer outputs
111 | for k, v in enumerate(self.extras):
112 | x = F.relu(v(x), inplace=True)
113 | if k % 2 == 1:
114 | sources.append(x)
115 |
116 | # apply multibox head to source layers
117 |
118 | loc_x = self.loc[0](sources[0])
119 | conf_x = self.conf[0](sources[0])
120 |
121 | max_conf, _ = torch.max(conf_x[:, 0:3, :, :], dim=1, keepdim=True)
122 | conf_x = torch.cat((max_conf, conf_x[:, 3:, :, :]), dim=1)
123 |
124 | loc.append(loc_x.permute(0, 2, 3, 1).contiguous())
125 | conf.append(conf_x.permute(0, 2, 3, 1).contiguous())
126 |
127 | for i in range(1, len(sources)):
128 | x = sources[i]
129 | conf.append(self.conf[i](x).permute(0, 2, 3, 1).contiguous())
130 | loc.append(self.loc[i](x).permute(0, 2, 3, 1).contiguous())
131 |
132 | '''
133 | for (x, l, c) in zip(sources, self.loc, self.conf):
134 | loc.append(l(x).permute(0, 2, 3, 1).contiguous())
135 | conf.append(c(x).permute(0, 2, 3, 1).contiguous())
136 | '''
137 |
138 | features_maps = []
139 | for i in range(len(loc)):
140 | feat = []
141 | feat += [loc[i].size(1), loc[i].size(2)]
142 | features_maps += [feat]
143 |
144 | self.priorbox = PriorBox(size, features_maps, cfg)
145 | self.priors = Variable(self.priorbox.forward(), volatile=True)
146 |
147 | loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1)
148 | conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1)
149 |
150 |
151 | if self.phase == 'test':
152 | output = self.detect(
153 | loc.view(loc.size(0), -1, 4), # loc preds
154 | self.softmax(conf.view(conf.size(0), -1,
155 | self.num_classes)), # conf preds
156 | self.priors.type(type(x.data)) # default boxes
157 | )
158 |
159 | else:
160 | output = (
161 | loc.view(loc.size(0), -1, 4),
162 | conf.view(conf.size(0), -1, self.num_classes),
163 | self.priors
164 | )
165 | return output
166 |
167 | def load_weights(self, base_file):
168 | other, ext = os.path.splitext(base_file)
169 | if ext == '.pkl' or '.pth':
170 | print('Loading weights into state dict...')
171 | mdata = torch.load(base_file,
172 | map_location=lambda storage, loc: storage)
173 | weights = mdata['weight']
174 | epoch = mdata['epoch']
175 | self.load_state_dict(weights)
176 | print('Finished!')
177 | else:
178 | print('Sorry only .pth and .pkl files supported.')
179 | return epoch
180 |
181 | def xavier(self, param):
182 | init.xavier_uniform(param)
183 |
184 | def weights_init(self, m):
185 | if isinstance(m, nn.Conv2d):
186 | self.xavier(m.weight.data)
187 | m.bias.data.zero_()
188 |
189 |
190 | vgg_cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M',
191 | 512, 512, 512, 'M']
192 |
193 | extras_cfg = [256, 'S', 512, 128, 'S', 256]
194 |
195 |
196 | def vgg(cfg, i, batch_norm=False):
197 | layers = []
198 | in_channels = i
199 | for v in cfg:
200 | if v == 'M':
201 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
202 | elif v == 'C':
203 | layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]
204 | else:
205 | conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
206 | if batch_norm:
207 | layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
208 | else:
209 | layers += [conv2d, nn.ReLU(inplace=True)]
210 | in_channels = v
211 | conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)
212 | conv7 = nn.Conv2d(1024, 1024, kernel_size=1)
213 | layers += [conv6,
214 | nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]
215 | return layers
216 |
217 |
218 | def add_extras(cfg, i, batch_norm=False):
219 | # Extra layers added to VGG for feature scaling
220 | layers = []
221 | in_channels = i
222 | flag = False
223 | for k, v in enumerate(cfg):
224 | if in_channels != 'S':
225 | if v == 'S':
226 | layers += [nn.Conv2d(in_channels, cfg[k + 1],
227 | kernel_size=(1, 3)[flag], stride=2, padding=1)]
228 | else:
229 | layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])]
230 | flag = not flag
231 | in_channels = v
232 | return layers
233 |
234 |
235 | def multibox(vgg, extra_layers, num_classes):
236 | loc_layers = []
237 | conf_layers = []
238 | vgg_source = [21, 28, -2]
239 |
240 | loc_layers += [nn.Conv2d(vgg[14].out_channels, 4,
241 | kernel_size=3, padding=1)]
242 | conf_layers += [nn.Conv2d(vgg[14].out_channels,
243 | 3 + (num_classes-1), kernel_size=3, padding=1)]
244 |
245 | for k, v in enumerate(vgg_source):
246 | loc_layers += [nn.Conv2d(vgg[v].out_channels,
247 | 4, kernel_size=3, padding=1)]
248 | conf_layers += [nn.Conv2d(vgg[v].out_channels,
249 | num_classes, kernel_size=3, padding=1)]
250 | for k, v in enumerate(extra_layers[1::2], 2):
251 | loc_layers += [nn.Conv2d(v.out_channels,
252 | 4, kernel_size=3, padding=1)]
253 | conf_layers += [nn.Conv2d(v.out_channels,
254 | num_classes, kernel_size=3, padding=1)]
255 | return vgg, extra_layers, (loc_layers, conf_layers)
256 |
257 |
258 | def build_s3fd(phase, num_classes=2):
259 | base_, extras_, head_ = multibox(
260 | vgg(vgg_cfg, 3), add_extras((extras_cfg), 1024), num_classes)
261 |
262 | return S3FD(phase, base_, extras_, head_, num_classes)
263 |
264 |
265 | if __name__ == '__main__':
266 | net = build_s3fd('train', num_classes=2)
267 | inputs = Variable(torch.randn(4, 3, 640, 640))
268 | output = net(inputs)
269 |
270 |
--------------------------------------------------------------------------------
/tmp/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/tmp/test.jpg
--------------------------------------------------------------------------------
/tmp/test2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yxlijun/S3FD.pytorch/bccf1d99fa36f4140c42731e99e1627d76a8eb56/tmp/test2.jpg
--------------------------------------------------------------------------------
/tools/afw_img_list.txt:
--------------------------------------------------------------------------------
1 | 1004109301
2 | 111076519
3 | 1139324862
4 | 1204062305
5 | 1224897301
6 | 1254885428
7 | 1295311477
8 | 1361196352
9 | 1372188757
10 | 14424972
11 | 156474078
12 | 1587030290
13 | 1634816
14 | 1636651575
15 | 1648807314
16 | 170817766
17 | 1709378501
18 | 174692320
19 | 1814664578
20 | 18489332
21 | 199759840
22 | 2030653815
23 | 2043831280
24 | 2118625994
25 | 2120936774
26 | 213654866
27 | 2147052512
28 | 2186255795
29 | 2233672250
30 | 2239710476
31 | 225191079
32 | 2266416332
33 | 22699817
34 | 2288136183
35 | 2312639559
36 | 2353849
37 | 2372995574
38 | 237815567
39 | 2404040793
40 | 2417212918
41 | 2437602091
42 | 2451065225
43 | 250277765
44 | 2542662563
45 | 2580479214
46 | 261068
47 | 2653111362
48 | 270814102
49 | 2715171150
50 | 281972218
51 | 2844520516
52 | 2863107962
53 | 2911658494
54 | 2939015820
55 | 3062021448
56 | 3089202157
57 | 310076750
58 | 3187108438
59 | 3210734866
60 | 3284354538
61 | 3331716292
62 | 342149506
63 | 3464901851
64 | 346731834
65 | 347629355
66 | 347826333
67 | 3576294411
68 | 364259537
69 | 3662810723
70 | 3684472818
71 | 368987306
72 | 37096733
73 | 3729198156
74 | 3796238727
75 | 3854178896
76 | 3858593140
77 | 3873491482
78 | 3893740955
79 | 3929640120
80 | 3944399031
81 | 3989161
82 | 399829006
83 | 40014967
84 | 4017305068
85 | 4022732812
86 | 406798473
87 | 4082680322
88 | 4141887018
89 | 4174638819
90 | 4237203680
91 | 4250120238
92 | 4253907822
93 | 4285163979
94 | 432269399
95 | 4332978153
96 | 4337161543
97 | 4351876664
98 | 435926861
99 | 437595409
100 | 442651885
101 | 4470478982
102 | 4471110141
103 | 447910249
104 | 448291547
105 | 4492032921
106 | 45092961
107 | 4512714865
108 | 4520272436
109 | 4553922208
110 | 4555082379
111 | 4560029166
112 | 4584451140
113 | 4683040401
114 | 4739664721
115 | 4758145781
116 | 47618649
117 | 4774338842
118 | 4801259916
119 | 4821642
120 | 4856974482
121 | 4880083461
122 | 4970182488
123 | 5002723411
124 | 5007442
125 | 5020454673
126 | 5065140719
127 | 5083671561
128 | 5144909700
129 | 5146483815
130 | 5151536225
131 | 5188566452
132 | 5201079592
133 | 5204730083
134 | 5227275045
135 | 52381600
136 | 5301057994
137 | 539722510
138 | 5452623
139 | 56054945
140 | 59354095
141 | 642820626
142 | 658607626
143 | 79378097
144 | 815038
145 | 82161078
146 | 823016568
147 | 878985234
148 | 88094323
149 | 899545263
150 | 90800092
151 | 91328372
152 | 9545523490
153 | 955659370
154 | 1051618982
155 | 1130084326
156 | 120563545
157 | 134212
158 | 1602308
159 | 16413031
160 | 2037185414
161 | 2060241469
162 | 2080551997
163 | 2086996835
164 | 2099639490
165 | 2122067003
166 | 2201628776
167 | 2239259
168 | 2296215131
169 | 2316734819
170 | 2329110240
171 | 2339510439
172 | 2392075438
173 | 2406586388
174 | 24795717
175 | 2519293956
176 | 253915276
177 | 255360810
178 | 2751381965
179 | 2803423910
180 | 2805422179
181 | 3020248483
182 | 3116931144
183 | 3346359383
184 | 3363054468
185 | 3504938758
186 | 3532475790
187 | 3722549017
188 | 378492784
189 | 397921011
190 | 4009440741
191 | 410225851
192 | 411555970
193 | 4145388945
194 | 4239974048
195 | 4400753623
196 | 442743156
197 | 4538917191
198 | 4573422380
199 | 4906266640
200 | 507521047
201 | 5082623456
202 | 5106695994
203 | 5169701116
204 | 70037463
205 | 719902933
--------------------------------------------------------------------------------
/tools/afw_test.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import sys
9 | import torch
10 | import argparse
11 | import torch.nn as nn
12 | import torch.utils.data as data
13 | import torch.backends.cudnn as cudnn
14 | import torchvision.transforms as transforms
15 |
16 | import cv2
17 | import time
18 | import numpy as np
19 | from PIL import Image
20 |
21 | from data.config import cfg
22 | from s3fd import build_s3fd
23 | from torch.autograd import Variable
24 | from utils.augmentations import to_chw_bgr
25 |
26 |
27 | parser = argparse.ArgumentParser(description='s3fd evaluatuon afw')
28 | parser.add_argument('--model', type=str,
29 | default='weights/s3fd.pth', help='trained model')
30 | parser.add_argument('--thresh', default=0.1, type=float,
31 | help='Final confidence threshold')
32 | args = parser.parse_args()
33 |
34 | use_cuda = torch.cuda.is_available()
35 |
36 | if use_cuda:
37 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
38 | else:
39 | torch.set_default_tensor_type('torch.FloatTensor')
40 |
41 | AFW_IMG_DIR = os.path.join(cfg.FACE.AFW_DIR, 'images')
42 | AFW_RESULT_DIR = os.path.join(cfg.FACE.AFW_DIR, 's3fd')
43 | AFW_RESULT_IMG_DIR = os.path.join(AFW_RESULT_DIR, 'images')
44 |
45 | if not os.path.exists(AFW_RESULT_IMG_DIR):
46 | os.makedirs(AFW_RESULT_IMG_DIR)
47 |
48 |
49 | def detect_face(net, img, thresh):
50 | height, width, _ = img.shape
51 | im_shrink = 640.0 / max(height, width)
52 | image = cv2.resize(img, None, None, fx=im_shrink,
53 | fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy()
54 |
55 | x = to_chw_bgr(image)
56 | x = x.astype('float32')
57 | x -= cfg.img_mean
58 | x = x[[2, 1, 0], :, :]
59 |
60 | x = Variable(torch.from_numpy(x).unsqueeze(0))
61 | if use_cuda:
62 | x = x.cuda()
63 |
64 | y = net(x)
65 | detections = y.data
66 | scale = torch.Tensor([img.shape[1], img.shape[0],
67 | img.shape[1], img.shape[0]])
68 |
69 | bboxes = []
70 | for i in range(detections.size(1)):
71 | j = 0
72 | while detections[0, i, j, 0] >= thresh:
73 | box = []
74 | score = detections[0, i, j, 0]
75 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int)
76 | j += 1
77 | box += [pt[0], pt[1], pt[2], pt[3], score]
78 | box[1] += 0.2 * (box[3] - box[1] + 1)
79 | bboxes += [box]
80 |
81 | return bboxes
82 |
83 |
84 | if __name__ == '__main__':
85 | net = build_s3fd('test', cfg.NUM_CLASSES)
86 | net.load_state_dict(torch.load(args.model))
87 | net.eval()
88 |
89 | if use_cuda:
90 | net.cuda()
91 | cudnn.benckmark = True
92 |
93 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS)
94 |
95 | counter = 0
96 | txt_out = os.path.join(AFW_RESULT_DIR, 'sfd_dets.txt')
97 | txt_in = os.path.join('./tools/afw_img_list.txt')
98 |
99 | fout = open(txt_out, 'w')
100 | fin = open(txt_in, 'r')
101 |
102 | for line in fin.readlines():
103 | line = line.strip()
104 | img_file = os.path.join(AFW_IMG_DIR, line + '.jpg')
105 | out_file = os.path.join(AFW_RESULT_IMG_DIR, line + '.jpg')
106 | counter += 1
107 | t1 = time.time()
108 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR)
109 | img = Image.open(img_file)
110 | if img.mode == 'L':
111 | img = img.convert('RGB')
112 | img = np.array(img)
113 | bboxes = detect_face(net, img, args.thresh)
114 | t2 = time.time()
115 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1))
116 | for bbox in bboxes:
117 | x1, y1, x2, y2, score = bbox
118 | fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format(
119 | line, score, x1, y1, x2, y2))
120 | for bbox in bboxes:
121 | x1, y1, x2, y2, score = bbox
122 | x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
123 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
124 | cv2.imwrite(out_file, img)
125 |
126 | fout.close()
127 | fin.close()
128 |
--------------------------------------------------------------------------------
/tools/anchor_matching_test.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import pickle
9 | import torch
10 | import numpy as np
11 | from data.config import cfg
12 | import torch.utils.data as data
13 |
14 | from utils.augmentations import S3FDValTransform
15 | from layers.functions import PriorBox
16 | from data.wider_face import WIDERDetection, detection_collate
17 |
18 | from layers.bbox_utils import match, match_ssd, decode
19 |
20 | import matplotlib.pyplot as plt
21 |
22 |
23 | dataset = WIDERDetection(
24 | cfg.TRAIN_FILE, transform=S3FDValTransform(cfg.INPUT_SIZE), train=False)
25 |
26 | data_loader = data.DataLoader(dataset, 64,
27 | num_workers=4,
28 | shuffle=False,
29 | collate_fn=detection_collate,
30 | pin_memory=True)
31 |
32 | anchor_boxes = PriorBox(cfg).forward()
33 | num_priors = anchor_boxes.size(0)
34 | variance = cfg.VARIANCE
35 |
36 | savepath = 'tmp'
37 | if not os.path.exists(savepath):
38 | os.makedirs(savepath)
39 |
40 | filename = os.path.join(savepath, 'match_anchor.pkl')
41 |
42 |
43 | def anchor_match_count():
44 | anchor_scale_map = {16: 0, 32: 0, 64: 0, 128: 0, 256: 0, 512: 0}
45 | thresh = cfg.OVERLAP_THRESH
46 | sfd_scales = []
47 | for idx, (_, target) in enumerate(data_loader):
48 | num = len(target)
49 |
50 | loc_t = torch.Tensor(num, num_priors, 4)
51 | conf_t = torch.LongTensor(num, num_priors)
52 |
53 | for index in range(num):
54 | truths = target[index][:, :-1]
55 | labels = target[index][:, -1]
56 |
57 | match(thresh, truths, anchor_boxes,
58 | variance, labels, loc_t, conf_t, index)
59 |
60 | pos = conf_t > 0
61 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_t)
62 | defaults = anchor_boxes.view(-1, num_priors,
63 | 4).expand_as(loc_t).contiguous().view(-1, 4).clone()
64 | loc_t = loc_t.view(-1, 4)
65 | decoded_boxes = decode(loc_t, defaults, variance)
66 | decoded_boxes = decoded_boxes.view(num, num_priors, 4)
67 | match_boxes = decoded_boxes[pos_idx].view(-1, 4)
68 |
69 | ori_boxes = match_boxes * cfg.INPUT_SIZE
70 | wh = ori_boxes[:, 2:] - ori_boxes[:, 0:2]
71 |
72 | scales = torch.sqrt(wh[:, 0] * wh[:, 1])
73 | scales = scales.numpy().astype(np.int)
74 | print(scales.shape)
75 |
76 | sfd_scales += [scales]
77 |
78 | sfd_scales = np.concatenate(sfd_scales, axis=0)
79 | sfd_result = all_np(sfd_scales)
80 |
81 | return sfd_result
82 |
83 |
84 | def anchor_match_ssd_count():
85 | anchor_scale_map = {16: 0, 32: 0, 64: 0, 128: 0, 256: 0, 512: 0}
86 | thresh = 0.5
87 | ssd_scales = []
88 | for idx, (_, target) in enumerate(data_loader):
89 | num = len(target)
90 |
91 | loc_t = torch.Tensor(num, num_priors, 4)
92 | conf_t = torch.LongTensor(num, num_priors)
93 |
94 | for index in range(num):
95 | truths = target[index][:, :-1]
96 | labels = target[index][:, -1]
97 |
98 | match_ssd(thresh, truths, anchor_boxes,
99 | variance, labels, loc_t, conf_t, index)
100 |
101 | pos = conf_t > 0
102 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_t)
103 | defaults = anchor_boxes.view(-1, num_priors,
104 | 4).expand_as(loc_t).contiguous().view(-1, 4).clone()
105 | loc_t = loc_t.view(-1, 4)
106 | decoded_boxes = decode(loc_t, defaults, variance)
107 | decoded_boxes = decoded_boxes.view(num, num_priors, 4)
108 | match_boxes = decoded_boxes[pos_idx].view(-1, 4)
109 |
110 | ori_boxes = match_boxes * cfg.INPUT_SIZE
111 | wh = ori_boxes[:, 2:] - ori_boxes[:, 0:2]
112 |
113 | scales = torch.sqrt(wh[:, 0] * wh[:, 1])
114 | scales = scales.numpy().astype(np.int)
115 | print(scales.shape)
116 |
117 | ssd_scales += [scales]
118 |
119 | ssd_scales = np.concatenate(ssd_scales, axis=0)
120 | ssd_result = all_np(ssd_scales)
121 | return ssd_result
122 |
123 |
124 | def all_np(arr):
125 | arr = np.array(arr)
126 | key = np.unique(arr)
127 | result = {}
128 | for k in key:
129 | mask = (arr == k)
130 | arr_new = arr[mask]
131 | v = arr_new.size
132 | result[k] = v
133 | return result
134 |
135 |
136 | def save_pkl():
137 | sfd_count = anchor_match_count()
138 | ssd_count = anchor_match_ssd_count()
139 |
140 | result = {'sfd': sfd_count, 'ssd': ssd_count}
141 | file = open(filename, 'wb')
142 | pickle.dump(result, file)
143 | file.close()
144 |
145 |
146 | def plot_anchor_match():
147 | if not os.path.exists(filename):
148 | save_pkl()
149 |
150 | with open(filename, 'rb') as f:
151 | result = pickle.load(f)
152 |
153 | sfd_res = result['sfd']
154 | ssd_res = result['ssd']
155 |
156 | sfd_count = []
157 | ssd_count = []
158 |
159 | frames = range(0, 660)
160 |
161 | sfd_feat_count = np.zeros(len(frames))
162 | ssd_feat_count = np.zeros(len(frames))
163 | feat_maps = np.array([16, 32, 64, 128, 256, 512])
164 |
165 | for i in frames:
166 | if i in sfd_res.keys():
167 | sfd_count += [sfd_res[i]]
168 | else:
169 | sfd_count += [0]
170 | if i in ssd_res.keys():
171 | ssd_count += [ssd_res[i]]
172 | else:
173 | ssd_count += [0]
174 |
175 | sfd_count = np.array(sfd_count)
176 | ssd_count = np.array(ssd_count)
177 |
178 | for feat in feat_maps:
179 | if feat in sfd_res.keys():
180 | sfd_feat_count[feat] = sfd_res[feat]
181 | if feat in ssd_res.keys():
182 | ssd_feat_count[feat] = ssd_res[feat]
183 |
184 | n = 280
185 | plt.plot(frames[:n], sfd_count[:n], 'r', label='sfd matching method')
186 | plt.plot(frames[:n], sfd_feat_count[:n], 'b',
187 | label='sfd in [16,32,64...] match')
188 |
189 | plt.plot(frames[:n], ssd_count[:n], 'g-', label='ssd matching method')
190 | plt.plot(frames[:n], ssd_feat_count[:n], 'c-',
191 | label='ssd in [16,32,64...] match')
192 |
193 | fig1 = plt.figure(1)
194 | axes = plt.subplot(111)
195 | axes.set_yticks([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
196 | axes.grid(True)
197 | plt.legend(loc="upper right")
198 |
199 | plt.ylabel('Num of match anchor ratio') # set ystick label
200 | plt.xlabel('Scale of face') # set xstck label
201 |
202 | plt.show()
203 |
204 |
205 | if __name__ == '__main__':
206 | plot_anchor_match()
207 |
--------------------------------------------------------------------------------
/tools/detect.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import torch
9 | import argparse
10 | import torch.nn as nn
11 | import torch.utils.data as data
12 | import torch.backends.cudnn as cudnn
13 | import torchvision.transforms as transforms
14 |
15 | import cv2
16 | import time
17 | import numpy as np
18 |
19 | from data.config import cfg
20 | from s3fd import build_s3fd
21 | from torch.autograd import Variable
22 | from utils.augmentations import S3FDBasicTransform
23 |
24 |
25 | parser = argparse.ArgumentParser(description='s3df evaluatuon fddb')
26 | parser.add_argument('--trained_model', type=str,
27 | default='weights/s3fd.pth', help='trained model')
28 | parser.add_argument('--thresh', default=0.1, type=float,
29 | help='Final confidence threshold')
30 | args = parser.parse_args()
31 |
32 | use_cuda = torch.cuda.is_available()
33 |
34 | if use_cuda:
35 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
36 | else:
37 | torch.set_default_tensor_type('torch.FloatTensor')
38 |
39 |
40 | net = build_s3fd('train', cfg.INPUT_SIZE, cfg.NUM_CLASSES)
41 | net.load_state_dict(torch.load(args.trained_model))
42 | net.eval()
43 |
44 |
45 | def dyna_anchor(imh,imw):
46 | pass
47 |
--------------------------------------------------------------------------------
/tools/eval_hand.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from __future__ import division
3 | from __future__ import absolute_import
4 | from __future__ import print_function
5 |
6 | import numpy as np
7 | import os
8 | import cPickle
9 |
10 | import torch
11 | import argparse
12 | import torch.nn as nn
13 | import torch.utils.data as data
14 | import torch.backends.cudnn as cudnn
15 | import torchvision.transforms as transforms
16 |
17 | import cv2
18 | import time
19 | import pickle
20 | from PIL import Image
21 |
22 | from data.config import cfg
23 | from s3fd import build_s3fd
24 | from torch.autograd import Variable
25 | from utils.augmentations import to_chw_bgr
26 | from data.egohand import HandDetection
27 |
28 | parser = argparse.ArgumentParser(description='s3fd head eval')
29 | parser.add_argument('--save_folder',
30 | type=str, default='tmp/',
31 | help='Directory for detect result')
32 | parser.add_argument('--model',
33 | type=str,
34 | default='weights/s3fd.pth', help='trained model')
35 | parser.add_argument('--thresh',
36 | default=0.01, type=float,
37 | help='Final confidence threshold')
38 |
39 |
40 | args = parser.parse_args()
41 |
42 | if not os.path.exists(args.save_folder):
43 | os.makedirs(args.save_folder)
44 |
45 | use_cuda = torch.cuda.is_available()
46 |
47 | if use_cuda:
48 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
49 | else:
50 | torch.set_default_tensor_type('torch.FloatTensor')
51 |
52 |
53 | labelmap = ['person']
54 | set_type = 'test'
55 | devkit_path = os.path.join(args.save_folder,'sfd_hand')
56 |
57 |
58 | class Timer(object):
59 | """A simple timer."""
60 |
61 | def __init__(self):
62 | self.total_time = 0.
63 | self.calls = 0
64 | self.start_time = 0.
65 | self.diff = 0.
66 | self.average_time = 0.
67 |
68 | def tic(self):
69 | # using time.time instead of time.clock because time time.clock
70 | # does not normalize for multithreading
71 | self.start_time = time.time()
72 |
73 | def toc(self, average=True):
74 | self.diff = time.time() - self.start_time
75 | self.total_time += self.diff
76 | self.calls += 1
77 | self.average_time = self.total_time / self.calls
78 | if average:
79 | return self.average_time
80 | else:
81 | return self.diff
82 |
83 | def voc_ap(rec, prec, use_07_metric=True):
84 | """ ap = voc_ap(rec, prec, [use_07_metric])
85 | Compute VOC AP given precision and recall.
86 | If use_07_metric is true, uses the
87 | VOC 07 11 point method (default:True).
88 | """
89 | if use_07_metric:
90 | # 11 point metric
91 | ap = 0.
92 | for t in np.arange(0., 1.1, 0.1):
93 | if np.sum(rec >= t) == 0:
94 | p = 0
95 | else:
96 | p = np.max(prec[rec >= t])
97 | ap = ap + p / 11.
98 | else:
99 | # correct AP calculation
100 | # first append sentinel values at the end
101 | mrec = np.concatenate(([0.], rec, [1.]))
102 | mpre = np.concatenate(([0.], prec, [0.]))
103 |
104 | # compute the precision envelope
105 | for i in range(mpre.size - 1, 0, -1):
106 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
107 |
108 | # to calculate area under PR curve, look for points
109 | # where X axis (recall) changes value
110 | i = np.where(mrec[1:] != mrec[:-1])[0]
111 |
112 | # and sum (\Delta recall) * prec
113 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
114 | return ap
115 |
116 |
117 | def voc_eval(detpath,
118 | imagenames,
119 | boxes,
120 | cachedir,
121 | ovthresh=0.5,
122 | use_07_metric=True):
123 | """rec, prec, ap = voc_eval(detpath,
124 | annopath,
125 | imagesetfile,
126 | classname,
127 | [ovthresh],
128 | [use_07_metric])
129 | Top level function that does the PASCAL VOC evaluation.
130 | detpath: Path to detections
131 | detpath.format(classname) should produce the detection results file.
132 | annopath: Path to annotations
133 | annopath.format(imagename) should be the xml annotations file.
134 | imagesetfile: Text file containing the list of images, one image per line.
135 | classname: Category name (duh)
136 | cachedir: Directory for caching the annotations
137 | [ovthresh]: Overlap threshold (default = 0.5)
138 | [use_07_metric]: Whether to use VOC07's 11 point AP computation
139 | (default True)
140 | """
141 | # assumes detections are in detpath.format(classname)
142 | # assumes annotations are in annopath.format(imagename)
143 | # assumes imagesetfile is a text file with each line an image name
144 | # cachedir caches the annotations in a pickle file
145 | # first load gt
146 | if not os.path.isdir(cachedir):
147 | os.mkdir(cachedir)
148 | cachefile = os.path.join(cachedir, 'annots.pkl')
149 | # read list of images
150 | if not os.path.isfile(cachefile):
151 | # load annots
152 | recs = {}
153 | for i, imagename in enumerate(imagenames):
154 | imagename = os.path.basename(imagename)[:-4]
155 | recs[imagename] = boxes[i]
156 | if i % 100 == 0:
157 | print('Reading annotation for {:d}/{:d}'.format(
158 | i + 1, len(imagenames)))
159 | # save
160 | print('Saving cached annotations to {:s}'.format(cachefile))
161 | with open(cachefile, 'wb') as f:
162 | pickle.dump(recs, f)
163 | else:
164 | # load
165 | with open(cachefile, 'rb') as f:
166 | recs = pickle.load(f)
167 |
168 | # extract gt objects for this class
169 | class_recs = {}
170 | npos = 0
171 | for imagename in imagenames:
172 | imagename = os.path.basename(imagename)[:-4]
173 | bbox = np.array([x for x in recs[imagename]])
174 | npos = npos + len(bbox)
175 | det = [False] * len(bbox)
176 |
177 | class_recs[imagename] = {'bbox': bbox,
178 | 'det': det}
179 |
180 | # read dets
181 | #detfile = detpath.format(classname)
182 | detfile = detpath
183 | with open(detfile, 'r') as f:
184 | lines = f.readlines()
185 | if any(lines) == 1:
186 |
187 | splitlines = [x.strip().split(' ') for x in lines]
188 | image_ids = [x[0] for x in splitlines]
189 | confidence = np.array([float(x[1]) for x in splitlines])
190 | BB = np.array([[float(z) for z in x[2:]] for x in splitlines])
191 |
192 | # sort by confidence
193 | sorted_ind = np.argsort(-confidence)
194 | sorted_scores = np.sort(-confidence)
195 | BB = BB[sorted_ind, :]
196 | image_ids = [image_ids[x] for x in sorted_ind]
197 |
198 | # go down dets and mark TPs and FPs
199 | nd = len(image_ids)
200 | tp = np.zeros(nd)
201 | fp = np.zeros(nd)
202 | for d in range(nd):
203 | R = class_recs[image_ids[d]]
204 | bb = BB[d, :].astype(float)
205 | ovmax = -np.inf
206 | BBGT = R['bbox'].astype(float)
207 | if BBGT.size > 0:
208 | # compute overlaps
209 | # intersection
210 | ixmin = np.maximum(BBGT[:, 0], bb[0])
211 | iymin = np.maximum(BBGT[:, 1], bb[1])
212 | ixmax = np.minimum(BBGT[:, 2], bb[2])
213 | iymax = np.minimum(BBGT[:, 3], bb[3])
214 | iw = np.maximum(ixmax - ixmin, 0.)
215 | ih = np.maximum(iymax - iymin, 0.)
216 | inters = iw * ih
217 | uni = ((bb[2] - bb[0]) * (bb[3] - bb[1]) +
218 | (BBGT[:, 2] - BBGT[:, 0]) *
219 | (BBGT[:, 3] - BBGT[:, 1]) - inters)
220 | overlaps = inters / uni
221 | ovmax = np.max(overlaps)
222 | jmax = np.argmax(overlaps)
223 |
224 | if ovmax > ovthresh:
225 | if not R['det'][jmax]:
226 | tp[d] = 1.
227 | R['det'][jmax] = 1
228 | else:
229 | fp[d] = 1.
230 | else:
231 | fp[d] = 1.
232 |
233 | # compute precision recall
234 | fp = np.cumsum(fp)
235 | tp = np.cumsum(tp)
236 | rec = tp / float(npos)
237 | # avoid divide by zero in case the first detection matches a difficult
238 | # ground truth
239 | prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
240 | ap = voc_ap(rec, prec, use_07_metric)
241 | else:
242 | rec = -1.
243 | prec = -1.
244 | ap = -1.
245 |
246 | return rec, prec, ap
247 |
248 |
249 | def get_output_dir(name, phase):
250 | """Return the directory where experimental artifacts are placed.
251 | If the directory does not exist, it is created.
252 | A canonical path is built using the name from an imdb and a network
253 | (if not None).
254 | """
255 | filedir = os.path.join(name, phase)
256 | if not os.path.exists(filedir):
257 | os.makedirs(filedir)
258 | return filedir
259 |
260 |
261 | def get_voc_results_file_template(image_set, cls):
262 | # VOCdevkit/VOC2007/results/det_test_aeroplane.txt
263 | filename = 'det_' + image_set + '_%s.txt' % (cls)
264 | filedir = os.path.join(devkit_path, 'results')
265 | if not os.path.exists(filedir):
266 | os.makedirs(filedir)
267 | path = os.path.join(filedir, filename)
268 | return path
269 |
270 |
271 | def write_voc_results_file(all_boxes, dataset):
272 | for cls_ind, cls in enumerate(labelmap):
273 | print('Writing {:s} VOC results file'.format(cls))
274 | filename = get_voc_results_file_template(set_type, cls)
275 | with open(filename, 'wt') as f:
276 | for im_ind, index in enumerate(dataset.fnames):
277 | dets = all_boxes[cls_ind + 1][im_ind]
278 | if dets == []:
279 | continue
280 | # the VOCdevkit expects 1-based indices
281 | for k in range(dets.shape[0]):
282 | file = os.path.basename(index)[:-4]
283 | f.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.
284 | format(file, dets[k, -1],
285 | dets[k, 0] + 1, dets[k, 1] + 1,
286 | dets[k, 2] + 1, dets[k, 3] + 1))
287 |
288 | def do_python_eval(dataset,output_dir='output', use_07=True):
289 | cachedir = os.path.join(devkit_path, 'annotations_cache')
290 | aps = []
291 | # The PASCAL VOC metric changed in 2010
292 | use_07_metric = use_07
293 | print('VOC07 metric? ' + ('Yes' if use_07_metric else 'No'))
294 | if not os.path.isdir(output_dir):
295 | os.mkdir(output_dir)
296 | for i, cls in enumerate(labelmap):
297 | filename = get_voc_results_file_template(set_type, cls)
298 | rec, prec, ap = voc_eval(
299 | filename,dataset.fnames,dataset.boxes,cachedir,
300 | ovthresh=0.5, use_07_metric=use_07_metric)
301 | aps += [ap]
302 | print('AP for {} = {:.4f}'.format(cls, ap))
303 | with open(os.path.join(output_dir, cls + '_pr.pkl'), 'wb') as f:
304 | pickle.dump({'rec': rec, 'prec': prec, 'ap': ap}, f)
305 | print('Mean AP = {:.4f}'.format(np.mean(aps)))
306 | print('~~~~~~~~')
307 | print('Results:')
308 | for ap in aps:
309 | print('{:.3f}'.format(ap))
310 | print('{:.3f}'.format(np.mean(aps)))
311 | print('~~~~~~~~')
312 | print('')
313 | print('--------------------------------------------------------------')
314 | print('Results computed with the **unofficial** Python eval code.')
315 | print('Results should be very close to the official MATLAB eval code.')
316 | print('--------------------------------------------------------------')
317 |
318 |
319 | def test_net(save_folder, net, dataset, thresh=0.05):
320 | num_images = len(dataset)
321 |
322 | all_boxes = [[[] for _ in range(num_images)]
323 | for _ in range(2)]
324 | _t = {'im_detect': Timer(), 'misc': Timer()}
325 |
326 | output_dir = get_output_dir(os.path.join(
327 | save_folder, 'sfd_hand'), set_type)
328 | det_file = os.path.join(output_dir, 'detections.pkl')
329 |
330 | for i in range(num_images):
331 | img = dataset.pull_image(i)
332 | h, w, _ = img.shape
333 | shrink = np.sqrt(
334 | 1700 * 1200 / (img.shape[0] * img.shape[1]))
335 | image = cv2.resize(img, None, None, fx=shrink, fy=shrink,
336 | interpolation=cv2.INTER_LINEAR)
337 |
338 | x = to_chw_bgr(image)
339 | x = x.astype('float32')
340 | x -= cfg.img_mean
341 | x = x[[2, 1, 0], :, :]
342 | x = Variable(torch.from_numpy(x).unsqueeze(0))
343 | if use_cuda:
344 | x = x.cuda()
345 | _t['im_detect'].tic()
346 | detections = net(x).data
347 | detect_time = _t['im_detect'].toc(average=False)
348 |
349 | for j in range(1, detections.size(1)):
350 | dets = detections[0, j, :]
351 | mask = dets[:, 0].gt(thresh).expand(5, dets.size(0)).t()
352 | dets = torch.masked_select(dets, mask).view(-1, 5)
353 | if dets.dim() == 0:
354 | continue
355 | boxes = dets[:, 1:]
356 | boxes[:, 0] *= w
357 | boxes[:, 2] *= w
358 | boxes[:, 1] *= h
359 | boxes[:, 3] *= h
360 | scores = dets[:, 0].cpu().numpy()
361 | cls_dets = np.hstack((boxes.cpu().numpy(),
362 | scores[:, np.newaxis])).astype(np.float32,
363 | copy=False)
364 | all_boxes[j][i] = cls_dets
365 |
366 | fin_mask = np.where(scores > 0.6)[0]
367 | bboxes = boxes.cpu().numpy()[fin_mask]
368 | scores = scores[fin_mask]
369 | for k in range(len(scores)):
370 | leftup = (int(bboxes[k][0]), int(bboxes[k][1]))
371 | right_bottom = (int(bboxes[k][2]), int(bboxes[k][3]))
372 | cv2.rectangle(img, leftup, right_bottom, (0, 255, 0), 2)
373 |
374 | save_file = os.path.join(output_dir, '{}.jpg'.format(i + 1))
375 | cv2.imwrite(save_file,img)
376 |
377 |
378 | print('im_detect: {:d}/{:d} {:.3f}s'.format(i + 1,
379 | num_images, detect_time))
380 |
381 | with open(det_file, 'wb') as f:
382 | pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL)
383 |
384 |
385 | print('Evaluating detections')
386 | evaluate_detections(all_boxes, output_dir, dataset)
387 |
388 |
389 | def evaluate_detections(box_list, output_dir, dataset):
390 | write_voc_results_file(box_list, dataset)
391 | do_python_eval(dataset,output_dir)
392 |
393 |
394 |
395 | if __name__ == '__main__':
396 | net = build_s3fd('test', cfg.NUM_CLASSES)
397 | net.load_state_dict(torch.load(args.model))
398 | net.eval()
399 |
400 | if use_cuda:
401 | net.cuda()
402 | cudnn.benckmark = True
403 | print('finish loading model')
404 |
405 | dataset = HandDetection(cfg.HAND.VAL_FILE,mode='val')
406 |
407 | test_net(args.save_folder, net, dataset, args.thresh)
408 |
409 |
--------------------------------------------------------------------------------
/tools/eval_head.py:
--------------------------------------------------------------------------------
1 | # coding:utf-8
2 | from __future__ import division
3 | from __future__ import absolute_import
4 | from __future__ import print_function
5 |
6 | import numpy as np
7 | import os
8 | import xml.etree.ElementTree as ET
9 | import cPickle
10 |
11 | import torch
12 | import argparse
13 | import torch.nn as nn
14 | import torch.utils.data as data
15 | import torch.backends.cudnn as cudnn
16 | import torchvision.transforms as transforms
17 |
18 | import cv2
19 | import time
20 | import pickle
21 | from PIL import Image
22 |
23 | from data.config import cfg
24 | from s3fd import build_s3fd
25 | from torch.autograd import Variable
26 | from utils.augmentations import to_chw_bgr
27 | from data.vochead import VOCDetection, VOCAnnotationTransform
28 |
29 |
30 | parser = argparse.ArgumentParser(description='s3fd head eval')
31 | parser.add_argument('--save_folder',
32 | type=str, default='tmp/',
33 | help='Directory for detect result')
34 | parser.add_argument('--model',
35 | type=str,
36 | default='weights/s3fd.pth', help='trained model')
37 | parser.add_argument('--thresh',
38 | default=0.01, type=float,
39 | help='Final confidence threshold')
40 | parser.add_argument('--data',
41 | default='PartA',
42 | choices=['PartA', 'PartB'],
43 | help='evaluate dataset')
44 |
45 | args = parser.parse_args()
46 |
47 |
48 | if not os.path.exists(args.save_folder):
49 | os.makedirs(args.save_folder)
50 |
51 | use_cuda = torch.cuda.is_available()
52 |
53 | if use_cuda:
54 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
55 | else:
56 | torch.set_default_tensor_type('torch.FloatTensor')
57 |
58 |
59 | labelmap = ['person']
60 |
61 | voc_dir = 'VOC' + args.data
62 | annopath = os.path.join(cfg.HEAD.DIR, voc_dir, 'Annotations', '%s.xml')
63 | imgpath = os.path.join(cfg.HEAD.DIR, voc_dir, 'JPEGImages', '%s.jpg')
64 | imgsetpath = os.path.join(cfg.HEAD.DIR, voc_dir, 'ImageSets',
65 | 'Main', '{:s}.txt')
66 |
67 | devkit_path = os.path.join(cfg.HEAD.DIR, voc_dir)
68 | set_type = 'test'
69 |
70 |
71 | class Timer(object):
72 | """A simple timer."""
73 |
74 | def __init__(self):
75 | self.total_time = 0.
76 | self.calls = 0
77 | self.start_time = 0.
78 | self.diff = 0.
79 | self.average_time = 0.
80 |
81 | def tic(self):
82 | # using time.time instead of time.clock because time time.clock
83 | # does not normalize for multithreading
84 | self.start_time = time.time()
85 |
86 | def toc(self, average=True):
87 | self.diff = time.time() - self.start_time
88 | self.total_time += self.diff
89 | self.calls += 1
90 | self.average_time = self.total_time / self.calls
91 | if average:
92 | return self.average_time
93 | else:
94 | return self.diff
95 |
96 |
97 | def parse_rec(filename):
98 | """ Parse a PASCAL VOC xml file """
99 | tree = ET.parse(filename)
100 | objects = []
101 | for obj in tree.findall('object'):
102 | obj_struct = {}
103 | obj_struct['name'] = obj.find('name').text
104 | obj_struct['pose'] = obj.find('pose').text
105 | obj_struct['truncated'] = int(obj.find('truncated').text)
106 | obj_struct['difficult'] = int(obj.find('difficult').text)
107 | bbox = obj.find('bndbox')
108 | obj_struct['bbox'] = [int(bbox.find('xmin').text) - 1,
109 | int(bbox.find('ymin').text) - 1,
110 | int(bbox.find('xmax').text) - 1,
111 | int(bbox.find('ymax').text) - 1]
112 | objects.append(obj_struct)
113 |
114 | return objects
115 |
116 |
117 | def voc_ap(rec, prec, use_07_metric=True):
118 | """ ap = voc_ap(rec, prec, [use_07_metric])
119 | Compute VOC AP given precision and recall.
120 | If use_07_metric is true, uses the
121 | VOC 07 11 point method (default:True).
122 | """
123 | if use_07_metric:
124 | # 11 point metric
125 | ap = 0.
126 | for t in np.arange(0., 1.1, 0.1):
127 | if np.sum(rec >= t) == 0:
128 | p = 0
129 | else:
130 | p = np.max(prec[rec >= t])
131 | ap = ap + p / 11.
132 | else:
133 | # correct AP calculation
134 | # first append sentinel values at the end
135 | mrec = np.concatenate(([0.], rec, [1.]))
136 | mpre = np.concatenate(([0.], prec, [0.]))
137 |
138 | # compute the precision envelope
139 | for i in range(mpre.size - 1, 0, -1):
140 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
141 |
142 | # to calculate area under PR curve, look for points
143 | # where X axis (recall) changes value
144 | i = np.where(mrec[1:] != mrec[:-1])[0]
145 |
146 | # and sum (\Delta recall) * prec
147 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
148 | return ap
149 |
150 |
151 | def voc_eval(detpath,
152 | annopath,
153 | imagesetfile,
154 | classname,
155 | cachedir,
156 | ovthresh=0.5,
157 | use_07_metric=True):
158 | """rec, prec, ap = voc_eval(detpath,
159 | annopath,
160 | imagesetfile,
161 | classname,
162 | [ovthresh],
163 | [use_07_metric])
164 | Top level function that does the PASCAL VOC evaluation.
165 | detpath: Path to detections
166 | detpath.format(classname) should produce the detection results file.
167 | annopath: Path to annotations
168 | annopath.format(imagename) should be the xml annotations file.
169 | imagesetfile: Text file containing the list of images, one image per line.
170 | classname: Category name (duh)
171 | cachedir: Directory for caching the annotations
172 | [ovthresh]: Overlap threshold (default = 0.5)
173 | [use_07_metric]: Whether to use VOC07's 11 point AP computation
174 | (default True)
175 | """
176 | # assumes detections are in detpath.format(classname)
177 | # assumes annotations are in annopath.format(imagename)
178 | # assumes imagesetfile is a text file with each line an image name
179 | # cachedir caches the annotations in a pickle file
180 | # first load gt
181 | if not os.path.isdir(cachedir):
182 | os.mkdir(cachedir)
183 | cachefile = os.path.join(cachedir, 'annots.pkl')
184 | # read list of images
185 | with open(imagesetfile, 'r') as f:
186 | lines = f.readlines()
187 | imagenames = [x.strip() for x in lines]
188 | if not os.path.isfile(cachefile):
189 | # load annots
190 | recs = {}
191 | for i, imagename in enumerate(imagenames):
192 | recs[imagename] = parse_rec(annopath % (imagename))
193 | if i % 100 == 0:
194 | print('Reading annotation for {:d}/{:d}'.format(
195 | i + 1, len(imagenames)))
196 | # save
197 | print('Saving cached annotations to {:s}'.format(cachefile))
198 | with open(cachefile, 'wb') as f:
199 | pickle.dump(recs, f)
200 | else:
201 | # load
202 | with open(cachefile, 'rb') as f:
203 | recs = pickle.load(f)
204 |
205 | # extract gt objects for this class
206 | class_recs = {}
207 | npos = 0
208 | for imagename in imagenames:
209 | R = [obj for obj in recs[imagename] if obj['name'] == classname]
210 | bbox = np.array([x['bbox'] for x in R])
211 | difficult = np.array([x['difficult'] for x in R]).astype(np.bool)
212 | det = [False] * len(R)
213 | npos = npos + sum(~difficult)
214 | class_recs[imagename] = {'bbox': bbox,
215 | 'difficult': difficult,
216 | 'det': det}
217 |
218 | # read dets
219 | detfile = detpath.format(classname)
220 | with open(detfile, 'r') as f:
221 | lines = f.readlines()
222 | if any(lines) == 1:
223 |
224 | splitlines = [x.strip().split(' ') for x in lines]
225 | image_ids = [x[0] for x in splitlines]
226 | confidence = np.array([float(x[1]) for x in splitlines])
227 | BB = np.array([[float(z) for z in x[2:]] for x in splitlines])
228 |
229 | # sort by confidence
230 | sorted_ind = np.argsort(-confidence)
231 | sorted_scores = np.sort(-confidence)
232 | BB = BB[sorted_ind, :]
233 | image_ids = [image_ids[x] for x in sorted_ind]
234 |
235 | # go down dets and mark TPs and FPs
236 | nd = len(image_ids)
237 | tp = np.zeros(nd)
238 | fp = np.zeros(nd)
239 | for d in range(nd):
240 | R = class_recs[image_ids[d]]
241 | bb = BB[d, :].astype(float)
242 | ovmax = -np.inf
243 | BBGT = R['bbox'].astype(float)
244 | if BBGT.size > 0:
245 | # compute overlaps
246 | # intersection
247 | ixmin = np.maximum(BBGT[:, 0], bb[0])
248 | iymin = np.maximum(BBGT[:, 1], bb[1])
249 | ixmax = np.minimum(BBGT[:, 2], bb[2])
250 | iymax = np.minimum(BBGT[:, 3], bb[3])
251 | iw = np.maximum(ixmax - ixmin, 0.)
252 | ih = np.maximum(iymax - iymin, 0.)
253 | inters = iw * ih
254 | uni = ((bb[2] - bb[0]) * (bb[3] - bb[1]) +
255 | (BBGT[:, 2] - BBGT[:, 0]) *
256 | (BBGT[:, 3] - BBGT[:, 1]) - inters)
257 | overlaps = inters / uni
258 | ovmax = np.max(overlaps)
259 | jmax = np.argmax(overlaps)
260 |
261 | if ovmax > ovthresh:
262 | if not R['difficult'][jmax]:
263 | if not R['det'][jmax]:
264 | tp[d] = 1.
265 | R['det'][jmax] = 1
266 | else:
267 | fp[d] = 1.
268 | else:
269 | fp[d] = 1.
270 |
271 | # compute precision recall
272 | fp = np.cumsum(fp)
273 | tp = np.cumsum(tp)
274 | rec = tp / float(npos)
275 | # avoid divide by zero in case the first detection matches a difficult
276 | # ground truth
277 | prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
278 | ap = voc_ap(rec, prec, use_07_metric)
279 | else:
280 | rec = -1.
281 | prec = -1.
282 | ap = -1.
283 |
284 | return rec, prec, ap
285 |
286 |
287 | def get_output_dir(name, phase):
288 | """Return the directory where experimental artifacts are placed.
289 | If the directory does not exist, it is created.
290 | A canonical path is built using the name from an imdb and a network
291 | (if not None).
292 | """
293 | filedir = os.path.join(name, phase)
294 | if not os.path.exists(filedir):
295 | os.makedirs(filedir)
296 | return filedir
297 |
298 |
299 | def get_voc_results_file_template(image_set, cls):
300 | # VOCdevkit/VOC2007/results/det_test_aeroplane.txt
301 | filename = 'det_' + image_set + '_%s.txt' % (cls)
302 | filedir = os.path.join(devkit_path, 'results')
303 | if not os.path.exists(filedir):
304 | os.makedirs(filedir)
305 | path = os.path.join(filedir, filename)
306 | return path
307 |
308 |
309 | def write_voc_results_file(all_boxes, dataset):
310 | for cls_ind, cls in enumerate(labelmap):
311 | print('Writing {:s} VOC results file'.format(cls))
312 | filename = get_voc_results_file_template(set_type, cls)
313 | with open(filename, 'wt') as f:
314 | for im_ind, index in enumerate(dataset.ids):
315 | dets = all_boxes[cls_ind + 1][im_ind]
316 | if dets == []:
317 | continue
318 | # the VOCdevkit expects 1-based indices
319 | for k in range(dets.shape[0]):
320 | f.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.
321 | format(index[1], dets[k, -1],
322 | dets[k, 0] + 1, dets[k, 1] + 1,
323 | dets[k, 2] + 1, dets[k, 3] + 1))
324 |
325 |
326 | def do_python_eval(output_dir='output', use_07=True):
327 | cachedir = os.path.join(devkit_path, 'annotations_cache')
328 | aps = []
329 | # The PASCAL VOC metric changed in 2010
330 | use_07_metric = use_07
331 | print('VOC07 metric? ' + ('Yes' if use_07_metric else 'No'))
332 | if not os.path.isdir(output_dir):
333 | os.mkdir(output_dir)
334 | for i, cls in enumerate(labelmap):
335 | filename = get_voc_results_file_template(set_type, cls)
336 | rec, prec, ap = voc_eval(
337 | filename, annopath, imgsetpath.format(set_type), cls, cachedir,
338 | ovthresh=0.5, use_07_metric=use_07_metric)
339 | aps += [ap]
340 | print('AP for {} = {:.4f}'.format(cls, ap))
341 | with open(os.path.join(output_dir, cls + '_pr.pkl'), 'wb') as f:
342 | pickle.dump({'rec': rec, 'prec': prec, 'ap': ap}, f)
343 | print('Mean AP = {:.4f}'.format(np.mean(aps)))
344 | print('~~~~~~~~')
345 | print('Results:')
346 | for ap in aps:
347 | print('{:.3f}'.format(ap))
348 | print('{:.3f}'.format(np.mean(aps)))
349 | print('~~~~~~~~')
350 | print('')
351 | print('--------------------------------------------------------------')
352 | print('Results computed with the **unofficial** Python eval code.')
353 | print('Results should be very close to the official MATLAB eval code.')
354 | print('--------------------------------------------------------------')
355 |
356 |
357 | def test_net(save_folder, net, dataset, thresh=0.05):
358 | num_images = len(dataset)
359 |
360 | all_boxes = [[[] for _ in range(num_images)]
361 | for _ in range(len(labelmap) + 1)]
362 |
363 | _t = {'im_detect': Timer(), 'misc': Timer()}
364 |
365 | output_dir = get_output_dir(os.path.join(
366 | save_folder, 'sfd_head'), set_type)
367 | det_file = os.path.join(output_dir, 'detections.pkl')
368 |
369 | for i in range(num_images):
370 | img = dataset.pull_image(i)
371 | h, w, _ = img.shape
372 | shrink = np.sqrt(
373 | 1700 * 1200 / (img.shape[0] * img.shape[1]))
374 | image = cv2.resize(img, None, None, fx=shrink, fy=shrink,
375 | interpolation=cv2.INTER_LINEAR)
376 |
377 | x = to_chw_bgr(image)
378 | x = x.astype('float32')
379 | x -= cfg.img_mean
380 | x = x[[2, 1, 0], :, :]
381 | x = Variable(torch.from_numpy(x).unsqueeze(0))
382 | if use_cuda:
383 | x = x.cuda()
384 | _t['im_detect'].tic()
385 | detections = net(x).data
386 | detect_time = _t['im_detect'].toc(average=False)
387 |
388 | for j in range(1, detections.size(1)):
389 | dets = detections[0, j, :]
390 | mask = dets[:, 0].gt(thresh).expand(5, dets.size(0)).t()
391 | dets = torch.masked_select(dets, mask).view(-1, 5)
392 | if dets.dim() == 0:
393 | continue
394 | boxes = dets[:, 1:]
395 | boxes[:, 0] *= w
396 | boxes[:, 2] *= w
397 | boxes[:, 1] *= h
398 | boxes[:, 3] *= h
399 | scores = dets[:, 0].cpu().numpy()
400 | cls_dets = np.hstack((boxes.cpu().numpy(),
401 | scores[:, np.newaxis])).astype(np.float32,
402 | copy=False)
403 | all_boxes[j][i] = cls_dets
404 | fin_mask = np.where(scores > 0.6)[0]
405 | bboxes = boxes.cpu().numpy()[fin_mask]
406 | scores = scores[fin_mask]
407 | for k in range(len(scores)):
408 | leftup = (int(bboxes[k][0]), int(bboxes[k][1]))
409 | right_bottom = (int(bboxes[k][2]), int(bboxes[k][3]))
410 | cv2.rectangle(img, leftup, right_bottom, (0, 255, 0), 2)
411 |
412 | save_file = os.path.join(output_dir, '{}.jpg'.format(i + 1))
413 | cv2.imwrite(save_file,img)
414 | print('im_detect: {:d}/{:d} {:.3f}s'.format(i + 1,
415 | num_images, detect_time))
416 | with open(det_file, 'wb') as f:
417 | pickle.dump(all_boxes, f, pickle.HIGHEST_PROTOCOL)
418 |
419 | print('Evaluating detections')
420 | evaluate_detections(all_boxes, output_dir, dataset)
421 |
422 |
423 | def evaluate_detections(box_list, output_dir, dataset):
424 | write_voc_results_file(box_list, dataset)
425 | do_python_eval(output_dir)
426 |
427 |
428 | if __name__ == '__main__':
429 | net = build_s3fd('test', cfg.NUM_CLASSES)
430 | net.load_state_dict(torch.load(args.model))
431 | net.eval()
432 |
433 | if use_cuda:
434 | net.cuda()
435 | cudnn.benckmark = True
436 | print('finish loading model')
437 |
438 | dataset = VOCDetection(cfg.HEAD.DIR, image_sets=[(args.data, 'test')],
439 | target_transform=VOCAnnotationTransform(),
440 | mode='test',
441 | dataset_name='VOCPartAB')
442 |
443 | test_net(args.save_folder, net, dataset, args.thresh)
444 |
--------------------------------------------------------------------------------
/tools/fddb_test.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import sys
9 | import torch
10 | import argparse
11 | import torch.nn as nn
12 | import torch.utils.data as data
13 | import torch.backends.cudnn as cudnn
14 | import torchvision.transforms as transforms
15 |
16 | import cv2
17 | import time
18 | import numpy as np
19 | from PIL import Image
20 |
21 | from data.config import cfg
22 | from s3fd import build_s3fd
23 | from torch.autograd import Variable
24 | from utils.augmentations import to_chw_bgr
25 |
26 | parser = argparse.ArgumentParser(description='s3fd evaluatuon fddb')
27 | parser.add_argument('--model', type=str,
28 | default='weights/s3fd.pth', help='trained model')
29 | parser.add_argument('--thresh', default=0.1, type=float,
30 | help='Final confidence threshold')
31 | args = parser.parse_args()
32 |
33 |
34 | use_cuda = torch.cuda.is_available()
35 |
36 | if use_cuda:
37 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
38 | else:
39 | torch.set_default_tensor_type('torch.FloatTensor')
40 |
41 |
42 | FDDB_IMG_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'images')
43 | FDDB_FOLD_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'FDDB-folds')
44 | FDDB_RESULT_DIR = os.path.join(cfg.FACE.FDDB_DIR, 's3fd')
45 | FDDB_RESULT_IMG_DIR = os.path.join(FDDB_RESULT_DIR, 'images')
46 |
47 | if not os.path.exists(FDDB_RESULT_IMG_DIR):
48 | os.makedirs(FDDB_RESULT_IMG_DIR)
49 |
50 |
51 | def detect_face(net, img, thresh):
52 | height, width, _ = img.shape
53 | x = to_chw_bgr(img)
54 | x = x.astype('float32')
55 | x -= cfg.img_mean
56 | x = x[[2, 1, 0], :, :]
57 |
58 | x = Variable(torch.from_numpy(x).unsqueeze(0))
59 | if use_cuda:
60 | x = x.cuda()
61 |
62 | y = net(x)
63 | detections = y.data
64 | scale = torch.Tensor([img.shape[1], img.shape[0],
65 | img.shape[1], img.shape[0]])
66 |
67 | bboxes = []
68 | for i in range(detections.size(1)):
69 | j = 0
70 | while detections[0, i, j, 0] >= thresh:
71 | box = []
72 | score = detections[0, i, j, 0]
73 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int)
74 | j += 1
75 | box += [pt[0], pt[1], pt[2] - pt[0], pt[3] - pt[1], score]
76 | bboxes += [box]
77 |
78 | return bboxes
79 |
80 |
81 | if __name__ == '__main__':
82 | net = build_s3fd('test', cfg.NUM_CLASSES)
83 | net.load_state_dict(torch.load(args.model))
84 | net.eval()
85 |
86 | if use_cuda:
87 | net.cuda()
88 | cudnn.benckmark = True
89 |
90 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS)
91 |
92 | counter = 0
93 |
94 | for i in range(10):
95 | txt_in = os.path.join(FDDB_FOLD_DIR, 'FDDB-fold-%02d.txt' % (i + 1))
96 | txt_out = os.path.join(FDDB_RESULT_DIR, 'fold-%02d-out.txt' % (i + 1))
97 | answer_in = os.path.join(
98 | FDDB_FOLD_DIR, 'FDDB-fold-%02d-ellipseList.txt' % (i + 1))
99 | with open(txt_in, 'r') as fr:
100 | lines = fr.readlines()
101 | fout = open(txt_out, 'w')
102 | ain = open(answer_in, 'r')
103 | for line in lines:
104 | line = line.strip()
105 | img_file = os.path.join(FDDB_IMG_DIR, line + '.jpg')
106 | out_file = os.path.join(
107 | FDDB_RESULT_IMG_DIR, line.replace('/', '_') + '.jpg')
108 | counter += 1
109 | t1 = time.time()
110 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR)
111 | img = Image.open(img_file)
112 | if img.mode == 'L':
113 | img = img.convert('RGB')
114 | img = np.array(img)
115 | bboxes = detect_face(net, img, args.thresh)
116 | t2 = time.time()
117 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1))
118 | fout.write('%s\n' % line)
119 | fout.write('%d\n' % len(bboxes))
120 | for bbox in bboxes:
121 | x1, y1, w, h, score = bbox
122 | fout.write('%d %d %d %d %lf\n' % (x1, y1, w, h, score))
123 | ain.readline()
124 | n = int(ain.readline().strip())
125 | for i in range(n):
126 | line = ain.readline().strip()
127 | line_data = [float(_) for _ in line.split(' ')[:5]]
128 | major_axis_radius, minor_axis_radius, angle, center_x, center_y = line_data
129 | angle = angle / 3.1415926 * 180.
130 | center_x, center_y = int(center_x), int(center_y)
131 | major_axis_radius, minor_axis_radius = int(
132 | major_axis_radius), int(minor_axis_radius)
133 | cv2.ellipse(img, (center_x, center_y), (major_axis_radius,
134 | minor_axis_radius), angle, 0, 360, (255, 0, 0), 2)
135 |
136 | for bbox in bboxes:
137 | x1, y1, w, h, score = bbox
138 | x1, y1, x2, y2 = int(x1), int(y1), int(x1 + w), int(y1 + h)
139 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
140 | cv2.imwrite(out_file, img)
141 | fout.close()
142 | ain.close()
143 |
--------------------------------------------------------------------------------
/tools/pascal_test.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import sys
9 | import torch
10 | import argparse
11 | import torch.nn as nn
12 | import torch.utils.data as data
13 | import torch.backends.cudnn as cudnn
14 | import torchvision.transforms as transforms
15 |
16 | import cv2
17 | import time
18 | import numpy as np
19 | from PIL import Image
20 |
21 | from data.config import cfg
22 | from s3fd import build_s3fd
23 | from torch.autograd import Variable
24 | from utils.augmentations import to_chw_bgr
25 |
26 |
27 | parser = argparse.ArgumentParser(description='s3df evaluatuon pascal')
28 | parser.add_argument('--model', type=str,
29 | default='weights/s3fd.pth', help='trained model')
30 | parser.add_argument('--thresh', default=0.1, type=float,
31 | help='Final confidence threshold')
32 | args = parser.parse_args()
33 |
34 | use_cuda = torch.cuda.is_available()
35 |
36 | if use_cuda:
37 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
38 | else:
39 | torch.set_default_tensor_type('torch.FloatTensor')
40 |
41 | PASCAL_IMG_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'images')
42 | PASCAL_RESULT_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 's3fd')
43 | PASCAL_RESULT_IMG_DIR = os.path.join(PASCAL_RESULT_DIR, 'images')
44 |
45 | if not os.path.exists(PASCAL_RESULT_IMG_DIR):
46 | os.makedirs(PASCAL_RESULT_IMG_DIR)
47 |
48 |
49 | def detect_face(net, img, thresh):
50 | height, width, _ = img.shape
51 | im_shrink = 640.0 / max(height, width)
52 | image = cv2.resize(img, None, None, fx=im_shrink,
53 | fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy()
54 |
55 | x = to_chw_bgr(image)
56 | x = x.astype('float32')
57 | x -= cfg.img_mean
58 | x = x[[2, 1, 0], :, :]
59 |
60 | x = Variable(torch.from_numpy(x).unsqueeze(0))
61 | if use_cuda:
62 | x = x.cuda()
63 |
64 | y = net(x)
65 | detections = y.data
66 | scale = torch.Tensor([img.shape[1], img.shape[0],
67 | img.shape[1], img.shape[0]])
68 |
69 | bboxes = []
70 | for i in range(detections.size(1)):
71 | j = 0
72 | while detections[0, i, j, 0] >= thresh:
73 | box = []
74 | score = detections[0, i, j, 0]
75 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int)
76 | j += 1
77 | box += [pt[0], pt[1], pt[2], pt[3], score]
78 | box[1] += 0.2 * (box[3] - box[1] + 1)
79 | bboxes += [box]
80 |
81 | return bboxes
82 |
83 |
84 | if __name__ == '__main__':
85 | net = build_s3fd('test', cfg.NUM_CLASSES)
86 | net.load_state_dict(torch.load(args.model))
87 | net.eval()
88 |
89 | if use_cuda:
90 | net.cuda()
91 | cudnn.benckmark = True
92 |
93 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS)
94 |
95 | counter = 0
96 | txt_out = os.path.join(PASCAL_RESULT_DIR, 'sfd_dets.txt')
97 | txt_in = os.path.join('./tools/pascal_img_list.txt')
98 |
99 | fout = open(txt_out, 'w')
100 | fin = open(txt_in, 'r')
101 |
102 | for line in fin.readlines():
103 | line = line.strip()
104 | img_file = os.path.join(PASCAL_IMG_DIR, line)
105 | out_file = os.path.join(PASCAL_RESULT_IMG_DIR, line)
106 | counter += 1
107 | t1 = time.time()
108 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR)
109 | img = Image.open(img_file)
110 | if img.mode == 'L':
111 | img = img.convert('RGB')
112 | img = np.array(img)
113 | bboxes = detect_face(net, img, args.thresh)
114 | t2 = time.time()
115 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1))
116 | for bbox in bboxes:
117 | x1, y1, x2, y2, score = bbox
118 | fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format(
119 | line, score, x1, y1, x2, y2))
120 | for bbox in bboxes:
121 | x1, y1, x2, y2, score = bbox
122 | x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
123 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
124 | cv2.imwrite(out_file, img)
125 |
126 | fout.close()
127 | fin.close()
128 |
--------------------------------------------------------------------------------
/tools/wider_test.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import torch
9 | import argparse
10 | import torch.nn as nn
11 | import torch.utils.data as data
12 | import torch.backends.cudnn as cudnn
13 | import torchvision.transforms as transforms
14 | import os.path as osp
15 |
16 | import cv2
17 | import time
18 | import numpy as np
19 | from PIL import Image
20 | import scipy.io as sio
21 |
22 | from data.config import cfg
23 | from s3fd import build_s3fd
24 | from torch.autograd import Variable
25 | from utils.augmentations import to_chw_bgr
26 |
27 |
28 | parser = argparse.ArgumentParser(description='s3fd evaluatuon wider')
29 | parser.add_argument('--model', type=str,
30 | default='weights/s3fd.pth', help='trained model')
31 | parser.add_argument('--thresh', default=0.05, type=float,
32 | help='Final confidence threshold')
33 | args = parser.parse_args()
34 |
35 |
36 | use_cuda = torch.cuda.is_available()
37 |
38 | if use_cuda:
39 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
40 | else:
41 | torch.set_default_tensor_type('torch.FloatTensor')
42 |
43 |
44 | def detect_face(net, img, shrink):
45 | if shrink != 1:
46 | img = cv2.resize(img, None, None, fx=shrink, fy=shrink,
47 | interpolation=cv2.INTER_LINEAR)
48 |
49 | x = to_chw_bgr(img)
50 | x = x.astype('float32')
51 | x -= cfg.img_mean
52 | x = x[[2, 1, 0], :, :]
53 |
54 | x = Variable(torch.from_numpy(x).unsqueeze(0))
55 |
56 | if use_cuda:
57 | x = x.cuda()
58 | # print(x.size())
59 | y = net(x)
60 | detections = y.data
61 | detections = detections.cpu().numpy()
62 |
63 | det_conf = detections[0, 1, :, 0]
64 | det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink
65 | det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink
66 | det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink
67 | det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink
68 | det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf))
69 |
70 | keep_index = np.where(det[:, 4] >= args.thresh)[0]
71 | det = det[keep_index, :]
72 |
73 | return det
74 |
75 |
76 | def flip_test(net, image, shrink):
77 | image_f = cv2.flip(image, 1)
78 | det_f = detect_face(net, image_f, shrink)
79 |
80 | det_t = np.zeros(det_f.shape)
81 | det_t[:, 0] = image.shape[1] - det_f[:, 2]
82 | det_t[:, 1] = det_f[:, 1]
83 | det_t[:, 2] = image.shape[1] - det_f[:, 0]
84 | det_t[:, 3] = det_f[:, 3]
85 | det_t[:, 4] = det_f[:, 4]
86 | return det_t
87 |
88 |
89 | def multi_scale_test(net, image, max_im_shrink):
90 | # shrink detecting and shrink only detect big face
91 | st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink
92 | det_s = detect_face(net, image, st)
93 | index = np.where(np.maximum(
94 | det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0]
95 | det_s = det_s[index, :]
96 |
97 | # enlarge one times
98 | bt = min(2, max_im_shrink) if max_im_shrink > 1 else (
99 | st + max_im_shrink) / 2
100 | det_b = detect_face(net, image, bt)
101 |
102 | # enlarge small image x times for small face
103 | if max_im_shrink > 2:
104 | bt *= 2
105 | while bt < max_im_shrink:
106 | det_b = np.row_stack((det_b, detect_face(net, image, bt)))
107 | bt *= 2
108 | det_b = np.row_stack((det_b, detect_face(net, image, max_im_shrink)))
109 |
110 | # enlarge only detect small face
111 | if bt > 1:
112 | index = np.where(np.minimum(
113 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0]
114 | det_b = det_b[index, :]
115 | else:
116 | index = np.where(np.maximum(
117 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0]
118 | det_b = det_b[index, :]
119 |
120 | return det_s, det_b
121 |
122 |
123 | def bbox_vote(det):
124 | order = det[:, 4].ravel().argsort()[::-1]
125 | det = det[order, :]
126 | while det.shape[0] > 0:
127 | # IOU
128 | area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1)
129 | xx1 = np.maximum(det[0, 0], det[:, 0])
130 | yy1 = np.maximum(det[0, 1], det[:, 1])
131 | xx2 = np.minimum(det[0, 2], det[:, 2])
132 | yy2 = np.minimum(det[0, 3], det[:, 3])
133 | w = np.maximum(0.0, xx2 - xx1 + 1)
134 | h = np.maximum(0.0, yy2 - yy1 + 1)
135 | inter = w * h
136 | o = inter / (area[0] + area[:] - inter)
137 |
138 | # get needed merge det and delete these det
139 | merge_index = np.where(o >= 0.3)[0]
140 | det_accu = det[merge_index, :]
141 | det = np.delete(det, merge_index, 0)
142 |
143 | if merge_index.shape[0] <= 1:
144 | continue
145 | det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4))
146 | max_score = np.max(det_accu[:, 4])
147 | det_accu_sum = np.zeros((1, 5))
148 | det_accu_sum[:, 0:4] = np.sum(
149 | det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:])
150 | det_accu_sum[:, 4] = max_score
151 | try:
152 | dets = np.row_stack((dets, det_accu_sum))
153 | except:
154 | dets = det_accu_sum
155 |
156 | dets = dets[0:750, :]
157 | return dets
158 |
159 |
160 | def get_data():
161 | subset = 'val'
162 | if subset is 'val':
163 | wider_face = sio.loadmat(
164 | './eval_tools/wider_face_val.mat')
165 | else:
166 | wider_face = sio.loadmat(
167 | './eval_tools/wider_face_test.mat')
168 | event_list = wider_face['event_list']
169 | file_list = wider_face['file_list']
170 | del wider_face
171 |
172 | imgs_path = os.path.join(
173 | cfg.FACE.WIDER_DIR, 'WIDER_{}'.format(subset), 'images')
174 | save_path = 'eval_tools/s3fd_{}'.format(subset)
175 |
176 | return event_list, file_list, imgs_path, save_path
177 |
178 | if __name__ == '__main__':
179 | event_list, file_list, imgs_path, save_path = get_data()
180 | cfg.USE_NMS = False
181 | net = build_s3fd('test', cfg.NUM_CLASSES)
182 | net.load_state_dict(torch.load(args.model))
183 | net.eval()
184 |
185 | if use_cuda:
186 | net.cuda()
187 | cudnn.benckmark = True
188 |
189 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS)
190 |
191 | counter = 0
192 |
193 | for index, event in enumerate(event_list):
194 | filelist = file_list[index][0]
195 | path = os.path.join(save_path, event[0][0].encode('utf-8'))
196 | if not os.path.exists(path):
197 | os.makedirs(path)
198 |
199 | for num, file in enumerate(filelist):
200 | im_name = file[0][0].encode('utf-8')
201 | in_file = os.path.join(imgs_path, event[0][0], im_name[:] + '.jpg')
202 | #img = cv2.imread(in_file)
203 | img = Image.open(in_file)
204 | if img.mode == 'L':
205 | img = img.convert('RGB')
206 | img = np.array(img)
207 |
208 | # max_im_shrink = (0x7fffffff / 577.0 /
209 | # (img.shape[0] * img.shape[1])) ** 0.5
210 |
211 | max_im_shrink = np.sqrt(
212 | 1700 * 1200 / (img.shape[0] * img.shape[1]))
213 |
214 | shrink = max_im_shrink if max_im_shrink < 1 else 1
215 | counter += 1
216 |
217 | t1 = time.time()
218 | det0 = detect_face(net, img, shrink)
219 |
220 | det1 = flip_test(net, img, shrink) # flip test
221 | [det2, det3] = multi_scale_test(net, img, max_im_shrink)
222 |
223 | det = np.row_stack((det0, det1, det2, det3))
224 | dets = bbox_vote(det)
225 |
226 | t2 = time.time()
227 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1))
228 |
229 | fout = open(osp.join(save_path, event[0][
230 | 0].encode('utf-8'), im_name + '.txt'), 'w')
231 | fout.write('{:s}\n'.format(event[0][0].encode(
232 | 'utf-8') + '/' + im_name + '.jpg'))
233 | fout.write('{:d}\n'.format(dets.shape[0]))
234 | for i in xrange(dets.shape[0]):
235 | xmin = dets[i][0]
236 | ymin = dets[i][1]
237 | xmax = dets[i][2]
238 | ymax = dets[i][3]
239 | score = dets[i][4]
240 | fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n'.
241 | format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score))
242 |
--------------------------------------------------------------------------------
/train.py:
--------------------------------------------------------------------------------
1 | #-*- coding:utf-8 -*-
2 |
3 | from __future__ import division
4 | from __future__ import absolute_import
5 | from __future__ import print_function
6 |
7 | import os
8 | import time
9 | import torch
10 | import argparse
11 | import torch.nn as nn
12 | import torch.optim as optim
13 | import torch.nn.init as init
14 | import torch.utils.data as data
15 | import numpy as np
16 | from torch.autograd import Variable
17 | import torch.backends.cudnn as cudnn
18 |
19 | from data.config import cfg
20 | from s3fd import build_s3fd
21 | from layers.modules import MultiBoxLoss
22 | from data.factory import dataset_factory, detection_collate
23 |
24 | #os.environ['CUDA_LAUNCH_BLOCKING'] = '1'
25 |
26 |
27 | def str2bool(v):
28 | return v.lower() in ("yes", "true", "t", "1")
29 |
30 | parser = argparse.ArgumentParser(
31 | description='S3FD face Detector Training With Pytorch')
32 | train_set = parser.add_mutually_exclusive_group()
33 | parser.add_argument('--dataset',
34 | default='face',
35 | choices=['hand', 'face', 'head'],
36 | help='Train target')
37 | parser.add_argument('--basenet',
38 | default='vgg16_reducedfc.pth',
39 | help='Pretrained base model')
40 | parser.add_argument('--batch_size',
41 | default=16, type=int,
42 | help='Batch size for training')
43 | parser.add_argument('--resume',
44 | default=None, type=str,
45 | help='Checkpoint state_dict file to resume training from')
46 | parser.add_argument('--num_workers',
47 | default=4, type=int,
48 | help='Number of workers used in dataloading')
49 | parser.add_argument('--cuda',
50 | default=True, type=str2bool,
51 | help='Use CUDA to train model')
52 | parser.add_argument('--lr', '--learning-rate',
53 | default=1e-3, type=float,
54 | help='initial learning rate')
55 | parser.add_argument('--momentum',
56 | default=0.9, type=float,
57 | help='Momentum value for optim')
58 | parser.add_argument('--weight_decay',
59 | default=5e-4, type=float,
60 | help='Weight decay for SGD')
61 | parser.add_argument('--gamma',
62 | default=0.1, type=float,
63 | help='Gamma update for SGD')
64 | parser.add_argument('--multigpu',
65 | default=False, type=str2bool,
66 | help='Use mutil Gpu training')
67 | parser.add_argument('--save_folder',
68 | default='weights/',
69 | help='Directory for saving checkpoint models')
70 | args = parser.parse_args()
71 |
72 |
73 | if torch.cuda.is_available():
74 | if args.cuda:
75 | torch.set_default_tensor_type('torch.cuda.FloatTensor')
76 | if not args.cuda:
77 | print("WARNING: It looks like you have a CUDA device, but aren't " +
78 | "using CUDA.\nRun with --cuda for optimal training speed.")
79 | torch.set_default_tensor_type('torch.FloatTensor')
80 | else:
81 | torch.set_default_tensor_type('torch.FloatTensor')
82 |
83 | if not os.path.exists(args.save_folder):
84 | os.makedirs(args.save_folder)
85 |
86 |
87 | train_dataset, val_dataset = dataset_factory(args.dataset)
88 |
89 | train_loader = data.DataLoader(train_dataset, args.batch_size,
90 | num_workers=args.num_workers,
91 | shuffle=True,
92 | collate_fn=detection_collate,
93 | pin_memory=True)
94 |
95 | val_batchsize = args.batch_size // 2
96 | val_loader = data.DataLoader(val_dataset, val_batchsize,
97 | num_workers=args.num_workers,
98 | shuffle=False,
99 | collate_fn=detection_collate,
100 | pin_memory=True)
101 |
102 | min_loss = np.inf
103 | start_epoch = 0
104 | s3fd_net = build_s3fd('train', cfg.NUM_CLASSES)
105 | net = s3fd_net
106 |
107 |
108 | if args.resume:
109 | print('Resuming training, loading {}...'.format(args.resume))
110 | start_epoch = net.load_weights(args.resume)
111 |
112 | else:
113 | vgg_weights = torch.load(args.save_folder + args.basenet)
114 | print('Load base network....')
115 | net.vgg.load_state_dict(vgg_weights)
116 |
117 | if args.cuda:
118 | if args.multigpu:
119 | net = torch.nn.DataParallel(s3fd_net)
120 | net = net.cuda()
121 | cudnn.benckmark = True
122 |
123 | if not args.resume:
124 | print('Initializing weights...')
125 | s3fd_net.extras.apply(s3fd_net.weights_init)
126 | s3fd_net.loc.apply(s3fd_net.weights_init)
127 | s3fd_net.conf.apply(s3fd_net.weights_init)
128 |
129 | optimizer = optim.SGD(net.parameters(), lr=args.lr, momentum=args.momentum,
130 | weight_decay=args.weight_decay)
131 | criterion = MultiBoxLoss(cfg, args.dataset, args.cuda)
132 | print('Loading wider dataset...')
133 | print('Using the specified args:')
134 | print(args)
135 |
136 |
137 | def train():
138 | step_index = 0
139 | iteration = 0
140 | net.train()
141 | for epoch in range(start_epoch, cfg.EPOCHES):
142 | losses = 0
143 | for batch_idx, (images, targets) in enumerate(train_loader):
144 | if args.cuda:
145 | images = Variable(images.cuda())
146 | targets = [Variable(ann.cuda(), volatile=True)
147 | for ann in targets]
148 | else:
149 | images = Variable(images)
150 | targets = [Variable(ann, volatile=True) for ann in targets]
151 |
152 | if iteration in cfg.LR_STEPS:
153 | step_index += 1
154 | adjust_learning_rate(optimizer, args.gamma, step_index)
155 |
156 | t0 = time.time()
157 | out = net(images)
158 | # backprop
159 | optimizer.zero_grad()
160 | loss_l, loss_c = criterion(out, targets)
161 | loss = loss_l + loss_c
162 | loss.backward()
163 | optimizer.step()
164 | t1 = time.time()
165 | losses += loss.data[0]
166 |
167 | if iteration % 10 == 0:
168 | tloss = losses / (batch_idx + 1)
169 | print('Timer: %.4f' % (t1 - t0))
170 | print('epoch:' + repr(epoch) + ' || iter:' +
171 | repr(iteration) + ' || Loss:%.4f' % (tloss))
172 | print('->> conf loss:{:.4f} || loc loss:{:.4f}'.format(
173 | loss_c.data[0], loss_l.data[0]))
174 | print('->>lr:{:.6f}'.format(optimizer.param_groups[0]['lr']))
175 |
176 | if iteration != 0 and iteration % 5000 == 0:
177 | print('Saving state, iter:', iteration)
178 | file = 'sfd_' + args.dataset + '_' + repr(iteration) + '.pth'
179 | torch.save(s3fd_net.state_dict(),
180 | os.path.join(args.save_folder, file))
181 | iteration += 1
182 |
183 | val(epoch)
184 | if iteration == cfg.MAX_STEPS:
185 | break
186 |
187 |
188 | def val(epoch):
189 | net.eval()
190 | loc_loss = 0
191 | conf_loss = 0
192 | step = 0
193 | t1 = time.time()
194 | for batch_idx, (images, targets) in enumerate(val_loader):
195 | if args.cuda:
196 | images = Variable(images.cuda())
197 | targets = [Variable(ann.cuda(), volatile=True)
198 | for ann in targets]
199 | else:
200 | images = Variable(images)
201 | targets = [Variable(ann, volatile=True) for ann in targets]
202 |
203 | out = net(images)
204 | loss_l, loss_c = criterion(out, targets)
205 | loss = loss_l + loss_c
206 | loc_loss += loss_l.data[0]
207 | conf_loss += loss_c.data[0]
208 | step += 1
209 |
210 | tloss = (loc_loss + conf_loss) / step
211 | t2 = time.time()
212 | print('Timer: %.4f' % (t2 - t1))
213 | print('test epoch:' + repr(epoch) + ' || Loss:%.4f' % (tloss))
214 |
215 | global min_loss
216 | if tloss < min_loss:
217 | print('Saving best state,epoch', epoch)
218 | file = 'sfd_{}.pth'.format(args.dataset)
219 | torch.save(s3fd_net.state_dict(), os.path.join(
220 | args.save_folder, file))
221 | min_loss = tloss
222 |
223 | states = {
224 | 'epoch': epoch,
225 | 'weight': s3fd_net.state_dict(),
226 | }
227 | file = 'sfd_{}_checkpoint.pth'.format(args.dataset)
228 | torch.save(states, os.path.join(
229 | args.save_folder, file))
230 |
231 |
232 | def adjust_learning_rate(optimizer, gamma, step):
233 | """Sets the learning rate to the initial LR decayed by 10 at every
234 | specified step
235 | # Adapted from PyTorch Imagenet example:
236 | # https://github.com/pytorch/examples/blob/master/imagenet/main.py
237 | """
238 | lr = args.lr * (gamma ** (step))
239 | for param_group in optimizer.param_groups:
240 | param_group['lr'] = lr
241 |
242 |
243 | if __name__ == '__main__':
244 | train()
245 |
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------