├── .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 |
53 | afw 54 | pascal 55 | fddb 56 |
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 | afw 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 | --------------------------------------------------------------------------------