├── .gitignore ├── .gitmodules ├── LICENSE ├── NOTE.md ├── README.md ├── cnn_get_batch_hardmine.m ├── cnn_init.m ├── cnn_load_pretrain.m ├── cnn_setup_imdb.m ├── cnn_train_dag_hardmine.m ├── cnn_widerface.m ├── cnn_widerface_eval.m ├── cnn_widerface_test_AB.m ├── data ├── demo │ └── selfie.jpg └── widerface │ ├── RefBox_N25.mat │ ├── RefBox_N25_scaled.mat │ ├── imageStats.mat │ └── imdb.mat ├── 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 │ │ │ │ ├── HR │ │ │ │ ├── wider_pr_info_HR_easy.mat │ │ │ │ ├── wider_pr_info_HR_hard.mat │ │ │ │ └── wider_pr_info_HR_medium.mat │ │ │ │ ├── LDCF+ │ │ │ │ ├── wider_pr_info_LDCF+_easy.mat │ │ │ │ ├── wider_pr_info_LDCF+_hard.mat │ │ │ │ └── wider_pr_info_LDCF+_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 │ │ │ ├── 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 │ │ │ ├── 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 │ │ │ ├── hr_res101 │ │ │ ├── wider_pr_info_hr_res101_easy_val.mat │ │ │ ├── wider_pr_info_hr_res101_hard_val.mat │ │ │ └── wider_pr_info_hr_res101_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 │ │ │ └── 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 │ ├── plot_pr.m │ ├── saveTightFigure.m │ └── wider_plot.m └── read_pred.m ├── init └── cnn_add_loss_fcn8s_resnet101_simple.m ├── scripts └── hr_res101.m ├── selfie.png ├── startup.m ├── tiny_face_detector.m ├── toolbox ├── Shuffle.c ├── Shuffle.m ├── Shuffle.mexa64 ├── VOCap.m ├── VOClabelcolormap.m ├── bilinear_u.m ├── enhanced_rdir.m ├── factorize.m ├── intersections.m ├── license.txt ├── nms │ ├── nms.m │ ├── nms_gpu_mex.cu │ ├── nms_gpu_mex.mexa64 │ ├── nms_gpu_mex.o │ ├── nms_mex.cpp │ ├── nms_mex.mexa64 │ ├── nms_multiclass.m │ ├── nms_multiclass_mex.cpp │ └── nvmex.m ├── nms_matlab.m ├── plotEllipses.m ├── plotLandmarks.m ├── rdir.m ├── saveTightFigure.m ├── subtightplot.m └── unpackColumns.m └── utils ├── cluster_rects.m ├── compile_mex.m ├── compute_dense_overlap.cc ├── measure_runtime.m ├── plotBoxes.m ├── rect_dist.m ├── test_compute_dense_overlap.m ├── test_data.mat ├── tile3DHeat.m └── visualize_detection.m /.gitignore: -------------------------------------------------------------------------------- 1 | data/widerface/WIDER_test 2 | data/widerface/WIDER_train 3 | data/widerface/WIDER_val 4 | results/ 5 | archive/ 6 | models/ 7 | demo/ 8 | trained_models/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "matconvnet"] 2 | path = matconvnet 3 | url = https://github.com/peiyunh/matconvnet.git 4 | [submodule "toolbox/export_fig"] 5 | path = toolbox/export_fig 6 | url = https://github.com/altmany/export_fig.git 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | TINY FACE DETECTOR 2 | SOFTWARE LICENSE AGREEMENT 3 | ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY 4 | 5 | BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR DOWNLOAD THE SOFTWARE. 6 | 7 | This is a license agreement ("Agreement") between your academic institution or non-profit organization or self (called "Licensee" or "You" in this Agreement) and Carnegie Mellon University (called "Licensor" in this Agreement). All rights not specifically granted to you in this Agreement are reserved for Licensor. 8 | 9 | RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: 10 | Licensor retains exclusive ownership of any copy of the Software (as defined below) licensed under this Agreement and hereby grants to Licensee a personal, non-exclusive, 11 | non-transferable license to use the Software for noncommercial research purposes, without the right to sublicense, pursuant to the terms and conditions of this Agreement. As used in this Agreement, the term "Software" means (i) the actual copy of all or any portion of code for program routines made accessible to Licensee by Licensor pursuant to this Agreement, inclusive of backups, updates, and/or merged copies permitted hereunder or subsequently supplied by Licensor, including all or any file structures, programming instructions, user interfaces and screen formats and sequences as well as any and all documentation and instructions related to it, and (ii) all or any derivatives and/or modifications created or made by You to any of the items specified in (i). 12 | 13 | CONFIDENTIALITY: Licensee acknowledges that the Software is proprietary to Licensor, and as such, Licensee agrees to receive all such materials in confidence and use the Software only in accordance with the terms of this Agreement. Licensee agrees to use reasonable effort to protect the Software from unauthorized use, reproduction, distribution, or publication. 14 | 15 | COPYRIGHT: The Software is owned by Licensor and is protected by United 16 | States copyright laws and applicable international treaties and/or conventions. 17 | 18 | PERMITTED USES: The Software may be used for your own noncommercial internal research purposes. You understand and agree that Licensor is not obligated to implement any suggestions and/or feedback you might provide regarding the Software, but to the extent Licensor does so, you are not entitled to any compensation related thereto. 19 | 20 | DERIVATIVES: You may create derivatives of or make modifications to the Software, however, You agree that all and any such derivatives and modifications will be owned by Licensor and become a part of the Software licensed to You under this Agreement. You may only use such derivatives and modifications for your own noncommercial internal research purposes, and you may not otherwise use, distribute or copy such derivatives and modifications in violation of this Agreement. 21 | 22 | BACKUPS: If Licensee is an organization, it may make that number of copies of the Software necessary for internal noncommercial use at a single site within its organization provided that all information appearing in or on the original labels, including the copyright and trademark notices are copied onto the labels of the copies. 23 | 24 | USES NOT PERMITTED: You may not distribute, copy or use the Software except as explicitly permitted herein. Licensee has not been granted any trademark license as part of this Agreement and may not use the name or mark “Tiny Face Detector", "Carnegie Mellon" or any renditions thereof without the prior written permission of Licensor. 25 | 26 | You may not sell, rent, lease, sublicense, lend, time-share or transfer, in whole or in part, or provide third parties access to prior or present versions (or any parts thereof) of the Software. 27 | 28 | ASSIGNMENT: You may not assign this Agreement or your rights hereunder without the prior written consent of Licensor. Any attempted assignment without such consent shall be null and void. 29 | 30 | TERM: The term of the license granted by this Agreement is from Licensee's acceptance of this Agreement by downloading the Software or by using the Software until terminated as provided below. 31 | 32 | The Agreement automatically terminates without notice if you fail to comply with any provision of this Agreement. Licensee may terminate this Agreement by ceasing using the Software. Upon any termination of this Agreement, Licensee will delete any and all copies of the Software. You agree that all provisions which operate to protect the proprietary rights of Licensor shall remain in force should breach occur and that the obligation of confidentiality described in this Agreement is binding in perpetuity and, as such, survives the term of the Agreement. 33 | 34 | FEE: Provided Licensee abides completely by the terms and conditions of this Agreement, there is no fee due to Licensor for Licensee's use of the Software in accordance with this Agreement. 35 | 36 | DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON-INFRINGEMENT. LICENSEE BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND RELATED MATERIALS. 37 | 38 | SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is provided as part of this Agreement. 39 | 40 | EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent permitted under applicable law, Licensor shall not be liable for direct, indirect, special, incidental, or consequential damages or lost profits related to Licensee's use of and/or inability to use the Software, even if Licensor is advised of the possibility of such damage. 41 | 42 | EXPORT REGULATION: Licensee agrees to comply with any and all applicable 43 | U.S. export control laws, regulations, and/or other laws related to embargoes and sanction programs administered by the Office of Foreign Assets Control. 44 | 45 | SEVERABILITY: If any provision(s) of this Agreement shall be held to be invalid, illegal, or unenforceable by a court or other tribunal of competent jurisdiction, the validity, legality and enforceability of the remaining provisions shall not in any way be affected or impaired thereby. 46 | 47 | NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right or remedy under this Agreement shall be construed as a waiver of any future or other exercise of such right or remedy by Licensor. 48 | 49 | GOVERNING LAW: This Agreement shall be construed and enforced in accordance with the laws of the Commonwealth of Pennsylvania without reference to conflict of laws principles. You consent to the personal jurisdiction of the courts of this County and waive their rights to venue outside of Allegheny County, Pennsylvania. 50 | 51 | ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and entire agreement between Licensee and Licensor as to the matter set forth herein and supersedes any previous agreements, understandings, and arrangements between the parties relating hereto. 52 | 53 | 54 | 55 | ************************************************************************ 56 | 57 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 58 | 59 | This project incorporates material from the project(s) listed below (collectively, "Third Party Code"). This Third Party Code is licensed to you under their original license terms set forth below. We reserves all other rights not expressly granted, whether by implication, estoppel or otherwise. 60 | 61 | 1. MatConvNet, version beta 22, (https://github.com/vlfeat/matconvnet) 62 | 63 | Copyright (c) 2014-16 The MatConvNet Team. 64 | All rights reserved. 65 | 66 | Redistribution and use in source and binary forms are permitted 67 | provided that the above copyright notice and this paragraph are 68 | duplicated in all such forms and that any documentation, advertising 69 | materials, and other materials related to such distribution and use 70 | acknowledge that the software was developed by the MatConvNet 71 | Team. The name of the MatConvNet Team may not be used to endorse or 72 | promote products derived from this software without specific prior 73 | written permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 74 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE 75 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 76 | PURPOSE. 77 | 78 | ************END OF THIRD-PARTY SOFTWARE NOTICES AND INFORMATION********** 79 | -------------------------------------------------------------------------------- /NOTE.md: -------------------------------------------------------------------------------- 1 | To make sure users do not get distracted by the name of code files, I have 2 | renamed some files to simpler forms. This is a file to keep track of name 3 | changes. 4 | 5 | 6 | - `scripts/hybrid_trires_limit30_hardmine_res101_normalscale_restdouble.m` <- `scripts/hr_res101.m` 7 | 8 | - `cluster_rects.m` <- `cluster_rects_noresz.m`. 9 | 10 | - `cnn_get_batch_hardmine.m` <- `cnn_get_batch_logistic_trires_limit30_hardmine_negborder.m`. 11 | 12 | - `cnn_widerface_test_AB.m` <- `cnn_widerface_test_with_zoom_AB_negborder.m`. 13 | 14 | - `data/widerface/RefBox_N25_scaled.mat` <- `data/widerface/RefBox_NoResize_N25_scaled.mat`. 15 | - `data/widerface/RefBox_N25.mat` <- 'data/widerface/RefBox_NoResize_N25_min10x10_maxInfxInf.mat` 16 | 17 | - `cnn_widerface_eval.m` <- `cnn_widerface_eval_new.m` 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Demo result](https://raw.githubusercontent.com/peiyunh/tiny/master/selfie.png) 2 | 3 | # Finding Tiny Faces 4 | By Peiyun Hu and Deva Ramanan at Carnegie Mellon University. 5 | 6 | ## Introduction 7 | We develop a face detector (Tiny Face Detector) that can find ~800 faces out of ~1000 reportedly present, by making use of novel characterization of scale, resolution, and context to find small objects. Can you confidently identify errors? 8 | 9 | Tiny Face Detector was initially described in an [arXiv tech report](https://arxiv.org/abs/1612.04402). 10 | 11 | In this repo, we provide a MATLAB implementation of Tiny face detector, including both training and testing code. A demo script is also provided. 12 | 13 | ### Citing us 14 | If you find our work useful in your research, please consider citing: 15 | ```latex 16 | @InProceedings{Hu_2017_CVPR, 17 | author = {Hu, Peiyun and Ramanan, Deva}, 18 | title = {Finding Tiny Faces}, 19 | booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 20 | month = {July}, 21 | year = {2017} 22 | } 23 | ``` 24 | 25 | ## Installation 26 | Clone the repo recursively so you have [my fork of MatConvNet](https://github.com/peiyunh/matconvnet/tree/9822ec97f35cf5a56ae22707cc1c04e0d738e7db). 27 | ```zsh 28 | git clone --recursive git@github.com:peiyunh/tiny.git 29 | ``` 30 | 31 | Compile MatConvNet by running following commands in MATLAB (see [Installing - MatConvNet](http://www.vlfeat.org/matconvnet/install/) for more details): 32 | ```Matlab 33 | >> cd matconvnet/; 34 | >> addpath matlab/; 35 | >> vl_compilenn('enableImreadJpeg', true, 'enableGpu', true, 'cudaRoot', [cuda_dir],... 36 | 'cudaMethod', 'nvcc', 'enableCudnn', true, 'cudnnRoot', [cudnn_dir]); 37 | >> vl_testnn('gpu', true); % vl_testnn('gpu', false) for cpu-only 38 | ``` 39 | 40 | Compile our MEX function in MATLAB and test if it works as expected: 41 | ```Matlab 42 | >> cd utils/; 43 | >> compile_mex; 44 | >> test_compute_dense_overlap; 45 | ``` 46 | 47 | 48 | Download [WIDER FACE](http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/) and unzip data and annotation files to `data/widerface` such that: 49 | ```zsh 50 | $ ls data/widerface 51 | wider_face_test.mat wider_face_train.mat wider_face_val.mat 52 | WIDER_test/ WIDER_train/ WIDER_val/ 53 | ``` 54 | 55 | ## Demo 56 | We provide a minimal demo `tiny_face_detector.m` that runs our detector on an single input image and output face detections: 57 | ```Matlab 58 | function bboxes = tiny_face_detector(image_path, output_path, prob_thresh, nms_thresh, gpu_id) 59 | ``` 60 | 61 | Here is a command you can run to reproduce our detection results on the world's largest selfie: 62 | ```Matlab 63 | >> bboxes = tiny_face_detector('data/demo/selfie.jpg', './selfie.png', 0.5, 0.1, 1) 64 | ``` 65 | 66 | The demo script will start by downloading an off-the-shelf ResNet101-based model, if it does not find one. Models based on other architecture are also available below: 67 | - [ResNet101](https://drive.google.com/file/d/1YO8zTXGCACRZvHDxtW8dEZL7CE8HVFJ8/view?usp=sharing) 68 | - [ResNet50](https://drive.google.com/file/d/1RFcSglvtasctXJQI1BS3laENXNvP8mwl/view?usp=sharing) 69 | - [VGG16](https://drive.google.com/file/d/1cOm-AiZFulruQpb9gRmFlRhsdL9bXJZZ/view?usp=sharing) 70 | 71 | ## Training 72 | To train a ResNet101-based Tiny Face Detector, run following command in MATLAB: 73 | ```Matlab 74 | >> hr_res101('train'); % which calls cnn_widerface.m 75 | ``` 76 | 77 | After training, run the following command to test on the validation set: 78 | ```Matlab 79 | >> hr_res101('test'); % which calls cnn_widerface_test_AB.m 80 | ``` 81 | 82 | Finally, run the following command to evaluate the trained models: 83 | ```Matlab 84 | >> hr_res101('eval'); % which calls cnn_widerface_eval.m 85 | ``` 86 | 87 | Please refer to `scripts/hr_res101.m` for more details on how training/testing/evaluation is configured. 88 | 89 | ### Clustering 90 | We derive canonical bounding box shapes by K-medoids clustering (`cluster_rects.m`). For reproducibility, we provide our clustering results in `data/widerface/RefBox_N25.mat`. We also provide the version after template resolution analysis in `data/widerface/RefBox_N25_scaled.mat` (Fig. 8 in our paper). 91 | 92 | ### Evaluation 93 | We provide both our own version of evaluation script (`cnn_widerface_eval.m`) and official evaluation script (`eval_tools/`). Our implementation runs much faster and is easier to customize. However, our version produces slightly lower numbers comparing to the official one. We use our evaluation script only for prototyping. All numbers in the paper are based on the official evaluation script. 94 | 95 | ## FAQ 96 | 97 | ### How do I train it on my own datasets? 98 | Training a `tiny-X-detector` on your own dataset takes just a little bit of coding and it is certainly doable. I would suggest start from the script named `cnn_setup_imdb.m`. The script produces a `imdb.mat` file which contains information about the path of images and the ground truth bounding boxes. Try modifying `cnn_setup_imdb.m` to make sure such information of your dataset goes into `imdb.mat`. 99 | 100 | ## Third-party re-implementations 101 | - PyTorch version by Varun Agarwal (@varunagrawal) at https://github.com/varunagrawal/tiny-faces-pytorch 102 | -------------------------------------------------------------------------------- /cnn_init.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_init.m 2 | % 3 | % This function initializes a well-known conv-net from scratch. 4 | % 5 | % INPUT: See below 6 | % 7 | % OUTPUT: net (initialized network) 8 | 9 | function net = cnn_init(varargin) 10 | 11 | opts.scale = 1 ; 12 | opts.initBias = 0.1 ; 13 | opts.weightDecay = 1 ; 14 | %opts.weightInitMethod = 'xavierimproved' ; 15 | opts.weightInitMethod = 'gaussian' ; 16 | opts.model = 'alexnet' ; 17 | opts.batchNormalization = false ; 18 | opts.networkType = 'simplenn' ; 19 | opts.cudnnWorkspaceLimit = 1024*1024*1204 ; % 1GB 20 | opts = vl_argparse(opts, varargin) ; 21 | 22 | % Define layers 23 | switch opts.model 24 | case 'alexnet' 25 | net.meta.normalization.imageSize = [227, 227, 3] ; 26 | net = alexnet(net, opts) ; 27 | bs = 256 ; 28 | case 'vgg-f' 29 | net.meta.normalization.imageSize = [224, 224, 3] ; 30 | net = vgg_f(net, opts) ; 31 | bs = 256 ; 32 | case 'vgg-m' 33 | net.meta.normalization.imageSize = [224, 224, 3] ; 34 | net = vgg_m(net, opts) ; 35 | bs = 196 ; 36 | case 'vgg-s' 37 | net.meta.normalization.imageSize = [224, 224, 3] ; 38 | net = vgg_s(net, opts) ; 39 | bs = 128 ; 40 | case 'vgg-vd-16' 41 | net.meta.normalization.imageSize = [224, 224, 3] ; 42 | net = vgg_vd(net, opts) ; 43 | bs = 32 ; 44 | case 'vgg-vd-19' 45 | net.meta.normalization.imageSize = [224, 224, 3] ; 46 | net = vgg_vd(net, opts) ; 47 | bs = 24 ; 48 | otherwise 49 | fprintf('Unknown model: cannot initialize.\n'); 50 | net = []; 51 | return; 52 | end 53 | 54 | % final touches 55 | switch lower(opts.weightInitMethod) 56 | case {'xavier', 'xavierimproved'} 57 | net.layers{end}.weights{1} = net.layers{end}.weights{1} / 10 ; 58 | end 59 | net.layers{end+1} = struct('type', 'softmaxloss', 'name', 'loss') ; 60 | 61 | % Meta parameters 62 | net.meta.inputSize = net.meta.normalization.imageSize ; 63 | net.meta.normalization.border = 256 - net.meta.normalization.imageSize(1:2) ; 64 | net.meta.normalization.interpolation = 'bicubic' ; 65 | net.meta.normalization.averageImage = [] ; 66 | net.meta.normalization.keepAspect = true ; 67 | net.meta.augmentation.rgbVariance = zeros(0,3) ; 68 | net.meta.augmentation.transformation = 'stretch' ; 69 | 70 | if ~opts.batchNormalization 71 | lr = logspace(-2, -4, 60) ; 72 | else 73 | lr = logspace(-1, -4, 20) ; 74 | end 75 | 76 | net.meta.trainOpts.learningRate = lr ; 77 | net.meta.trainOpts.numEpochs = numel(lr) ; 78 | net.meta.trainOpts.batchSize = bs ; 79 | net.meta.trainOpts.weightDecay = 0.0005 ; 80 | 81 | % Fill in default values 82 | net = vl_simplenn_tidy(net) ; 83 | 84 | % Switch to DagNN if requested 85 | switch lower(opts.networkType) 86 | case 'simplenn' 87 | % done 88 | case 'dagnn' 89 | net = dagnn.DagNN.fromSimpleNN(net, 'canonicalNames', true) ; 90 | net.addLayer('top1err', dagnn.Loss('loss', 'classerror'), ... 91 | {'prediction','label'}, 'top1err') ; 92 | net.addLayer('top5err', dagnn.Loss('loss', 'topkerror', ... 93 | 'opts', {'topK',5}), ... 94 | {'prediction','label'}, 'top5err') ; 95 | otherwise 96 | assert(false) ; 97 | end 98 | 99 | % -------------------------------------------------------------------- 100 | function net = add_block(net, opts, id, h, w, in, out, stride, pad, init_bias) 101 | % -------------------------------------------------------------------- 102 | info = vl_simplenn_display(net) ; 103 | fc = (h == info.dataSize(1,end) && w == info.dataSize(2,end)) ; 104 | if fc 105 | name = 'fc' ; 106 | else 107 | name = 'conv' ; 108 | end 109 | convOpts = {'CudnnWorkspaceLimit', opts.cudnnWorkspaceLimit} ; 110 | net.layers{end+1} = struct('type', 'conv', 'name', sprintf('%s%s', name, id), ... 111 | 'weights', {{init_weight(opts, h, w, in, out, 'single'), zeros(out, 1, 'single')}}, ... 112 | 'stride', stride, ... 113 | 'pad', pad, ... 114 | 'learningRate', [1 2], ... 115 | 'weightDecay', [opts.weightDecay 0], ... 116 | 'opts', {convOpts}) ; 117 | if opts.batchNormalization 118 | net.layers{end+1} = struct('type', 'bnorm', 'name', sprintf('bn%s',id), ... 119 | 'weights', {{ones(out, 1, 'single'), zeros(out, 1, 'single'), zeros(out, 2, 'single')}}, ... 120 | 'learningRate', [2 1 0.05], ... 121 | 'weightDecay', [0 0]) ; 122 | end 123 | net.layers{end+1} = struct('type', 'relu', 'name', sprintf('relu%s',id)) ; 124 | 125 | % ------------------------------------------------------------------------- 126 | function weights = init_weight(opts, h, w, in, out, type) 127 | % ------------------------------------------------------------------------- 128 | % See K. He, X. Zhang, S. Ren, and J. Sun. Delving deep into 129 | % rectifiers: Surpassing human-level performance on imagenet 130 | % classification. CoRR, (arXiv:1502.01852v1), 2015. 131 | 132 | switch lower(opts.weightInitMethod) 133 | case 'gaussian' 134 | sc = 0.01/opts.scale ; 135 | weights = randn(h, w, in, out, type)*sc; 136 | case 'xavier' 137 | sc = sqrt(3/(h*w*in)) ; 138 | weights = (rand(h, w, in, out, type)*2 - 1)*sc ; 139 | case 'xavierimproved' 140 | sc = sqrt(2/(h*w*out)) ; 141 | weights = randn(h, w, in, out, type)*sc ; 142 | otherwise 143 | error('Unknown weight initialization method''%s''', opts.weightInitMethod) ; 144 | end 145 | 146 | % -------------------------------------------------------------------- 147 | function net = add_norm(net, opts, id) 148 | % -------------------------------------------------------------------- 149 | if ~opts.batchNormalization 150 | net.layers{end+1} = struct('type', 'normalize', ... 151 | 'name', sprintf('norm%s', id), ... 152 | 'param', [5 1 0.0001/5 0.75]) ; 153 | end 154 | 155 | % -------------------------------------------------------------------- 156 | function net = add_dropout(net, opts, id) 157 | % -------------------------------------------------------------------- 158 | if ~opts.batchNormalization 159 | net.layers{end+1} = struct('type', 'dropout', ... 160 | 'name', sprintf('dropout%s', id), ... 161 | 'rate', 0.5) ; 162 | end 163 | 164 | 165 | % -------------------------------------------------------------------- 166 | function net = alexnet(net, opts) 167 | % -------------------------------------------------------------------- 168 | 169 | net.layers = {} ; 170 | 171 | net = add_block(net, opts, '1', 11, 11, 3, 96, 4, 0) ; 172 | net = add_norm(net, opts, '1') ; 173 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool1', ... 174 | 'method', 'max', ... 175 | 'pool', [3 3], ... 176 | 'stride', 2, ... 177 | 'pad', 0) ; 178 | 179 | 180 | net = add_block(net, opts, '2', 5, 5, 48, 256, 1, 2) ; 181 | net = add_norm(net, opts, '2') ; 182 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool2', ... 183 | 'method', 'max', ... 184 | 'pool', [3 3], ... 185 | 'stride', 2, ... 186 | 'pad', 0) ; 187 | 188 | 189 | net = add_block(net, opts, '3', 3, 3, 256, 384, 1, 1) ; 190 | net = add_block(net, opts, '4', 3, 3, 192, 384, 1, 1) ; 191 | net = add_block(net, opts, '5', 3, 3, 192, 256, 1, 1) ; 192 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool5', ... 193 | 'method', 'max', ... 194 | 'pool', [3 3], ... 195 | 'stride', 2, ... 196 | 'pad', 0) ; 197 | 198 | net = add_block(net, opts, '6', 6, 6, 256, 4096, 1, 0) ; 199 | net = add_dropout(net, opts, '6') ; 200 | 201 | net = add_block(net, opts, '7', 1, 1, 4096, 4096, 1, 0) ; 202 | net = add_dropout(net, opts, '7') ; 203 | 204 | net = add_block(net, opts, '8', 1, 1, 4096, 1000, 1, 0) ; 205 | net.layers(end) = [] ; 206 | if opts.batchNormalization, net.layers(end) = [] ; end 207 | 208 | % -------------------------------------------------------------------- 209 | function net = vgg_s(net, opts) 210 | % -------------------------------------------------------------------- 211 | 212 | net.layers = {} ; 213 | net = add_block(net, opts, '1', 7, 7, 3, 96, 2, 0) ; 214 | net = add_norm(net, opts, '1') ; 215 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool1', ... 216 | 'method', 'max', ... 217 | 'pool', [3 3], ... 218 | 'stride', 3, ... 219 | 'pad', [0 2 0 2]) ; 220 | 221 | net = add_block(net, opts, '2', 5, 5, 96, 256, 1, 0) ; 222 | net = add_norm(net, opts, '2') ; 223 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool2', ... 224 | 'method', 'max', ... 225 | 'pool', [2 2], ... 226 | 'stride', 2, ... 227 | 'pad', [0 1 0 1]) ; 228 | 229 | net = add_block(net, opts, '3', 3, 3, 256, 512, 1, 1) ; 230 | net = add_block(net, opts, '4', 3, 3, 512, 512, 1, 1) ; 231 | net = add_block(net, opts, '5', 3, 3, 512, 512, 1, 1) ; 232 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool5', ... 233 | 'method', 'max', ... 234 | 'pool', [3 3], ... 235 | 'stride', 3, ... 236 | 'pad', [0 1 0 1]) ; 237 | 238 | net = add_block(net, opts, '6', 6, 6, 512, 4096, 1, 0) ; 239 | net = add_dropout(net, opts, '6') ; 240 | 241 | net = add_block(net, opts, '7', 1, 1, 4096, 4096, 1, 0) ; 242 | net = add_dropout(net, opts, '7') ; 243 | 244 | net = add_block(net, opts, '8', 1, 1, 4096, 1000, 1, 0) ; 245 | net.layers(end) = [] ; 246 | if opts.batchNormalization, net.layers(end) = [] ; end 247 | 248 | % -------------------------------------------------------------------- 249 | function net = vgg_m(net, opts) 250 | % -------------------------------------------------------------------- 251 | 252 | net.layers = {} ; 253 | net = add_block(net, opts, '1', 7, 7, 3, 96, 2, 0) ; 254 | net = add_norm(net, opts, '1') ; 255 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool1', ... 256 | 'method', 'max', ... 257 | 'pool', [3 3], ... 258 | 'stride', 2, ... 259 | 'pad', 0) ; 260 | 261 | net = add_block(net, opts, '2', 5, 5, 96, 256, 2, 1) ; 262 | net = add_norm(net, opts, '2') ; 263 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool2', ... 264 | 'method', 'max', ... 265 | 'pool', [3 3], ... 266 | 'stride', 2, ... 267 | 'pad', [0 1 0 1]) ; 268 | 269 | net = add_block(net, opts, '3', 3, 3, 256, 512, 1, 1) ; 270 | net = add_block(net, opts, '4', 3, 3, 512, 512, 1, 1) ; 271 | net = add_block(net, opts, '5', 3, 3, 512, 512, 1, 1) ; 272 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool5', ... 273 | 'method', 'max', ... 274 | 'pool', [3 3], ... 275 | 'stride', 2, ... 276 | 'pad', 0) ; 277 | 278 | net = add_block(net, opts, '6', 6, 6, 512, 4096, 1, 0) ; 279 | net = add_dropout(net, opts, '6') ; 280 | 281 | net = add_block(net, opts, '7', 1, 1, 4096, 4096, 1, 0) ; 282 | net = add_dropout(net, opts, '7') ; 283 | 284 | net = add_block(net, opts, '8', 1, 1, 4096, 1000, 1, 0) ; 285 | net.layers(end) = [] ; 286 | if opts.batchNormalization, net.layers(end) = [] ; end 287 | 288 | % -------------------------------------------------------------------- 289 | function net = vgg_f(net, opts) 290 | % -------------------------------------------------------------------- 291 | 292 | net.layers = {} ; 293 | net = add_block(net, opts, '1', 11, 11, 3, 64, 4, 0) ; 294 | net = add_norm(net, opts, '1') ; 295 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool1', ... 296 | 'method', 'max', ... 297 | 'pool', [3 3], ... 298 | 'stride', 2, ... 299 | 'pad', [0 1 0 1]) ; 300 | 301 | net = add_block(net, opts, '2', 5, 5, 64, 256, 1, 2) ; 302 | net = add_norm(net, opts, '2') ; 303 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool2', ... 304 | 'method', 'max', ... 305 | 'pool', [3 3], ... 306 | 'stride', 2, ... 307 | 'pad', 0) ; 308 | 309 | net = add_block(net, opts, '3', 3, 3, 256, 256, 1, 1) ; 310 | net = add_block(net, opts, '4', 3, 3, 256, 256, 1, 1) ; 311 | net = add_block(net, opts, '5', 3, 3, 256, 256, 1, 1) ; 312 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool5', ... 313 | 'method', 'max', ... 314 | 'pool', [3 3], ... 315 | 'stride', 2, ... 316 | 'pad', 0) ; 317 | 318 | net = add_block(net, opts, '6', 6, 6, 256, 4096, 1, 0) ; 319 | net = add_dropout(net, opts, '6') ; 320 | 321 | net = add_block(net, opts, '7', 1, 1, 4096, 4096, 1, 0) ; 322 | net = add_dropout(net, opts, '7') ; 323 | 324 | net = add_block(net, opts, '8', 1, 1, 4096, 1000, 1, 0) ; 325 | net.layers(end) = [] ; 326 | if opts.batchNormalization, net.layers(end) = [] ; end 327 | 328 | % -------------------------------------------------------------------- 329 | function net = vgg_vd(net, opts) 330 | % -------------------------------------------------------------------- 331 | 332 | net.layers = {} ; 333 | net = add_block(net, opts, '1_1', 3, 3, 3, 64, 1, 1) ; 334 | net = add_block(net, opts, '1_2', 3, 3, 64, 64, 1, 1) ; 335 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool1', ... 336 | 'method', 'max', ... 337 | 'pool', [2 2], ... 338 | 'stride', 2, ... 339 | 'pad', 0) ; 340 | 341 | net = add_block(net, opts, '2_1', 3, 3, 64, 128, 1, 1) ; 342 | net = add_block(net, opts, '2_2', 3, 3, 128, 128, 1, 1) ; 343 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool2', ... 344 | 'method', 'max', ... 345 | 'pool', [2 2], ... 346 | 'stride', 2, ... 347 | 'pad', 0) ; 348 | 349 | net = add_block(net, opts, '3_1', 3, 3, 128, 256, 1, 1) ; 350 | net = add_block(net, opts, '3_2', 3, 3, 256, 256, 1, 1) ; 351 | net = add_block(net, opts, '3_3', 3, 3, 256, 256, 1, 1) ; 352 | if strcmp(opts.model, 'vgg-vd-19') 353 | net = add_block(net, opts, '3_4', 3, 3, 256, 256, 1, 1) ; 354 | end 355 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool3', ... 356 | 'method', 'max', ... 357 | 'pool', [2 2], ... 358 | 'stride', 2, ... 359 | 'pad', 0) ; 360 | 361 | net = add_block(net, opts, '4_1', 3, 3, 256, 512, 1, 1) ; 362 | net = add_block(net, opts, '4_2', 3, 3, 512, 512, 1, 1) ; 363 | net = add_block(net, opts, '4_3', 3, 3, 512, 512, 1, 1) ; 364 | if strcmp(opts.model, 'vgg-vd-19') 365 | net = add_block(net, opts, '4_4', 3, 3, 512, 512, 1, 1) ; 366 | end 367 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool4', ... 368 | 'method', 'max', ... 369 | 'pool', [2 2], ... 370 | 'stride', 2, ... 371 | 'pad', 0) ; 372 | 373 | net = add_block(net, opts, '5_1', 3, 3, 512, 512, 1, 1) ; 374 | net = add_block(net, opts, '5_2', 3, 3, 512, 512, 1, 1) ; 375 | net = add_block(net, opts, '5_3', 3, 3, 512, 512, 1, 1) ; 376 | if strcmp(opts.model, 'vgg-vd-19') 377 | net = add_block(net, opts, '5_4', 3, 3, 512, 512, 1, 1) ; 378 | end 379 | net.layers{end+1} = struct('type', 'pool', 'name', 'pool5', ... 380 | 'method', 'max', ... 381 | 'pool', [2 2], ... 382 | 'stride', 2, ... 383 | 'pad', 0) ; 384 | 385 | net = add_block(net, opts, '6', 7, 7, 512, 4096, 1, 0) ; 386 | net = add_dropout(net, opts, '6') ; 387 | 388 | net = add_block(net, opts, '7', 1, 1, 4096, 4096, 1, 0) ; 389 | net = add_dropout(net, opts, '7') ; 390 | 391 | net = add_block(net, opts, '8', 1, 1, 4096, 1000, 1, 0) ; 392 | net.layers(end) = [] ; 393 | if opts.batchNormalization, net.layers(end) = [] ; end 394 | -------------------------------------------------------------------------------- /cnn_load_pretrain.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_load_pretrain.m 2 | % 3 | % This function takes an input network and fill its parameter weights based 4 | % on a pretrained network. Parameters are matched based on names. If target 5 | % network is empty, then use the structure of pretrained network. It happens 6 | % when cnn_init.m fails to initialize the model structure. 7 | % 8 | % INPUT: net (target network) 9 | % prepath (path to a network with pretrained weights) 10 | % 11 | % OUTPUT: net (target network with pretrained weights) 12 | 13 | 14 | function net = cnn_load_pretrain(net, prepath) 15 | 16 | % convert pretrained network to DagNN (easy indexing) 17 | prenet_ = load(prepath); 18 | if isfield(prenet_, 'net') 19 | prenet_ = prenet_.net; 20 | end 21 | 22 | if isfield(prenet_, 'params') 23 | prenet = dagnn.DagNN.loadobj(prenet_); 24 | else 25 | prenet = dagnn.DagNN.fromSimpleNN(prenet_); 26 | end 27 | 28 | clear prenet_; 29 | 30 | % same canonical param name 31 | if isempty(net) 32 | net = prenet; 33 | else 34 | for i = 1:numel(net.params) 35 | idx = prenet.getParamIndex(net.params(i).name); 36 | if ~isnan(idx) 37 | net.params(i).value = prenet.params(idx).value; 38 | end 39 | end 40 | end 41 | 42 | if isempty(net.getLayerIndex('drop6')) 43 | net.addLayer('drop6', dagnn.DropOut('rate', 0.5), 'fc6x', 'fc6xd'); 44 | net.setLayerInputs('fc7', {'fc6xd'}); 45 | end 46 | 47 | if isempty(net.getLayerIndex('drop7')) 48 | net.addLayer('drop7', dagnn.DropOut('rate', 0.5), 'fc7x', 'fc7xd'); 49 | net.setLayerInputs('score_fr', {'fc7xd'}); 50 | end 51 | 52 | % remove average image 53 | net.meta.normalization.averageImage = []; 54 | 55 | % NOTE Reshape multipliers and biases in BN to be vectors instead of 56 | % 1x1xK matrices. Otherwise, there will be errors in cnn_train_dag.m 57 | for i = 1:numel(net.layers) 58 | if isa(net.layers(i).block, 'dagnn.BatchNorm') 59 | midx = net.getParamIndex(net.layers(i).params{1}); % multiplier 60 | bidx = net.getParamIndex(net.layers(i).params{2}); % bias 61 | % vectorize 62 | net.params(midx).value = net.params(midx).value(:); 63 | net.params(bidx).value = net.params(bidx).value(:); 64 | end 65 | end -------------------------------------------------------------------------------- /cnn_setup_imdb.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_setup_imdb.m 2 | % 3 | % This function reads WIDER FACE dataset and generates a MATLAB struct 4 | % variable that is more friendly and eaiser to work with. 5 | % 6 | % INPUT: 7 | % 8 | % OUTPUT: imdb (a more user-friendly struct variable for the dataset) 9 | 10 | function imdb = cnn_setup_imdb(varargin) 11 | 12 | opts.dataDir = fullfile('data','widerface') ; 13 | opts = vl_argparse(opts, varargin) ; 14 | 15 | % construct imdb 16 | imdb = struct(); 17 | imdb.imageDir = opts.dataDir; 18 | imdb.images = struct(); 19 | imdb.labels = struct(); 20 | 21 | imdb.images.name = {}; 22 | 23 | cnt = 0; 24 | % train 25 | load(fullfile(opts.dataDir, 'wider_face_train.mat')); 26 | for i = 1:numel(event_list) 27 | imageDir = fullfile('WIDER_train/images', event_list{i}); 28 | imageList = file_list{i}; 29 | bboxList = face_bbx_list{i}; 30 | for j = 1:numel(imageList) 31 | cnt = cnt + 1; 32 | imagePath = fullfile(imageDir, [imageList{j} '.jpg']); 33 | imdb.images.name{cnt} = imagePath; 34 | 35 | info = imfinfo(fullfile(opts.dataDir, imagePath)); 36 | imdb.images.size(cnt,1:2) = [info.Height info.Width]; 37 | 38 | imdb.images.set(cnt) = 1; 39 | rects = bboxList{j}; 40 | imdb.labels.rects{cnt} = horzcat(... 41 | rects(:,[1 2]), rects(:,[1 2])+rects(:,[3 4])-1); 42 | imdb.labels.eventid(cnt) = i; 43 | end 44 | end 45 | 46 | % setup event list ( index is consistent with face_bbx_list ) 47 | imdb.events.name = event_list; 48 | 49 | %load(fullfile(opts.dataDir, 'event_diffmap.mat')); 50 | %for i = 1:numel(event_list) 51 | % imdb.events.diff(i) = diffmap(event_list{i}); 52 | %end 53 | 54 | % clear variables 55 | fprintf('Setup imdb: processed %d images.\n', cnt); 56 | clear face_bbx_list event_list file_list; 57 | 58 | % val 59 | load(fullfile(opts.dataDir, 'wider_face_val.mat')); 60 | for i = 1:numel(event_list) 61 | imageDir = fullfile('WIDER_val/images', event_list{i}); 62 | imageList = file_list{i}; 63 | bboxList = face_bbx_list{i}; 64 | for j = 1:numel(imageList) 65 | cnt = cnt + 1; 66 | imagePath = fullfile(imageDir, [imageList{j} '.jpg']); 67 | imdb.images.name{cnt} = imagePath; 68 | 69 | info = imfinfo(fullfile(opts.dataDir, imagePath)); 70 | imdb.images.size(cnt,1:2) = [info.Height info.Width]; 71 | 72 | imdb.images.set(cnt) = 2; 73 | rects = bboxList{j}; 74 | imdb.labels.rects{cnt} = horzcat(... 75 | rects(:,[1 2]), rects(:,[1 2])+rects(:,[3 4])-1); 76 | imdb.labels.eventid(cnt) = i; 77 | end 78 | end 79 | fprintf('Setup imdb: processed %d images.\n', cnt); 80 | clear face_bbx_list event_list file_list; 81 | 82 | % test 83 | load(fullfile(opts.dataDir, 'wider_face_test.mat')); 84 | for i = 1:numel(event_list) 85 | imageDir = fullfile('WIDER_test/images', event_list{i}); 86 | imageList = file_list{i}; 87 | for j = 1:numel(imageList) 88 | cnt = cnt + 1; 89 | imagePath = fullfile(imageDir, [imageList{j} '.jpg']); 90 | imdb.images.name{cnt} = imagePath; 91 | 92 | info = imfinfo(fullfile(opts.dataDir, imagePath)); 93 | imdb.images.size(cnt,1:2) = [info.Height info.Width]; 94 | 95 | imdb.images.set(cnt) = 3; 96 | imdb.labels.eventid(cnt) = i; 97 | end 98 | end 99 | fprintf('Setup imdb: processed %d images.\n', cnt); 100 | clear event_list file_list; 101 | -------------------------------------------------------------------------------- /cnn_widerface.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_widerface.m 2 | % 3 | % This function serves as the main function for training a model. 4 | % 5 | % INPUT: configuration (see code for details) 6 | % 7 | % OUTPUT: net (trained network) 8 | % info (training stats) 9 | 10 | function [net, info] = cnn_widerface(varargin) 11 | startup; 12 | 13 | 14 | opts.keepDilatedZeros = false; 15 | opts.inputSize = [500, 500]; 16 | opts.learningRate = 1e-4; 17 | 18 | %% use customized training function ie. adam 19 | opts.trainFn = '@cnn_train_dag'; 20 | opts.batchGetterFn = '@cnn_get_batch_logistic_zoom'; 21 | opts.freezeResNet = false; 22 | opts.tag = ''; 23 | opts.clusterNum = 25; 24 | opts.clusterName = ''; 25 | opts.bboxReg = true; 26 | opts.skipLRMult = [1, 0.001, 0.0001, 0.00001]; 27 | opts.sampleSize = 256; 28 | opts.posFraction = 0.5; 29 | opts.posThresh = 0.7; 30 | opts.negThresh = 0.3; 31 | opts.border = [0, 0]; 32 | opts.pretrainModelPath = 'matconvnet/pascal-fcn8s-tvg-dag.mat'; 33 | opts.dataDir = fullfile('data','widerface') ; 34 | opts.modelType = 'pascal-fcn8s-tvg-dag' ; 35 | opts.networkType = 'dagnn' ; 36 | opts.batchNormalization = true ; 37 | opts.weightInitMethod = 'gaussian' ; 38 | [opts, varargin] = vl_argparse(opts, varargin) ; 39 | 40 | opts.minClusterSize = [2, 2]; 41 | opts.maxClusterSize = opts.inputSize; 42 | [opts, varargin] = vl_argparse(opts, varargin) ; 43 | 44 | sfx = opts.modelType ; 45 | if opts.freezeResNet, sfx = ['freezed-' sfx] ; end 46 | sfx = [sfx '-' 'sample' num2str(opts.sampleSize)] ; 47 | sfx = [sfx '-' 'posfrac' num2str(opts.posFraction)] ; 48 | sfx = [sfx '-' 'N' num2str(opts.clusterNum)]; 49 | if opts.bboxReg, sfx = [sfx '-' 'bboxreg']; end 50 | 51 | if any(opts.inputSize~=500), 52 | sz = opts.inputSize; 53 | sfx = [sfx '-input' num2str(sz(1)) 'x' num2str(sz(2))]; 54 | end 55 | if ~isempty(opts.clusterName) 56 | sfx = [sfx '-' 'cluster-' opts.clusterName]; 57 | end 58 | 59 | opts.expDir = fullfile('models', ['widerface-' sfx]) ; 60 | if ~isempty(opts.tag) 61 | opts.expDir = [opts.expDir '-' opts.tag]; 62 | end 63 | [opts, varargin] = vl_argparse(opts, varargin) ; 64 | opts.expDir 65 | 66 | opts.batchSize = 10; 67 | opts.numSubBatches = 1; 68 | opts.numEpochs = 50; 69 | opts.gpus = [1]; 70 | opts.numFetchThreads = 8; 71 | opts.lite = false ; 72 | opts.imdbPath = fullfile(opts.dataDir, 'imdb.mat'); 73 | opts = vl_argparse(opts, varargin) ; 74 | 75 | opts.train = struct() ; 76 | opts = vl_argparse(opts, varargin) ; 77 | 78 | opts.train.gpus = opts.gpus; 79 | opts.train.batchSize = opts.batchSize; 80 | opts.train.numSubBatches = opts.numSubBatches; 81 | opts.train.numEpochs = opts.numEpochs; 82 | opts.train.learningRate = opts.learningRate; 83 | 84 | opts.train.keepDilatedZeros = opts.keepDilatedZeros; 85 | 86 | %% initialize model structure 87 | fprintf('Trying to initialize the structure of %s\n', opts.modelType); 88 | net = cnn_init('model', opts.modelType, ... 89 | 'batchNormalization', opts.batchNormalization, ... 90 | 'weightInitMethod', opts.weightInitMethod, ... 91 | 'networkType', opts.networkType) ; 92 | 93 | %% load pretrained weights 94 | if ~isempty(opts.pretrainModelPath) 95 | fprintf('Loading pretrained weights from %s\n', opts.pretrainModelPath); 96 | if ~exist(opts.pretrainModelPath) 97 | [~,model_name,~] = fileparts(opts.pretrainModelPath); 98 | download_path = sprintf('./trained_models/%s.mat', model_name); 99 | download_url = sprintf('http://www.vlfeat.org/matconvnet/models/%s.mat', model_name); 100 | fprintf('Downloading model %s from %s to %s ... \n', model_name, download_url, download_path); 101 | cmd = sprintf('wget -O %s %s', download_path, download_url); 102 | system(cmd); 103 | end 104 | net = cnn_load_pretrain(net, opts.pretrainModelPath); 105 | end 106 | 107 | net.meta.inputSize = opts.inputSize; 108 | net.meta.normalization.inputSize = opts.inputSize; 109 | net.meta.normalization.border = opts.border; 110 | net.meta.augmentation.transformation = 'none'; 111 | net.meta.augmentation.rgbVariance = []; 112 | 113 | if ~exist(opts.expDir), mkdir(opts.expDir); end; 114 | 115 | %% prepare data 116 | if exist(opts.imdbPath) 117 | imdb = load(opts.imdbPath) ; 118 | fprintf('Loaded imdb from %s\n', opts.imdbPath); 119 | else 120 | imdb = cnn_setup_imdb('dataDir', opts.dataDir); 121 | save(opts.imdbPath, '-struct', 'imdb') ; 122 | fprintf('Saved imdb to %s\n', opts.imdbPath); 123 | end 124 | 125 | %% save model options 126 | optpath = fullfile(opts.expDir, 'opts.mat'); 127 | if ~exist(optpath), save(optpath, 'opts'); end 128 | 129 | 130 | %% define batch getter function 131 | %batchGetter = @cnn_get_batch_logistic_zoom; 132 | if ~isempty(opts.batchGetterFn) 133 | batchGetter = str2func(opts.batchGetterFn); 134 | end 135 | 136 | %% compute image stats 137 | imageStatsPath = fullfile(opts.dataDir, 'imageStats.mat') ; 138 | if exist(imageStatsPath) 139 | load(imageStatsPath, 'averageImage', 'rgbMean', 'rgbCovariance') ; 140 | else 141 | [averageImage, rgbMean, rgbCovariance] = getImageStats(batchGetter, ... 142 | opts, net.meta, imdb) ; 143 | save(imageStatsPath, 'averageImage', 'rgbMean', 'rgbCovariance') ; 144 | end 145 | net.meta.augmentation.transformation = 'f5'; 146 | net.meta.normalization.averageImage = rgbMean ; 147 | [v,d] = eig(rgbCovariance) ; 148 | net.meta.augmentation.rgbVariance = 0.1*sqrt(d)*v' ; 149 | clear v d ; 150 | 151 | %% clustering 152 | minh = opts.minClusterSize(1); minw = opts.minClusterSize(2); 153 | maxh = opts.maxClusterSize(1); maxw = opts.maxClusterSize(2); 154 | if isempty(opts.clusterName) 155 | tmp_str = ['%s_N%d_' sprintf('min%dx%d_max%dx%d.mat',minh,minw,maxh,maxw)]; 156 | else 157 | tmp_str = ['%s_N%d_' opts.clusterName '.mat']; 158 | end 159 | clusterName = @(name,nd)(sprintf(tmp_str, name, nd)); 160 | 161 | %clusterName = @(name,nd,minh,minw,maxh,maxw)(sprintf( ... 162 | % '%s_N%d_min%dx%d_max%dx%d.mat',name,nd,minh,minw,maxh,maxw)); 163 | %clusterPath = fullfile(opts.dataDir, clusterName(... 164 | % 'RefBox',opts.clusterNum,minh,minw,maxh,maxw)); 165 | boxName = 'RefBox'; 166 | clusterPath = fullfile(opts.dataDir, clusterName(boxName,opts.clusterNum)); 167 | 168 | fprintf('cluster path: %s\n', clusterPath); 169 | 170 | if ~exist(clusterPath) 171 | clusters = cluster_rects(imdb, opts.clusterNum, [minh minw], [maxh maxw]); 172 | save(clusterPath, 'clusters'); 173 | else 174 | load(clusterPath); 175 | end 176 | net.meta.clusters = clusters; 177 | 178 | %% add predictors/losses 179 | switch opts.modelType 180 | case 'resnet-101-simple' 181 | net = cnn_add_loss_fcn8s_resnet101_simple(opts, net); 182 | otherwise 183 | error(sprintf('Not Implemented: model type %s', opts.modelType)); 184 | end 185 | 186 | %% compute receptive fields and canonical variable sizes 187 | var2idx = containers.Map; 188 | for i = 1:numel(net.vars) 189 | var2idx(net.vars(i).name) = i; 190 | end 191 | net.meta.var2idx = var2idx; 192 | 193 | sz_ = opts.inputSize; 194 | net.meta.varsizes = net.getVarSizes({'data',[sz_,3,1]}); 195 | net.meta.recfields = net.getVarReceptiveFields('data'); 196 | 197 | %% configure sampling hyperparameters 198 | net.meta.sampleSize = opts.sampleSize; 199 | net.meta.posFraction = opts.posFraction; 200 | net.meta.posThresh = opts.posThresh; 201 | net.meta.negThresh = opts.negThresh; 202 | 203 | %% assign training function 204 | trainFn = str2func(opts.trainFn); 205 | 206 | %% print out training options 207 | opts 208 | opts.train 209 | 210 | %% start training (no validation) 211 | derOutputs = {'loss_cls', 1, 'loss_reg', 1}; 212 | [net, info] = trainFn(net, imdb, getBatchFn(batchGetter, opts, net.meta), ... 213 | 'expDir', opts.expDir,... 214 | 'derOutputs', derOutputs, ... 215 | 'val', nan,... 216 | opts.train) ; 217 | 218 | 219 | %% wrapper for batch getter function 220 | function fn = getBatchFn(batchGetter, opts, meta) 221 | useGpu = numel(opts.train.gpus) > 0 ; 222 | 223 | bopts.numThreads = opts.numFetchThreads ; 224 | bopts.inputSize = meta.normalization.inputSize ; 225 | bopts.border = meta.normalization.border ; 226 | bopts.averageImage = meta.normalization.averageImage ; 227 | bopts.rgbVariance = meta.augmentation.rgbVariance ; 228 | bopts.transformation = meta.augmentation.transformation ; 229 | 230 | if isfield(meta, 'sampleSize'), bopts.sampleSize = meta.sampleSize; end; 231 | if isfield(meta, 'posFraction'), bopts.posFraction = meta.posFraction; end; 232 | if isfield(meta, 'posThresh'), bopts.posThresh = meta.posThresh; end; 233 | if isfield(meta, 'negThresh'), bopts.negThresh = meta.negThresh; end; 234 | 235 | if isfield(meta, 'clusters'), bopts.clusters = meta.clusters; end; 236 | if isfield(meta, 'var2idx'), bopts.var2idx = meta.var2idx; end; 237 | if isfield(meta, 'varsizes'), bopts.varsizes = meta.varsizes; end; 238 | if isfield(meta, 'recfields'), bopts.recfields = meta.recfields; end; 239 | switch lower(opts.networkType) 240 | case 'simplenn' 241 | fn = @(x,y) getSimpleNNBatch(batchGetter, bopts,x,y) ; 242 | case 'dagnn' 243 | fn = @(x,y) getDagNNBatch(batchGetter, bopts,useGpu,x,y) ; 244 | end 245 | 246 | %% interface to batch getter function 247 | function inputs = getDagNNBatch(batchGetter, opts, useGpu, imdb, batch) 248 | imagePaths = strcat([imdb.imageDir filesep], imdb.images.name(batch)) ; 249 | imageSizes = imdb.images.size(batch, :); 250 | %isVal = ~isempty(batch) && imdb.images.set(batch(1)) ~= 1 ; 251 | isVal = 0; 252 | if isfield(opts, 'clusters') && ~isVal 253 | labelRects = imdb.labels.rects(batch); 254 | else 255 | labelRects = []; 256 | end 257 | 258 | [images, clsmaps, regmaps] = batchGetter(imagePaths, imageSizes, labelRects, ... 259 | opts, 'prefetch', nargout == 0) ; 260 | 261 | if nargout > 0 262 | % if we are training 263 | if useGpu && ~isempty(clsmaps) && ~isempty(regmaps) 264 | images = gpuArray(images) ; 265 | end 266 | inputs = {'data', images}; 267 | 268 | if ~isempty(clsmaps) 269 | inputs(end+1:end+2) = {'label_cls', clsmaps}; 270 | end 271 | if ~isempty(regmaps) 272 | inputs(end+1:end+2) = {'label_reg', regmaps}; 273 | end 274 | end 275 | 276 | %% function to collect image statistics 277 | function [averageImage, rgbMean, rgbCovariance] = ... 278 | getImageStats(batchGetter, opts, meta, imdb) 279 | train = find(imdb.images.set == 1) ; 280 | train = train(1: 101: end); 281 | bs = 256 ; 282 | opts.networkType = 'dagnn' ; 283 | fn = getBatchFn(batchGetter, opts, meta) ; 284 | avg = {}; rgbm1 = {}; rgbm2 = {}; 285 | 286 | for t=1:bs:numel(train) 287 | batch_time = tic ; 288 | batch = train(t:min(t+bs-1, numel(train))) ; 289 | fprintf('collecting image stats: batch starting with image %d ...', batch(1)) ; 290 | temp = fn(imdb, batch) ; 291 | temp = gather(temp{2}); 292 | z = reshape(permute(temp,[3 1 2 4]),3,[]) ; 293 | n = size(z,2) ; 294 | avg{end+1} = mean(temp, 4) ; 295 | rgbm1{end+1} = sum(z,2)/n ; 296 | rgbm2{end+1} = z*z'/n ; 297 | batch_time = toc(batch_time) ; 298 | fprintf(' %.2f s (%.1f images/s)\n', batch_time, numel(batch)/ batch_time) ; 299 | end 300 | averageImage = mean(cat(4,avg{:}),4) ; 301 | rgbm1 = mean(cat(2,rgbm1{:}),2) ; 302 | rgbm2 = mean(cat(3,rgbm2{:}),3) ; 303 | rgbMean = rgbm1 ; 304 | rgbCovariance = rgbm2 - rgbm1*rgbm1' ; 305 | 306 | 307 | -------------------------------------------------------------------------------- /cnn_widerface_eval.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_widerface.m 2 | % 3 | % This function serves as the main function for evaluating a model. It loads 4 | % detection and ground truth and evaluates at all three difficulty levels at 5 | % once. 6 | % 7 | % Note that this evaluation script consistently produces slightly lower 8 | % numbers (mAPs) comparing to the official evaluation script. I implement my 9 | % own version because it runs faster and it is more customizable, in terms of 10 | % adding visualization etc. 11 | % 12 | % INPUT: configuration (see code for details) 13 | % 14 | % OUTPUT: none 15 | 16 | function cnn_widerface_eval(varargin) 17 | 18 | % 19 | opts.noUpsampling = false; 20 | opts.noOrgres = false; 21 | opts.noDownsampling = false; 22 | opts.testMultires = false; 23 | opts.testTag = ''; 24 | opts.inputSize = [500, 500]; 25 | [opts, varargin] = vl_argparse(opts, varargin); 26 | 27 | % 28 | opts.evalWithReg = true; 29 | opts.tag = ''; 30 | opts.bboxReg = true; 31 | opts.skipLRMult = [1, 0.001, 0.0001, 0.00001]; 32 | opts.penalizeDuplicate = true; 33 | opts.nmsThresh = 0.3; 34 | opts.probThresh = 0.8; 35 | opts.draw = false; 36 | opts.minOverlap = [0.3:0.2:0.7]; 37 | opts.testEpoch = 0; 38 | opts.testIter = 0; 39 | opts.testSet = 'val'; 40 | opts.resDir = 'results/'; 41 | opts.testName = ''; 42 | opts.clusterNum = 25; 43 | opts.clusterName = ''; 44 | opts.sampleSize = 256; 45 | opts.posFraction = 0.5; 46 | opts.posThresh = 0.7; 47 | opts.negThresh = 0.3; 48 | opts.pretrainModelPath = 'matconvnet/pascal-fcn8s-tvg-dag.mat'; 49 | opts.dataDir = fullfile('data','widerface') ; 50 | opts.modelType = 'pascal-fcn8s-tvg-dag' ; 51 | opts.networkType = 'dagnn' ; 52 | opts.batchNormalization = true ; 53 | opts.weightInitMethod = 'gaussian' ; 54 | [opts, varargin] = vl_argparse(opts, varargin) ; 55 | 56 | % 57 | opts.minClusterSize = [2, 2]; 58 | opts.maxClusterSize = opts.inputSize; 59 | [opts, varargin] = vl_argparse(opts, varargin) ; 60 | 61 | % 62 | sfx = opts.modelType ; 63 | sfx = [sfx '-' 'sample' num2str(opts.sampleSize)] ; 64 | sfx = [sfx '-' 'posfrac' num2str(opts.posFraction)] ; 65 | sfx = [sfx '-' 'N' num2str(opts.clusterNum)]; 66 | 67 | if opts.bboxReg, sfx = [sfx '-' 'bboxreg']; end 68 | 69 | if any(opts.inputSize~=500), 70 | sz = opts.inputSize; 71 | sfx = [sfx '-input' num2str(sz(1)) 'x' num2str(sz(2))]; 72 | end 73 | if ~isempty(opts.clusterName) 74 | sfx = [sfx '-' 'cluster-' opts.clusterName]; 75 | end 76 | 77 | % 78 | opts.expDir = fullfile('models', ['widerface-' sfx]); 79 | if ~isempty(opts.tag) 80 | opts.expDir = [opts.expDir '-' opts.tag]; 81 | end 82 | [opts, varargin] = vl_argparse(opts, varargin) ; 83 | 84 | % imdb 85 | opts.imdbPath = fullfile(opts.dataDir, 'imdb.mat'); 86 | [opts, varargin] = vl_argparse(opts, varargin) ; 87 | 88 | % 89 | 90 | if exist(opts.imdbPath) 91 | imdb = load(opts.imdbPath) ; 92 | else 93 | imdb = cnn_setup_imdb('dataDir', opts.dataDir); 94 | if ~exist(opts.expDir), mkdir(opts.expDir) ; end 95 | save(opts.imdbPath, '-struct', 'imdb') ; 96 | end 97 | 98 | % 99 | if opts.testEpoch == 0 100 | testEpoch = findLastCheckpoint(opts.expDir); 101 | if testEpoch==0 102 | error('No available model for evaluation.'); 103 | end 104 | else 105 | testEpoch = opts.testEpoch; 106 | end 107 | testSet = opts.testSet; 108 | 109 | if isempty(opts.testName) 110 | testName = strrep(opts.expDir, 'models/', ''); 111 | testName = sprintf('%s-epoch%d-%s', testName, testEpoch, testSet); 112 | testName = [testName '-probthresh' num2str(opts.probThresh)]; 113 | testName = [testName '-nmsthresh' num2str(opts.nmsThresh)]; 114 | if opts.testMultires, testName = [testName '-multires']; end 115 | if opts.noOrgres, testName = [testName '-noorgres']; end 116 | if opts.noUpsampling, testName = [testName '-noupsampling']; end 117 | if opts.noDownsampling, testName = [testName '-nodownsampling']; end 118 | if opts.evalWithReg, testName = [testName '-evalWithReg']; end 119 | else 120 | testName = opts.testName; 121 | end 122 | 123 | if ~isempty(opts.testTag), 124 | testName = [testName '-' opts.testTag]; 125 | end 126 | 127 | if strcmp(opts.resDir, 'results/') 128 | resDir = fullfile(opts.resDir, testName); 129 | if numel(resDir) > 255, resDir = strrep(resDir, '-nmsthresh0.3', ''); end 130 | if numel(resDir) > 255, resDir = strrep(resDir, 'widerface-resnet-50-',''); end 131 | if numel(resDir) > 255, resDir = strrep(resDir, 'bboxreg-logistic-cluster-',''); end 132 | else 133 | resDir = opts.resDir; 134 | end 135 | 136 | % load ground truth info 137 | %fprintf('Loading ground truth annotation for %s.\n', opts.testSet); 138 | switch opts.testSet 139 | case 'val' 140 | test = find(imdb.images.set == 2); 141 | case 'test' 142 | error('Evaluting on test set - you must be kidding me...\n') 143 | end 144 | 145 | hard_info = load('eval_tools/ground_truth/wider_hard_val.mat'); 146 | med_info = load('eval_tools/ground_truth/wider_medium_val.mat'); 147 | easy_info = load('eval_tools/ground_truth/wider_easy_val.mat'); 148 | 149 | % thresholds 150 | minOverlap = opts.minOverlap; 151 | nt = numel(opts.minOverlap); 152 | 153 | % 154 | img_idx_map = containers.Map(); 155 | for i = 1:numel(hard_info.file_list) 156 | for j = 1:numel(hard_info.file_list{i}) 157 | img_idx_map(hard_info.file_list{i}{j}) = j; 158 | end 159 | end 160 | 161 | % number of files 162 | easy_npos = 0 ; 163 | med_npos = 0 ; 164 | hard_npos = 0 ; 165 | 166 | gt(numel(test)) = struct('BB', [], 'det', []); 167 | easy_gt(numel(test)) = struct('BB', [], 'det', []); 168 | med_gt(numel(test)) = struct('BB', [], 'det', []); 169 | hard_gt(numel(test)) = struct('BB', [], 'det', []); 170 | for i = 1:numel(test) 171 | eventId = imdb.labels.eventid(test(i)); 172 | 173 | gtrects = imdb.labels.rects{test(i)}; 174 | gt(i).BB = gtrects'; 175 | easy_gt(i).det = false(size(gtrects,1), nt); 176 | med_gt(i).det = false(size(gtrects,1), nt); 177 | hard_gt(i).det = false(size(gtrects,1), nt); 178 | 179 | gt_h = gtrects(:,4)-gtrects(:,2)+1; 180 | gt_w = gtrects(:,3)-gtrects(:,1)+1; 181 | 182 | % NOTE: using released evaluation tools 183 | img_size = imdb.images.size(test(i),:); 184 | [~, img_name, ~] = fileparts(imdb.images.name{test(i)}); 185 | img_idx = img_idx_map(img_name); 186 | 187 | easy_gt(i).ign = ones(size(gtrects, 1), 1); 188 | med_gt(i).ign = ones(size(gtrects, 1), 1); 189 | hard_gt(i).ign = ones(size(gtrects, 1), 1); 190 | 191 | % easy_gt(i).ign(easy_info.ignore_list{eventId}{img_idx}) = 0; 192 | % med_gt(i).ign(med_info.ignore_list{eventId}{img_idx}) = 0; 193 | % hard_gt(i).ign(hard_info.ignore_list{eventId}{img_idx}) = 0; 194 | easy_gt(i).ign(easy_info.gt_list{eventId}{img_idx}) = 0; 195 | med_gt(i).ign(med_info.gt_list{eventId}{img_idx}) = 0; 196 | hard_gt(i).ign(hard_info.gt_list{eventId}{img_idx}) = 0; 197 | 198 | easy_npos = easy_npos + sum(easy_gt(i).ign == 0); 199 | med_npos = med_npos + sum(med_gt(i).ign == 0); 200 | hard_npos = hard_npos + sum(hard_gt(i).ign == 0); 201 | end 202 | 203 | % collect all predictions 204 | detrespath = fullfile(resDir, sprintf('detections.txt')); 205 | if ~exist(detrespath) || 1 206 | fout = fopen(detrespath, 'w'); 207 | for i = 1:numel(test) 208 | eventId = imdb.labels.eventid(test(i)); 209 | 210 | event = imdb.events.name{eventId}; 211 | [~,imname,~] = fileparts(imdb.images.name{test(i)}); 212 | resfile = fullfile(resDir, event, [imname '.txt']); 213 | if ~exist(resfile), continue; end 214 | o = fopen(resfile); 215 | C = textscan(o,'%d %d %d %d %f','HeaderLines', 2); 216 | % if this is an older result 217 | if any(cellfun(@(x)(any(isnan(x))), C)) 218 | fclose(o); 219 | o = fopen(resfile); 220 | C = textscan(o,'%d %d %d %d %d %f','HeaderLines', 2); 221 | end 222 | x1 = C{1}; y1 = C{2}; w = C{3}; h = C{4}; 223 | x2 = x1 + (w-1); y2 = y1 + (h-1); 224 | confidence = C{end}; 225 | 226 | fclose(o); 227 | for j = 1:numel(confidence) 228 | fprintf(fout, '%d %f %d %d %d %d\n',i,confidence(j), ... 229 | x1(j),y1(j),x2(j),y2(j)); 230 | end 231 | end 232 | fclose(fout); 233 | end 234 | 235 | % 236 | [ids,confidence,b1,b2,b3,b4] = textread(detrespath, '%d %f %d %d %d %d'); 237 | BB = [b1 b2 b3 b4]'; 238 | 239 | % 240 | bh = b4 - b2 + 1; 241 | bw = b3 - b1 + 1; 242 | 243 | % sort detections by decreasing confidence 244 | [sc,si]=sort(-confidence); 245 | ids=ids(si); 246 | BB=BB(:,si); 247 | %tids = tids(si); 248 | 249 | % assign detections to ground truth objects 250 | nd=length(confidence); 251 | 252 | easy_tp=zeros(nd,nt); 253 | easy_fp=zeros(nd,nt); 254 | med_tp=zeros(nd,nt); 255 | med_fp=zeros(nd,nt); 256 | hard_tp=zeros(nd,nt); 257 | hard_fp=zeros(nd,nt); 258 | 259 | ovmaxs=zeros(nd,1); 260 | tic; 261 | for d=1:nd 262 | % display progress 263 | if toc>1 264 | %fprintf('face: pr: compute: %d/%d\n',d,nd); 265 | drawnow; 266 | tic; 267 | end 268 | 269 | % find ground truth image 270 | i=ids(d); 271 | 272 | % assign detection to ground truth object if any 273 | bb=BB(:,d); 274 | ovmax=-inf; 275 | jmax = 0 ; 276 | 277 | for j=1:size(gt(i).BB,2) 278 | bbgt=gt(i).BB(:,j); 279 | bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))]; 280 | iw=bi(3)-bi(1)+1; 281 | ih=bi(4)-bi(2)+1; 282 | if iw>0 & ih>0 283 | % compute overlap as area of intersection / area of union 284 | ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+... 285 | (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-... 286 | iw*ih; 287 | ov=iw*ih/ua; 288 | if ov>ovmax 289 | ovmax=ov; 290 | jmax=j; 291 | end 292 | end 293 | end 294 | 295 | % assign detection as true positive/don't care/false positive 296 | for k=1:nt 297 | if ovmax>=opts.minOverlap(k) 298 | %if ~easy_gt(i).ign(j) 299 | if ~easy_gt(i).ign(jmax) 300 | if ~easy_gt(i).det(jmax,k) || ~opts.penalizeDuplicate 301 | easy_tp(d,k)=1; % true positive 302 | easy_gt(i).det(jmax,k)=true; 303 | else 304 | easy_fp(d,k)=1; % false positive (multiple detection) 305 | end 306 | end 307 | %if ~med_gt(i).ign(j) 308 | if ~med_gt(i).ign(jmax) 309 | if ~med_gt(i).det(jmax,k) || ~opts.penalizeDuplicate 310 | med_tp(d,k)=1; % true positive 311 | med_gt(i).det(jmax,k)=true; 312 | else 313 | med_fp(d,k)=1; % false positive (multiple detection) 314 | end 315 | end 316 | %if ~hard_gt(i).ign(j) 317 | if ~hard_gt(i).ign(jmax) 318 | if ~hard_gt(i).det(jmax,k) || ~opts.penalizeDuplicate 319 | hard_tp(d,k)=1; % true positive 320 | hard_gt(i).det(jmax,k)=true; 321 | else 322 | hard_fp(d,k)=1; % false positive (multiple detection) 323 | end 324 | end 325 | else 326 | easy_fp(d,k)=1; % false positive 327 | med_fp(d,k)=1; % false positive 328 | hard_fp(d,k)=1; % false positive 329 | end 330 | end 331 | ovmaxs(d)=ovmax; 332 | end 333 | 334 | % compute precision/recall 335 | easy_fp_ = easy_fp; 336 | easy_tp_ = easy_tp; 337 | 338 | easy_fp=cumsum(easy_fp,1); 339 | easy_tp=cumsum(easy_tp,1); 340 | easy_rec=easy_tp/easy_npos; 341 | easy_prec=easy_tp./(easy_fp+easy_tp); 342 | 343 | easy_aps = zeros(1, nt); 344 | for k = 1:nt 345 | easy_aps(k)=VOCap(easy_rec(:,k),easy_prec(:,k)); 346 | fprintf('class: face, epoch: %d, subset: %s (easy), minOverlap=%.2f, AP = %.3f\n', ... 347 | testEpoch, testSet, opts.minOverlap(k), easy_aps(k)) 348 | end 349 | 350 | med_fp_ = med_fp; 351 | med_tp_ = med_tp; 352 | 353 | med_fp=cumsum(med_fp,1); 354 | med_tp=cumsum(med_tp,1); 355 | med_rec=med_tp/med_npos; 356 | med_prec=med_tp./(med_fp+med_tp); 357 | 358 | med_aps = zeros(1, nt); 359 | for k = 1:nt 360 | med_aps(k)=VOCap(med_rec(:,k),med_prec(:,k)); 361 | fprintf('class: face, epoch: %d, subset: %s (medium), minOverlap=%.2f, AP = %.3f\n', ... 362 | testEpoch, testSet, opts.minOverlap(k), med_aps(k)) 363 | end 364 | 365 | hard_fp_ = hard_fp; 366 | hard_tp_ = hard_tp; 367 | 368 | hard_fp=cumsum(hard_fp,1); 369 | hard_tp=cumsum(hard_tp,1); 370 | hard_rec=hard_tp/hard_npos; 371 | hard_prec=hard_tp./(hard_fp+hard_tp); 372 | 373 | hard_aps = zeros(1, nt); 374 | for k = 1:nt 375 | hard_aps(k)=VOCap(hard_rec(:,k),hard_prec(:,k)); 376 | fprintf('class: face, epoch: %d, subset: %s (hard), minOverlap=%.2f, AP = %.3f\n', ... 377 | testEpoch, testSet, opts.minOverlap(k), hard_aps(k)) 378 | end 379 | 380 | if opts.draw 381 | close all; 382 | for i = 1:3 383 | switch i 384 | case 1 385 | rec = easy_rec; 386 | prec = easy_prec; 387 | aps = easy_aps; 388 | diffLevel = 'easy'; 389 | case 2 390 | rec = med_rec; 391 | prec = med_prec; 392 | aps = med_aps; 393 | diffLevel = 'medium'; 394 | case 3 395 | rec = hard_rec; 396 | prec = hard_prec; 397 | aps = hard_aps; 398 | diffLevel = 'hard'; 399 | end 400 | 401 | figure(i); 402 | %% plot our precision/recall 403 | hold on; 404 | for k = 1:nt 405 | plot(rec(:,k),prec(:,k),'-','linewidth',3); 406 | [~,ii] = max(rec(:,k).*prec(:,k)); 407 | end 408 | 409 | hold off; 410 | grid; 411 | xlabel 'recall' 412 | ylabel 'precision' 413 | %title(sprintf('class: face, subset: %s, AP = %.3f',testSet,ap)); 414 | title(sprintf('class face, epoch %d, subset %s(%s), AP(0.5) %.3f', ... 415 | testEpoch, testSet, diffLevel, aps(opts.minOverlap==0.5))); 416 | xlim([0,1]); 417 | ylim([0,1]); 418 | print('-dpng', fullfile(resDir, ['wider_' diffLevel '.png'])); 419 | end 420 | end 421 | 422 | % ------------------------------------------------------------------------- 423 | function [epoch, iter] = findLastCheckpoint(modelDir) 424 | % ------------------------------------------------------------------------- 425 | list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ; 426 | 427 | epoch = 0; 428 | 429 | tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ; 430 | % find latest epoch 431 | for i = 1:numel(tokens) 432 | token = tokens{i}{1}; 433 | ep = str2num(token{1}); 434 | if ep >= epoch 435 | epoch = ep; 436 | end 437 | end 438 | -------------------------------------------------------------------------------- /cnn_widerface_test_AB.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_widerface.m 2 | % 3 | % This function serves as the main function for testing a model. 4 | % 5 | % INPUT: configuration (see code for details) 6 | % 7 | % OUTPUT: none (detections will be written to files) 8 | 9 | function cnn_widerface_test_AB(varargin) 10 | 11 | startup; 12 | 13 | opts.allscale_templateIds = []; 14 | opts.onescale_templateIds = []; 15 | 16 | opts.overWrite = false; 17 | opts.noOrgres = false; 18 | opts.noDownsampling = false; 19 | opts.noUpsampling = false; 20 | opts.testMultires = false; 21 | opts.testTag = ''; 22 | opts.inputSize = [500, 500]; 23 | 24 | opts.evalWithReg = true; 25 | opts.tag = ''; 26 | opts.bboxReg = true; 27 | opts.skipLRMult = [1, 0.001, 0.0001, 0.00001]; 28 | opts.vis = true; 29 | opts.testEpoch = 0; 30 | opts.testSet = 'val'; 31 | opts.resDir = 'results/'; 32 | opts.clusterNum = 25; 33 | opts.clusterName = ''; 34 | opts.sampleSize = 256; 35 | opts.posFraction = 0.5; 36 | opts.posThresh = 0.7; 37 | opts.negThresh = 0.3; 38 | opts.border = [0, 0]; 39 | opts.pretrainModelPath = 'matconvnet/pascal-fcn8s-tvg-dag.mat'; 40 | opts.dataDir = fullfile('data','widerface') ; 41 | opts.modelType = 'pascal-fcn8s-tvg-dag' ; 42 | opts.networkType = 'dagnn' ; 43 | opts.batchNormalization = true; 44 | opts.weightInitMethod = 'gaussian' ; 45 | [opts, varargin] = vl_argparse(opts, varargin) ; 46 | 47 | opts.probThresh = 0.05; 48 | opts.nmsThresh = 0.3; 49 | 50 | sfx = opts.modelType ; 51 | sfx = [sfx '-' 'sample' num2str(opts.sampleSize)] ; 52 | sfx = [sfx '-' 'posfrac' num2str(opts.posFraction)] ; 53 | sfx = [sfx '-' 'N' num2str(opts.clusterNum)]; 54 | 55 | if opts.bboxReg, sfx = [sfx '-' 'bboxreg']; end 56 | 57 | if any(opts.inputSize~=500), 58 | sz = opts.inputSize; 59 | sfx = [sfx '-input' num2str(sz(1)) 'x' num2str(sz(2))]; 60 | end 61 | if ~isempty(opts.clusterName) 62 | sfx = [sfx '-' 'cluster-' opts.clusterName]; 63 | end 64 | 65 | opts.expDir = fullfile('models', ['widerface-' sfx]) ; 66 | if ~isempty(opts.tag) 67 | opts.expDir = [opts.expDir '-' opts.tag]; 68 | end 69 | [opts, varargin] = vl_argparse(opts, varargin) ; 70 | opts.expDir 71 | 72 | opts.batchSize = 10; 73 | opts.numSubBatches = 1; 74 | opts.numEpochs = 20; 75 | opts.gpus = []; 76 | opts.learningRate = 0.0001; 77 | opts.numFetchThreads = 4 ; 78 | opts.lite = false ; 79 | opts.imdbPath = fullfile(opts.dataDir, 'imdb.mat'); 80 | opts = vl_argparse(opts, varargin) ; 81 | 82 | opts 83 | 84 | % load imdb 85 | if exist(opts.imdbPath) 86 | imdb = load(opts.imdbPath) ; 87 | else 88 | imdb = cnn_setup_imdb('dataDir', opts.dataDir); 89 | if ~exist(opts.expDir), mkdir(opts.expDir) ; end 90 | save(opts.imdbPath, '-struct', 'imdb') ; 91 | end 92 | 93 | % load model for testing 94 | opts.networkType = 'dagnn' ; 95 | 96 | % test latest model if no other options 97 | if opts.testEpoch == 0 98 | testEpoch = findLastCheckpoint(opts.expDir); 99 | if testEpoch==0 100 | error('No available model for evaluation.'); 101 | end 102 | else 103 | testEpoch = opts.testEpoch; 104 | end 105 | testSet = opts.testSet; 106 | testModelName = sprintf('net-epoch-%d.mat',testEpoch); 107 | testModelPath = fullfile(opts.expDir, testModelName); 108 | fprintf('Evaluating model from %s\n', testModelPath); 109 | 110 | % generate tag based on test settings 111 | testName = strrep(opts.expDir, 'models/', ''); 112 | testName = sprintf('%s-epoch%d-%s', testName, testEpoch, testSet); 113 | testName = [testName '-probthresh' num2str(opts.probThresh)]; 114 | testName = [testName '-nmsthresh' num2str(opts.nmsThresh)]; 115 | if opts.testMultires, testName = [testName '-multires']; end 116 | if opts.noOrgres, testName = [testName '-noorgres']; end 117 | if opts.noUpsampling, testName = [testName '-noupsampling']; end 118 | if opts.noDownsampling, testName = [testName '-nodownsampling']; end 119 | if opts.evalWithReg, testName = [testName '-evalWithReg']; end 120 | 121 | % append additional tags 122 | if ~isempty(opts.testTag), 123 | testName = [testName '-' opts.testTag]; 124 | end 125 | 126 | % generate result directory 127 | resDir = fullfile(opts.resDir, testName); 128 | if numel(resDir) > 255, resDir = strrep(resDir, '-nmsthresh0.3', ''); end 129 | if numel(resDir) > 255, resDir = strrep(resDir, 'widerface-resnet-50-',''); end 130 | if numel(resDir) > 255, resDir = strrep(resDir, 'bboxreg-logistic-cluster-',''); end 131 | if ~exist(resDir) mkdir(resDir); end 132 | for i = 1:numel(imdb.events.name) 133 | eventDir = fullfile(resDir, imdb.events.name{i}); 134 | if ~exist(eventDir), mkdir(eventDir); end 135 | end 136 | 137 | % load core net 138 | net_ = load(testModelPath); 139 | if isfield(net_, 'net') 140 | net = dagnn.DagNN.loadobj(net_.net); 141 | else 142 | net = dagnn.DagNN.loadobj(net_); 143 | end 144 | clear net_; 145 | 146 | % make sure matconvnet does not clear my precious variables 147 | %net.vars(net.getVarIndex('score_res4')).precious = 1; 148 | %net.vars(net.getVarIndex('score_res3')).precious = 1; 149 | %net.vars(net.getVarIndex('score_final')).precious = 1; 150 | 151 | % add cropping so that our network adjusts to different resolution at test time 152 | % (note: during training we always look at cropped regions with fixed size) 153 | net.layers(net.getLayerIndex('score4')).block.crop = [1,2,1,2]; 154 | net.addLayer('cropx',dagnn.Crop('crop',[0 0]), {'score_res3', 'score4'}, 'score_res3c'); % post crop 155 | net.setLayerInputs('fusex', {'score_res3c', 'score4'}); 156 | 157 | % add a probability output layer 158 | net.addLayer('prob_cls', dagnn.Sigmoid(), 'score_cls', 'prob_cls'); 159 | 160 | % build a dictionary from variable name to index 161 | var2idx = containers.Map; 162 | for i = 1:numel(net.vars) 163 | var2idx(net.vars(i).name) = i; 164 | end 165 | net.meta.var2idx = var2idx; 166 | net.meta.recfields = net.getVarReceptiveFields('data'); 167 | 168 | % move network onto gpu 169 | net.mode = 'test' ; 170 | if ~isempty(opts.gpus), 171 | assert(numel(opts.gpus) == 1); 172 | gpuDevice(opts.gpus); 173 | net.move('gpu'); 174 | end 175 | 176 | % 177 | vis = opts.vis; 178 | 179 | % setup test set 180 | switch opts.testSet 181 | case 'val' 182 | test = find(imdb.images.set==2); 183 | case 'test' 184 | test = find(imdb.images.set==3); 185 | end 186 | 187 | % canonical shapes 188 | clusters = net.meta.clusters; 189 | clusters_h = clusters(:,4) - clusters(:,2) + 1; 190 | clusters_w = clusters(:,3) - clusters(:,1) + 1; 191 | clusters_scale = clusters(:,5); 192 | max_cluster_h = max(clusters_h); 193 | max_cluster_w = max(clusters_w); 194 | 195 | % average image 196 | averageImage = reshape(net.meta.normalization.averageImage,1,1,3); 197 | 198 | 199 | % Type A and Type B template Ids 200 | if isempty(opts.allscale_templateIds) && isempty(opts.onescale_templateIds) 201 | error('at least specify allscale templates or onescale template'); 202 | else 203 | allscale_templateIds = opts.allscale_templateIds; 204 | onescale_templateIds = opts.onescale_templateIds; 205 | ignoredTemplateIds = setdiff(1:size(clusters,1), [allscale_templateIds onescale_templateIds]); 206 | end 207 | 208 | % Run evaluation image-by-image 209 | probThresh = opts.probThresh; 210 | nmsThresh = opts.nmsThresh; 211 | 212 | t1 = tic; 213 | for i = 1:numel(test) 214 | % input file 215 | imagePath = fullfile(imdb.imageDir, imdb.images.name{test(i)}); 216 | 217 | % output file 218 | [~,imname,imext] = fileparts(imagePath); 219 | eventId = imdb.labels.eventid(test(i)); 220 | event = imdb.events.name{eventId}; 221 | ofile = fullfile(resDir, event, [imname '.txt']); 222 | 223 | if ~opts.overWrite && ~vis && exist(ofile), 224 | continue; 225 | end 226 | 227 | imgsize = imdb.images.size(test(i),:); 228 | minside = min(imdb.images.size(test(i),:)); 229 | if opts.testMultires 230 | scales = [-2, -1, 0, 1]; 231 | else 232 | scales = [0] ; 233 | end 234 | 235 | if opts.noUpsampling 236 | scales(scales > 0) = []; 237 | end 238 | 239 | if opts.noDownsampling 240 | scales(scales < 0) = []; 241 | end 242 | 243 | if opts.noOrgres 244 | scales(scales == 0) = []; 245 | end 246 | 247 | if isempty(scales), 248 | error('Error: no scale to test (scales is empty)'); 249 | end 250 | 251 | drects = []; 252 | for s = 2 .^ scales 253 | testSize = minside * s; 254 | 255 | % scale-specific template selection 256 | if s < 1 % if we down-sample, no med/small templates 257 | invalid_onescale_idx = find(clusters_scale(onescale_templateIds) >= 1); 258 | elseif s == 1 % if no re-sample, only med templates 259 | invalid_onescale_idx = find(clusters_scale(onescale_templateIds) ~= 1); 260 | elseif s > 1 % if we up-sample, no big/med templates 261 | invalid_onescale_idx = find(clusters_scale(onescale_templateIds) <= 1); 262 | end 263 | invalid_tid = [ignoredTemplateIds onescale_templateIds(invalid_onescale_idx)]; 264 | 265 | % read input (only resize when we have to) 266 | if testSize ~= min(imdb.images.size(test(i),:)) 267 | ims = vl_imreadjpeg({imagePath}, 'resize', testSize); 268 | else 269 | ims = vl_imreadjpeg({imagePath}); 270 | end 271 | im = uint8(ims{1}); 272 | 273 | % give up when input resolution is too huge 274 | if s > 1 && (size(im,1) > 5000 || size(im,2) > 5000) 275 | continue; 276 | end 277 | 278 | % subtract average image and feed into the network 279 | im_ = bsxfun(@minus, single(im), averageImage); 280 | if strcmp(net.device, 'gpu') 281 | im_ = gpuArray(im_); 282 | end 283 | inputs = {'data', im_}; 284 | net.eval(inputs(1:2)); 285 | 286 | % compute classification and regression scores 287 | score_cls = gather(net.vars(net.getVarIndex('score_cls')).value); 288 | score_reg = gather(net.vars(net.getVarIndex('score_reg')).value); 289 | prob_cls = gather(net.vars(net.getVarIndex('prob_cls')).value); 290 | 291 | % decompose regression predictions 292 | tx = score_reg(:,:,1:opts.clusterNum); 293 | ty = score_reg(:,:,opts.clusterNum+1:opts.clusterNum*2); 294 | tw = score_reg(:,:,opts.clusterNum*2+1:opts.clusterNum*3); 295 | th = score_reg(:,:,opts.clusterNum*3+1:opts.clusterNum*4); 296 | 297 | % 298 | net.meta.inputSize = size(im_); 299 | net.meta.normalization.inputSize = size(im_); 300 | net.meta.varsizes = net.getVarSizes({'data', [size(im_),1]}); 301 | 302 | % NOTE: no need to do this since we allow negative appearing on the border during training 303 | %viomask = violation(net.meta,clusters,size(im_,1),size(im_,2)); 304 | %prob_cls(viomask) = 0; 305 | 306 | % zero out prediction from templates that are invalid on this scale 307 | prob_cls(:,:,invalid_tid) = 0 ; 308 | 309 | % gather initial detections 310 | idx = find(prob_cls > probThresh); 311 | scores = score_cls(idx); 312 | 313 | % translate feature-level coordinates to pixel-level coordinates 314 | [fy,fx,fc] = ind2sub(size(prob_cls), idx); 315 | [cy,cx] = backtrack(net.meta, fy, fx); 316 | cw = clusters(fc,3)-clusters(fc,1)+1; 317 | ch = clusters(fc,4)-clusters(fc,2)+1; 318 | 319 | % apply regression refinement if necessary 320 | if opts.evalWithReg 321 | dcx = cw .* tx(idx); 322 | dcy = ch .* ty(idx); 323 | rcx = cx + dcx; 324 | rcy = cy + dcy; 325 | rcw = cw .* exp(tw(idx)); 326 | rch = ch .* exp(th(idx)); 327 | tmp_drects = [rcx-rcw/2,rcy-rch/2,rcx+rcw/2,rcy+rch/2]; 328 | else 329 | tmp_drects = [cx-cw/2,cy-ch/2,cx+cw/2,cy+ch/2]; 330 | end 331 | 332 | % convert detections to the original scale 333 | original_size = imdb.images.size(test(i),:); 334 | factor = min(original_size ./ testSize); 335 | tmp_drects = bsxfun(@times, tmp_drects, factor); 336 | tmp_drects = horzcat(tmp_drects, fc, scores); 337 | drects = vertcat(drects, tmp_drects) ; 338 | end 339 | 340 | % append score and do nms 341 | ridx = nms(drects(:,[1:4 end]), nmsThresh); 342 | srects = drects(ridx, :); 343 | 344 | % round to pixel coordinates 345 | if ~isempty(srects) 346 | srects(:,1:4) = round(srects(:,1:4)); 347 | end 348 | 349 | % output to file 350 | fout = fopen(ofile, 'w'); 351 | fprintf(fout, '%s/%s%s\n', event, imname, imext); 352 | fprintf(fout, '%d\n', size(srects,1)); 353 | for j = 1:size(srects, 1) 354 | fprintf(fout, '%d %d %d %d %f\n', ... 355 | srects(j,1), srects(j,2), ... 356 | srects(j,3)-srects(j,1)+1, ... 357 | srects(j,4)-srects(j,2)+1, ... 358 | srects(j,end)); 359 | end 360 | fclose(fout); 361 | 362 | if vis 363 | figure(1); 364 | clf; 365 | 366 | im = imread(imagePath); 367 | imshow(im); 368 | hold on ; 369 | if test(i) <= numel(imdb.labels.rects) 370 | grects = imdb.labels.rects{test(i)}; 371 | else 372 | grects = []; 373 | end 374 | 375 | if ~isempty(grects), 376 | % get rid of ground truth that are too small 377 | grects(find(grects(:,4)-grects(:,2)+1<10),:) = []; 378 | % for each ground truth, compute the best overlap with any detection 379 | ovlp = 1 - pdist2(srects(:,1:4), grects, @rect_dist, 'smallest', 1); 380 | colors = [0 0 0]; 381 | if all(ovlp==0) % no detection associated with this gt at all 382 | colors = [1 0 0]; 383 | else 384 | colors(ovlp >= 0.5, 2) = 1; % we got this one 385 | colors(ovlp < 0.5, 1) = 1; % we failed this one 386 | end 387 | plotBoxes(grects(:,1), grects(:,2), ... 388 | grects(:,3)-grects(:,1)+1, grects(:,4)-grects(:,2)+1,... 389 | colors, 3*ones(size(grects,1),1)); 390 | rec = sum(ovlp>=0.5); % we can compute a per-image recall rate 391 | rec_rate = rec / size(grects, 1); 392 | else 393 | rec = nan; 394 | rec_rate = nan; 395 | end 396 | 397 | % plot detections 398 | srects = double(srects); 399 | % plotBoxes(srects(:,1), srects(:,2), ... 400 | % srects(:,3)-srects(:,1)+1, ... 401 | % srects(:,4)-srects(:,2)+1,... 402 | % [0 0 1], 2*ones(size(srects,1),1)); 403 | visualize_detection([], srects, 0.3); 404 | hold off; 405 | 406 | msg = sprintf('recall %d%%(%d/%d), at thresh %.2f\n', ... 407 | round(rec_rate*100), rec, size(grects,1), ... 408 | opts.probThresh); 409 | title(msg); 410 | 411 | drawnow; 412 | keyboard; 413 | end 414 | t2 = toc(t1); 415 | fprintf('Testing epoch %d: processed %d/%d, %.2f img/sec\n', ... 416 | testEpoch, i, numel(test), i/t2); 417 | end 418 | 419 | function viomask = violation(opts,clusters,h,w) 420 | rf = opts.recfields(opts.var2idx('prob_cls')); 421 | ofx = rf.offset(2); 422 | ofy = rf.offset(1); 423 | stx = rf.stride(2); 424 | sty = rf.stride(1); 425 | 426 | % 427 | varsize = opts.varsizes{opts.var2idx('score_cls')}; 428 | vsx = varsize(2); 429 | vsy = varsize(1); 430 | 431 | % 432 | [xx,yy] = meshgrid(ofx+[0:vsx-1]*stx, ofy+[0:vsy-1]*sty); 433 | nc = size(clusters,1); 434 | dx1 = reshape(clusters(:,1),1,1,nc); 435 | dy1 = reshape(clusters(:,2),1,1,nc); 436 | dx2 = reshape(clusters(:,3),1,1,nc); 437 | dy2 = reshape(clusters(:,4),1,1,nc); 438 | areas = reshape((dx2-dx1+1).*(dy2-dy1+1), 1,1,nc); 439 | 440 | xx1 = bsxfun(@plus, xx, dx1); 441 | yy1 = bsxfun(@plus, yy, dy1); 442 | xx2 = bsxfun(@plus, xx, dx2); 443 | yy2 = bsxfun(@plus, yy, dy2); 444 | 445 | % compute four corners of the rect 446 | viox1 = xx1 <= 0; 447 | vioy1 = yy1 <= 0; 448 | viox2 = xx2 > w; 449 | vioy2 = yy2 > h; 450 | viomask = viox1 | vioy1 | viox2 | vioy2; 451 | 452 | function [cy,cx] = backtrack(opts,fy,fx) 453 | rf = opts.recfields(opts.var2idx('score_cls')); 454 | ofx = rf.offset(2); 455 | ofy = rf.offset(1); 456 | stx = rf.stride(2); 457 | sty = rf.stride(1); 458 | cx = (fx-1)*stx + ofx; 459 | cy = (fy-1)*sty + ofy; 460 | 461 | % ------------------------------------------------------------------------- 462 | function epoch = findLastCheckpoint(modelDir) 463 | % ------------------------------------------------------------------------- 464 | list = dir(fullfile(modelDir, 'net-epoch-*.mat')) ; 465 | 466 | epoch = 0; 467 | 468 | tokens = regexp({list.name}, 'net-epoch-([\d]+).mat', 'tokens') ; 469 | % find latest epoch 470 | for i = 1:numel(tokens) 471 | token = tokens{i}{1}; 472 | ep = str2num(token{1}); 473 | if ep >= epoch 474 | epoch = ep; 475 | end 476 | end 477 | 478 | -------------------------------------------------------------------------------- /data/demo/selfie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/data/demo/selfie.jpg -------------------------------------------------------------------------------- /data/widerface/RefBox_N25.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/data/widerface/RefBox_N25.mat -------------------------------------------------------------------------------- /data/widerface/RefBox_N25_scaled.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/data/widerface/RefBox_N25_scaled.mat -------------------------------------------------------------------------------- /data/widerface/imageStats.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/data/widerface/imageStats.mat -------------------------------------------------------------------------------- /data/widerface/imdb.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/data/widerface/imdb.mat -------------------------------------------------------------------------------- /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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/ground_truth/wider_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_face_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/ground_truth/wider_face_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/ground_truth/wider_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/HR/wider_pr_info_HR_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/baselines/Val/setting_int/hr_res101/wider_pr_info_hr_res101_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/two_stage_cnn/wider_pr_info_two_stage_cnn_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/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/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/eval_tools/plot/figure/Test/wider_pr_cruve_int_medium.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]); 4 | axes1 = axes('Parent',figure1,... 5 | 'LineWidth',2,... 6 | 'FontSize',15,... 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',4,... 18 | 'Color',LineColor(i,:)) 19 | hleg = legend(lendge_name{:},'Location','SouthEast'); 20 | grid on; 21 | hold on; 22 | end 23 | xlim([0,1]); 24 | ylim([0,1]); 25 | xlabel('Recall'); 26 | ylabel('Precision'); 27 | 28 | savename = sprintf('./plot/figure/%s/wider_pr_cruve_%s_%s.pdf',dateset_class,seting_class,setting_name); 29 | saveTightFigure(gcf,savename); 30 | clear gcf; 31 | hold off; 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /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) width height]); 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(end); 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 | -------------------------------------------------------------------------------- /init/cnn_add_loss_fcn8s_resnet101_simple.m: -------------------------------------------------------------------------------- 1 | function net = cnn_add_loss_fcn8s_resnet101_simple(opts, net) 2 | 3 | %% 4 | if opts.freezeResNet, 5 | for i = 1:numel(net.params) 6 | net.params(i).learningRate = 0; 7 | end 8 | end 9 | 10 | %% 11 | N = opts.clusterNum; 12 | skipLRMultipliers = opts.skipLRMult; 13 | learningRates = skipLRMultipliers; 14 | 15 | %% remove prob 16 | if ~isnan(net.getLayerIndex('prob')) 17 | net.removeLayer('prob'); 18 | end 19 | 20 | % 21 | names = {}; 22 | for i = 1:numel(net.layers) 23 | if ~isempty(strfind(net.layers(i).name,'res5')) || ... 24 | ~isempty(strfind(net.layers(i).name, 'bn5')) 25 | names{end+1} = net.layers(i).name; 26 | end 27 | end 28 | names{end+1} = 'pool5'; 29 | names{end+1} = 'fc1000'; 30 | 31 | for i = 1:numel(names) 32 | net.removeLayer(names{i}); 33 | end 34 | 35 | % NOTE: we end up not using features from res5 36 | % %% update 'fc1000' (on 'pool5') 37 | % lidx = net.getLayerIndex('fc1000'); 38 | % fidx = net.getParamIndex('fc1000_filter'); 39 | % bidx = net.getParamIndex('fc1000_bias'); 40 | % v = net.params(fidx).value; 41 | % [h,w,in,~] = size(v); 42 | % out = 5*N; 43 | % net.params(fidx).value = zeros(h,w,in,out,'single'); 44 | % net.params(fidx).learningRate = learningRates(1); 45 | % net.params(bidx).value = zeros(1,out,'single'); 46 | % net.params(bidx).learningRate = learningRates(1); 47 | % net.layers(lidx).block.size(4) = out; 48 | % 49 | % %% add upsampling 50 | % filter = single(bilinear_u(4, 1, 5*N)); 51 | % ctblk = dagnn.ConvTranspose('size', size(filter), 'upsample', 2, ... 52 | % 'crop', [0, 0, 0, 0], 'hasBias', false); 53 | % net.addLayer('score2', ctblk, 'fc1000', 'score2', 'score2f'); 54 | % fidx = net.getParamIndex('score2f'); 55 | % net.params(fidx).value = filter; 56 | % net.params(fidx).learningRate = 0; 57 | 58 | 59 | %% add predictors on 'res4b22x' 60 | filter = zeros(1,1,1024,5*N,'single'); 61 | bias = zeros(1,5*N,'single'); 62 | cblk = dagnn.Conv('size',size(filter),'stride',1,'pad',0); 63 | net.addLayer('score_res4', cblk, 'res4b22x', 'score_res4', ... 64 | {'score_res4_filter', 'score_res4_bias'}); 65 | fidx = net.getParamIndex('score_res4_filter'); 66 | bidx = net.getParamIndex('score_res4_bias'); 67 | net.params(fidx).value = filter; 68 | net.params(fidx).learningRate = learningRates(2); 69 | net.params(bidx).value = bias; 70 | net.params(bidx).learningRate = learningRates(2); 71 | 72 | %% add upsampling 73 | filter = single(bilinear_u(4, 1, 5*N)); 74 | 75 | % adapt for different input sizes (we end up using 500x500) 76 | if all(opts.inputSize==500) 77 | ctblk = dagnn.ConvTranspose('size', size(filter), 'upsample', 2, ... 78 | 'crop', [1,2,1,2], 'hasBias', false); 79 | elseif opts.inputSize(1)==750 && opts.inputSize(2)==1000 80 | ctblk = dagnn.ConvTranspose('size', size(filter), 'upsample', 2, ... 81 | 'crop', [1,1,1,2], 'hasBias', false); 82 | elseif opts.inputSize(1)==300 && opts.inputSize(2)==300 83 | ctblk = dagnn.ConvTranspose('size', size(filter), 'upsample', 2, ... 84 | 'crop', [1,1,1,1], 'hasBias', false); 85 | else 86 | error('Input size not supported'); 87 | end 88 | 89 | % define bilinear interpolation filter (fixed weights) 90 | net.addLayer('score4', ctblk, 'score_res4', 'score4', 'score4f'); 91 | fidx = net.getParamIndex('score4f'); 92 | net.params(fidx).value = filter; 93 | net.params(fidx).learningRate = 0; 94 | 95 | %% add predictors on 'res3dx' 96 | filter = zeros(1,1,512,5*N,'single'); 97 | bias = zeros(1,5*N,'single'); 98 | cblk = dagnn.Conv('size',size(filter),'stride',1,'pad',0); 99 | net.addLayer('score_res3', cblk, 'res3b3x', 'score_res3', ... 100 | {'score_res3_filter', 'score_res3_bias'}); 101 | fidx = net.getParamIndex('score_res3_filter'); 102 | bidx = net.getParamIndex('score_res3_bias'); 103 | net.params(fidx).value = filter; 104 | net.params(fidx).learningRate = learningRates(3); 105 | net.params(bidx).value = bias; 106 | net.params(bidx).learningRate = learningRates(3); 107 | 108 | % Note: since we train on cropped regions with fixed size, 109 | % we don't need to add cropping layers for aligning heat maps 110 | % before adding them 111 | 112 | % sum 113 | net.addLayer('fusex',dagnn.Sum(),{'score_res3', 'score4'}, ... 114 | 'score_res3_fused'); 115 | 116 | %% rename last score to score_final 117 | net.renameVar('score_res3_fused', 'score_final'); 118 | 119 | % 120 | net.addLayer('split', dagnn.Split('childIds', {1:N, N+1:5*N}), ... 121 | 'score_final', {'score_cls', 'score_reg'}); 122 | 123 | % only use customized loss when we have variable sample size 124 | net.addLayer('loss_cls', dagnn.Loss('loss', 'logistic'), ... 125 | {'score_cls', 'label_cls'}, 'loss_cls'); 126 | net.addLayer('loss_reg', dagnn.HuberLoss(), ... 127 | {'score_reg', 'label_reg', 'label_cls'}, 'loss_reg'); 128 | 129 | -------------------------------------------------------------------------------- /scripts/hr_res101.m: -------------------------------------------------------------------------------- 1 | function hr_res101(mode) 2 | 3 | if nargin < 1 || isempty(mode) 4 | mode = 'train'; 5 | end 6 | 7 | %% general settings 8 | overWrite = false; 9 | modelType = 'resnet-101-simple'; 10 | pretrainModelPath = './trained_models/imagenet-resnet-101-dag.mat'; 11 | inputSize = [500, 500]; 12 | trainFn = '@cnn_train_dag_hardmine'; 13 | batchGetterFn = '@cnn_get_batch_hardmine'; 14 | maxClusterSize = [inf, inf]; 15 | minClusterSize = [10, 10]; 16 | nmsThresh = 0.3; 17 | numSubBatches = 1; 18 | batchSize = 12; 19 | numEpochs = 50; 20 | tag = ''; 21 | gpus = [1 2 3 4]; 22 | if numel(gpus) > 1 23 | batchSize = batchSize * numel(gpus); 24 | end 25 | 26 | testTag = ''; 27 | testSet = 'val'; 28 | testMultires = true; 29 | 30 | clusterNum = 25; 31 | clusterName = 'scaled'; 32 | skipLRMult = [0 1 0.1]; % separate learning rate for skip connections from res5, res4, res3 33 | learningRates = [1e-4*ones(1,30)]; 34 | 35 | allscale_templateIds = [5:12]; % Type-A 36 | onescale_templateIds = [19:25]; % Type-B 37 | 38 | switch mode 39 | case 'train' 40 | % we still need an input size so that we know what to crop 41 | cnn_widerface('inputSize', inputSize, ... 42 | 'minClusterSize', minClusterSize, ... 43 | 'maxClusterSize', maxClusterSize, ... 44 | 'pretrainModelPath', pretrainModelPath, ... 45 | 'clusterNum', clusterNum, ... 46 | 'clusterName', clusterName, ... 47 | 'modelType', modelType, ... 48 | 'trainFn', trainFn, ... 49 | 'batchGetterFn', batchGetterFn, ... 50 | 'batchSize', batchSize, ... 51 | 'numEpochs', numEpochs, ... 52 | 'numSubBatches', numSubBatches,... 53 | 'gpus', gpus, ... 54 | 'skipLRMult', skipLRMult, ... 55 | 'learningRate', learningRates, ... 56 | 'tag', tag); 57 | case 'vis' 58 | for i = 20 59 | cnn_widerface_test_AB('overWrite', overWrite, ... 60 | 'inputSize', inputSize, ... 61 | 'clusterNum', clusterNum, ... 62 | 'clusterName', clusterName, ... 63 | 'testMultires', testMultires, ... 64 | 'noUpsampling', false, ... 65 | 'noOrgres', false, ... 66 | 'noDownsampling', false, ... 67 | 'allscale_templateIds', allscale_templateIds, ... 68 | 'onescale_templateIds', onescale_templateIds, ... 69 | 'tag', tag, ... 70 | 'testTag', testTag, ... 71 | 'inputSize', inputSize, ... 72 | 'batchSize', batchSize, ... 73 | 'numSubBatches', numSubBatches,... 74 | 'modelType', modelType, ... 75 | 'pretrainModelPath', pretrainModelPath, ... 76 | 'vis', vis, 'gpus', gpus, ... 77 | 'probThresh', probThresh, ... 78 | 'nmsThresh', nmsThresh, ... 79 | 'testSet', testSet, ... 80 | 'testEpoch', i); 81 | end 82 | case 'test' 83 | numEpochsToTest = numEpochs; 84 | gpus = [1 2 3 4]; 85 | gpuNum = numel(gpus); 86 | taskPerGpu = 2; 87 | vis = false; 88 | probThresh = 0.03; 89 | spmd (taskPerGpu * gpuNum) 90 | startEpoch = numEpochsToTest - labindex + 1; 91 | testEpochs = startEpoch : ((-1)*taskPerGpu*gpuNum) : 1; 92 | gpuId = gpus(ceil(labindex/taskPerGpu)); 93 | for i = testEpochs 94 | cnn_widerface_test_AB('overWrite', overWrite, ... 95 | 'allscale_templateIds', allscale_templateIds, ... 96 | 'onescale_templateIds', onescale_templateIds, ... 97 | 'inputSize', inputSize, ... 98 | 'modelType', modelType, ... 99 | 'clusterNum', clusterNum, ... 100 | 'clusterName', clusterName, ... 101 | 'testMultires', testMultires, ... 102 | 'noUpsampling', false, ... 103 | 'noOrgres', false, ... 104 | 'noDownsampling', false, ... 105 | 'tag', tag, ... 106 | 'testTag', testTag, ... 107 | 'vis', vis, ... 108 | 'gpus', gpuId, ... 109 | 'probThresh', probThresh, ... 110 | 'nmsThresh', nmsThresh, ... 111 | 'testSet', testSet, ... 112 | 'testEpoch', i); 113 | end 114 | end 115 | case 'eval' 116 | probThresh = 0.03; 117 | for i = numEpochs:-1:1 118 | cnn_widerface_eval('clusterNum', clusterNum, ... 119 | 'clusterName', clusterName, ... 120 | 'testMultires', true, ... 121 | 'noUpsampling', false, ... 122 | 'noOrgres', false, ... 123 | 'noDownsampling', false, ... 124 | 'tag', tag, ... 125 | 'testTag', testTag, ... 126 | 'inputSize', inputSize, ... 127 | 'modelType', modelType, ... 128 | 'gpus', gpus, ... 129 | 'probThresh', probThresh, ... 130 | 'nmsThresh', nmsThresh, ... 131 | 'testSet', testSet, ... 132 | 'testEpoch', i); 133 | end 134 | end 135 | -------------------------------------------------------------------------------- /selfie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/selfie.png -------------------------------------------------------------------------------- /startup.m: -------------------------------------------------------------------------------- 1 | % FILE: minimal_demo.m 2 | % 3 | % This script add important paths and setup the matconvnet. 4 | 5 | addpath matconvnet; 6 | addpath matconvnet/matlab; 7 | vl_setupnn; 8 | 9 | addpath init; 10 | addpath toolbox; 11 | addpath toolbox/nms; 12 | addpath scripts; 13 | addpath utils; 14 | 15 | rng(0); -------------------------------------------------------------------------------- /tiny_face_detector.m: -------------------------------------------------------------------------------- 1 | % FILE: tiny_face_detector.m 2 | % 3 | % This script serves as a minimal demo for our face detector. Note that 4 | % running this file does not reproduce the same numbers as reported in our 5 | % paper, due to different parameter setting. 6 | % 7 | % In this demo, we set the parameters in a way that the visualization looks 8 | % clean, but this results in a relatively poor recall. However, to achieve a 9 | % nice recall, we have to lower the threshold of detection confidence and 10 | % increase the overlap threshold of NMS. 11 | % 12 | % In our WIDER FACE experiments, we set confidence threshold to 0.03 and NMS 13 | % threshold to 0.3. Additionally, we test with a fixed set of scales. For 14 | % more details, please refer to our experiment script (scripts/hr_res101.m) 15 | % and the main test function (cnn_widerface_test_AB.m). 16 | % 17 | % Feel free to modify the code to suit your needs (such as batch processing). 18 | 19 | 20 | function bboxes = tiny_face_detector(image_path, output_path, prob_thresh, nms_thresh, gpu_id) 21 | 22 | if nargin < 1 || isempty(image_path) 23 | image_path = 'data/demo/selfie.jpg'; 24 | end 25 | % if nargin < 2 || isempty(output_path) 26 | if nargin < 2 27 | output_path = './selfie.png'; 28 | end 29 | if nargin < 3 30 | prob_thresh = 0.5; 31 | end 32 | if nargin < 4 33 | nms_thresh = 0.1; 34 | end 35 | if nargin < 5 36 | gpu_id = 0; % 0 means no use of GPU (matconvnet starts with 1) 37 | end 38 | 39 | addpath matconvnet; 40 | addpath matconvnet/matlab; 41 | vl_setupnn; 42 | 43 | addpath utils; 44 | addpath toolbox/nms; 45 | addpath toolbox/export_fig; 46 | 47 | % 48 | MAX_INPUT_DIM = 5000; 49 | MAX_DISP_DIM = 3000; 50 | 51 | % specify pretrained model (download if needed) 52 | model_dir = './trained_models'; 53 | if ~exist(model_dir) 54 | mkdir(model_dir); 55 | end 56 | model_path = fullfile(model_dir, 'hr_res101.mat'); 57 | if ~exist(model_path) 58 | url = 'https://www.cs.cmu.edu/~peiyunh/tiny/hr_res101.mat'; 59 | cmd = ['wget -O ' model_path ' ' url]; 60 | system(cmd); 61 | end 62 | 63 | % loadng pretrained model (and some final touches) 64 | fprintf('Loading pretrained detector model...\n'); 65 | net = load(model_path); 66 | net = dagnn.DagNN.loadobj(net.net); 67 | net.mode = 'test'; 68 | if gpu_id > 0 % for matconvnet it starts with 1 69 | gpuDevice(gpu_id); 70 | net.move('gpu'); 71 | end 72 | net.layers(net.getLayerIndex('score4')).block.crop = [1,2,1,2]; 73 | net.addLayer('cropx',dagnn.Crop('crop',[0 0]),... 74 | {'score_res3', 'score4'}, 'score_res3c'); 75 | net.setLayerInputs('fusex', {'score_res3c', 'score4'}); 76 | net.addLayer('prob_cls', dagnn.Sigmoid(), 'score_cls', 'prob_cls'); 77 | averageImage = reshape(net.meta.normalization.averageImage,1,1,3); 78 | 79 | % reference boxes of templates 80 | clusters = net.meta.clusters; 81 | clusters_h = clusters(:,4) - clusters(:,2) + 1; 82 | clusters_w = clusters(:,3) - clusters(:,1) + 1; 83 | normal_idx = find(clusters(:,5) == 1); 84 | 85 | % by default, we look at three resolutions (.5X, 1X, 2X) 86 | %scales = [-1 0 1]; % update: adapt to image resolution (see below) 87 | 88 | % initialize output 89 | bboxes = []; 90 | 91 | % load input 92 | t1 = tic; 93 | [~,name,ext] = fileparts(image_path); 94 | try 95 | raw_img = imread(image_path); 96 | catch 97 | error(sprintf('Invalid input image path: %s', image_path)); 98 | return; 99 | end 100 | 101 | % process input at different scales 102 | raw_img = single(raw_img); 103 | [raw_h, raw_w, ~] = size(raw_img) ; 104 | min_scale = min(floor(log2(max(clusters_w(normal_idx)/raw_w))),... 105 | floor(log2(max(clusters_h(normal_idx)/raw_h)))); 106 | max_scale = min(1, -log2(max(raw_h, raw_w)/MAX_INPUT_DIM)); 107 | scales = [min_scale:0, 0.5:0.5:max_scale]; 108 | 109 | for s = 2.^scales 110 | img = imresize(raw_img, s, 'bilinear'); 111 | img = bsxfun(@minus, img, averageImage); 112 | 113 | fprintf('Processing %s at scale %f.\n', image_path, s); 114 | 115 | if strcmp(net.device, 'gpu') 116 | img = gpuArray(img); 117 | end 118 | 119 | % we don't run every template on every scale 120 | % ids of templates to ignore 121 | tids = []; 122 | if s <= 1, tids = 5:12; 123 | else, tids = [5:12 19:25]; 124 | end 125 | ignoredTids = setdiff(1:size(clusters,1), tids); 126 | 127 | % run through the net 128 | [img_h, img_w, ~] = size(img); 129 | inputs = {'data', img}; 130 | net.eval(inputs); 131 | 132 | % collect scores 133 | score_cls = gather(net.vars(net.getVarIndex('score_cls')).value); 134 | score_reg = gather(net.vars(net.getVarIndex('score_reg')).value); 135 | prob_cls = gather(net.vars(net.getVarIndex('prob_cls')).value); 136 | prob_cls(:,:,ignoredTids) = 0; 137 | 138 | % threshold for detection 139 | idx = find(prob_cls > prob_thresh); 140 | [fy,fx,fc] = ind2sub(size(prob_cls), idx); 141 | 142 | % interpret heatmap into bounding boxes 143 | cy = (fy-1)*8 - 1; cx = (fx-1)*8 - 1; 144 | ch = clusters(fc,4) - clusters(fc,2) + 1; 145 | cw = clusters(fc,3) - clusters(fc,1) + 1; 146 | 147 | % extract bounding box refinement 148 | Nt = size(clusters, 1); 149 | tx = score_reg(:,:,1:Nt); 150 | ty = score_reg(:,:,Nt+1:2*Nt); 151 | tw = score_reg(:,:,2*Nt+1:3*Nt); 152 | th = score_reg(:,:,3*Nt+1:4*Nt); 153 | 154 | % refine bounding boxes 155 | dcx = cw .* tx(idx); 156 | dcy = ch .* ty(idx); 157 | rcx = cx + dcx; 158 | rcy = cy + dcy; 159 | rcw = cw .* exp(tw(idx)); 160 | rch = ch .* exp(th(idx)); 161 | 162 | % 163 | scores = score_cls(idx); 164 | tmp_bboxes = [rcx-rcw/2, rcy-rch/2, rcx+rcw/2, rcy+rch/2]; 165 | 166 | tmp_bboxes = horzcat(tmp_bboxes ./ s, scores); 167 | 168 | bboxes = vertcat(bboxes, tmp_bboxes); 169 | end 170 | 171 | % nms 172 | ridx = nms(bboxes(:,[1:4 end]), nms_thresh); 173 | bboxes = bboxes(ridx,:); 174 | 175 | % 176 | bboxes(:,[2 4]) = max(1, min(raw_h, bboxes(:,[2 4]))); 177 | bboxes(:,[1 3]) = max(1, min(raw_w, bboxes(:,[1 3]))); 178 | 179 | % 180 | t2 = toc(t1); 181 | 182 | % visualize detection on a reasonable resolution 183 | vis_img = raw_img; 184 | vis_bbox = bboxes; 185 | if max(raw_h, raw_w) > MAX_DISP_DIM 186 | vis_scale = MAX_DISP_DIM/max(raw_h, raw_w); 187 | vis_img = imresize(raw_img, vis_scale); 188 | vis_bbox(:,1:4) = vis_bbox(:,1:4) * vis_scale; 189 | end 190 | visualize_detection(uint8(vis_img), vis_bbox, prob_thresh); 191 | 192 | % 193 | drawnow; 194 | 195 | % (optional) export figure 196 | if ~isempty(output_path) 197 | export_fig('-dpng', '-native', '-opengl', '-transparent', output_path, '-r300'); 198 | end 199 | 200 | fprintf('Detection was finished in %f seconds\n', t2); 201 | 202 | % free gpu device 203 | if gpu_id > 0 204 | gpuDevice([]); 205 | end -------------------------------------------------------------------------------- /toolbox/Shuffle.m: -------------------------------------------------------------------------------- 1 | function X = Shuffle(Arg1, Arg2, Arg3) %#ok 2 | % Random permutation of array elements 3 | % SHUFFLE works in Inplace, Index and Derange mode: 4 | % 5 | % 1. INPLACE MODE: Y = Shuffle(X, Dim) - - - - - - - - - - - - - - - - - - - - 6 | % The elements of the input array are randomly re-ordered along the specified 7 | % dimension. In opposite to X(RANDPERM(LENGTH(X)) no temporary memory is used, 8 | % such that SHUFFLE is much more efficient for large arrays. 9 | % INPUT: 10 | % X: Array of any size. Types: DOUBLE, SINGLE, CHAR, LOGICAL, 11 | % (U)INT64/32/16/8. The processed dimension must be shorter than 2^32 12 | % elements. To shuffle larger or complex arrays, use the Index mode. 13 | % Dim: Dimension to operate on. 14 | % Optional, default: [], operate on first non-singleton dimension. 15 | % OUTPUT: 16 | % Y: Array of same size and type as X, but with shuffled elements. 17 | % 18 | % 2. INDEX MODE: Index = Shuffle(N, 'index', NOut) - - - - - - - - - - - - - - 19 | % A vector of shuffled indices is created as by RANDPERM, but faster and using 20 | % the smallest possible integer type to save memory. The number of output 21 | % elements can be limited. This method works for cells, structs or complex 22 | % arrays. 23 | % INPUT: 24 | % N: Numeric scalar >= 0. 25 | % String: 'index'. 26 | % NOut: Optional, number of outputs, NOut <= N. Default: N. 27 | % OUTPUT: 28 | % Index: [1 x nOut] vector containing the shuffled elements of the vector 29 | % [1:N] vector. To limit the memory usage the smallest possible type 30 | % is used: UINT8/16/32 or INT64. 31 | % 32 | % 3. DERANGEMENT MODE: Index = Shuffle(N, 'derange', NOut) - - - - - - - - - - 33 | % Equivalent to Index mode, but all elements Index[i] ~= i. 34 | % 35 | % CONTROL COMMANDS: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 36 | % Shuffle(S, 'seed'): S is either empty, scalar or a [1 x 4] DOUBLE vector to 37 | % set the random number generator to a certain state. 4 integers between 0 38 | % and 2^32-1 are recommended for maximum entropy. If S is empty the default 39 | % seed is used. 40 | % Shuffle([], 'lock'): Lock Mex in the memory such that "clear all" does not 41 | % reset the random number generator. If the Mex was compiled with 42 | % -DAUTOLOCK it is locked automatically. 43 | % Shuffle([], 'unlock'): Unlock the Mex file to allow a recompilation. 44 | % Shuffle(): Display compiler settings and status: Fast/exact integer, accept 45 | % cell/struct, current lock status, auto-lock mode. 46 | % 47 | % EXAMPLES: 48 | % Shuffle(12345678901, 'seed'); 49 | % R = Shuffle(1:8) % [5, 8, 7, 4, 2, 6, 3, 1] 50 | % R = Shuffle('abcdefg') % 'gdfbcea' 51 | % R = Shuffle([1:4; 5:8], 2) % [3, 4, 2, 1; 8, 6, 7, 5] 52 | % I = Shuffle(8, 'index'); % UINT8([3, 6, 5, 2, 4, 7, 8, 1]) 53 | % Choose 10 different rows from a 1000 x 100 matrix: 54 | % X = rand(1000, 100); Y = X(Shuffle(1000, 'index', 10), :); 55 | % Operate on cells or complex arrays: 56 | % C = {9, 's', 1:5}; SC = C(Shuffle(numel(C), 'index')); 57 | % M = rand(3) + i * rand(3); SM = M(:, Shuffle(size(C, 2), 'index')) 58 | % 59 | % NOTES: Shuffle(X) is about 50% to 85% faster than: Y = X(randperm(numel(X)). 60 | % It uses the Knuth-shuffle algorithm, also known as Fisher-Yates-shuffle. 61 | % The random numbers are created by the cute KISS algorithm of George 62 | % Marsaglia, which has a period of about 2^124 (~10^37). 63 | % More notes in Shuffle.c. 64 | % 65 | % COMPILATION: See Shuffle.c 66 | % 67 | % Tested: Matlab 6.5, 7.7, 7.8, WinXP, 32bit 68 | % Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008 69 | % Assumed Compatibility: higher Matlab versions, Mac, Linux, 64bit 70 | % Author: Jan Simon, Heidelberg, (C) 2010-2011 j@n-simon.de 71 | % 72 | % See also RAND, RANDPERM. 73 | % FEX: 74 | 75 | % $JRev: R-m V:012 Sum:Q65/zXZqnvFX Date:07-Mar-2011 00:49:06 $ 76 | % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $ 77 | % $UnitTest: uTest_Shuffle $ 78 | % $File: Tools\GLSets\Shuffle.m $ 79 | 80 | % History see Shuffle.c 81 | 82 | % Some Matlab algorithms for the Knuth-Shuffle: -------------------------------- 83 | % They are faster than Matlab's RANDPERM methods, but the MEX is recommended! 84 | 85 | % n = numel(X); 86 | % for i = 2:n % Knuth shuffle in forward direction: 87 | % w = ceil(rand * i); % 1 <= w <= i 88 | % t = X(w); 89 | % X(w) = X(i); 90 | % X(i) = t; 91 | % end 92 | 93 | % for i = n:-1:2 % Knuth shuffle in backward direction: 94 | % w = ceil(rand * i); % 1 <= w <= i 95 | % t = X(w); 96 | % X(w) = X(i); 97 | % X(i) = t; 98 | % end 99 | 100 | % for i = 1:nOut % Limit output: 101 | % w = ceil(rand * (n - i + 1)) + (i - 1); % i <= w <= n 102 | % t = X(w); 103 | % X(w) = X(i); 104 | % X(i) = t; 105 | % end 106 | % X = X(1:nOut); 107 | 108 | error(['JSimon:', mfilename, ':NoMex'], 'Need compiled mex file!'); 109 | -------------------------------------------------------------------------------- /toolbox/Shuffle.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/toolbox/Shuffle.mexa64 -------------------------------------------------------------------------------- /toolbox/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)); 10 | 11 | -------------------------------------------------------------------------------- /toolbox/VOClabelcolormap.m: -------------------------------------------------------------------------------- 1 | % VOCLABELCOLORMAP Creates a label color map such that adjacent indices have different 2 | % colors. Useful for reading and writing index images which contain large indices, 3 | % by encoding them as RGB images. 4 | % 5 | % CMAP = VOCLABELCOLORMAP(N) creates a label color map with N entries. 6 | function cmap = labelcolormap(N) 7 | 8 | if nargin==0 9 | N=256 10 | end 11 | cmap = zeros(N,3); 12 | for i=1:N 13 | id = i-1; r=0;g=0;b=0; 14 | for j=0:7 15 | r = bitor(r, bitshift(bitget(id,1),7 - j)); 16 | g = bitor(g, bitshift(bitget(id,2),7 - j)); 17 | b = bitor(b, bitshift(bitget(id,3),7 - j)); 18 | id = bitshift(id,-3); 19 | end 20 | cmap(i,1)=r; cmap(i,2)=g; cmap(i,3)=b; 21 | end 22 | cmap = cmap / 255; 23 | -------------------------------------------------------------------------------- /toolbox/bilinear_u.m: -------------------------------------------------------------------------------- 1 | function f = bilinear_u(k, numGroups, numClasses) 2 | %BILINEAR_U Create bilinear interpolation filters 3 | % BILINEAR_U(K, NUMGROUPS, NUMCLASSES) compute a square bilinear filter 4 | % of size k for deconv layer of depth numClasses and number of groups 5 | % numGroups 6 | 7 | factor = floor((k+1)/2) ; 8 | if rem(k,2)==1 9 | center = factor ; 10 | else 11 | center = factor + 0.5 ; 12 | end 13 | C = 1:k ; 14 | if numGroups ~= numClasses 15 | f = zeros(k,k,numGroups,numClasses) ; 16 | else 17 | f = zeros(k,k,1,numClasses) ; 18 | end 19 | 20 | for i =1:numClasses 21 | if numGroups ~= numClasses 22 | index = i ; 23 | else 24 | index = 1 ; 25 | end 26 | f(:,:,index,i) = (ones(1,k) - abs(C-center)./factor)'*(ones(1,k) - abs(C-center)./(factor)); 27 | end 28 | end 29 | 30 | -------------------------------------------------------------------------------- /toolbox/enhanced_rdir.m: -------------------------------------------------------------------------------- 1 | %% RDIR Enhanced - Examples of use 2 | % 3 | % This script demonstrates how to use the different abilities of the 4 | % enhanced |rdir| function. 5 | % 6 | % Examples are based on |matlabroot| directory content. Results may vary 7 | % depending on your version of Matlab. 8 | % 9 | 10 | %% Standard use 11 | rdir([matlabroot, '\*.txt']) 12 | 13 | %% Using double wildcard ** 14 | % List |".m"| files whose name contains |"tmpl"| in all subdirectories of 15 | % |matlabroot| 16 | rdir([matlabroot, '\**\*tmpl*.m']) 17 | 18 | %% RDIR output 19 | d = rdir([matlabroot, '\**\*tmpl*.m']) 20 | 21 | %% 22 | disp(d(1)) 23 | 24 | 25 | %% Using 3rd argument to shorten output names 26 | % Remove |"C:\Program Files\"| in returned names 27 | rdir([matlabroot, '\*.txt'], '', 'C:\Program Files\') 28 | 29 | %% 30 | % Remove |matlabroot| in returned names 31 | rdir([matlabroot, '\*.txt'], '', true) 32 | 33 | %% 34 | % Optional 2nd |rdir| output indicates common path removed from each output 35 | % name 36 | [d, p] = rdir([matlabroot, '\*.txt'], '', true); 37 | 38 | fprintf('Common path : \n%s\n\n', p) 39 | 40 | disp( d(1) ) 41 | 42 | %% Using a filter with "regexp" 43 | % List |".mat"| files, then select those whose name match regular expression 44 | % |'data\d'| (ie |"data"| followed by a numeric digit) 45 | rdir([matlabroot '\toolbox\**\*.mat'], 'regexp(name, ''data\d'')', true) 46 | 47 | %% Using a function handle as filter 48 | 49 | fun = @(d) ~isempty(regexp(d.name, 'data\d')) && (d.bytes < 10*1024) 50 | 51 | rdir([matlabroot '\toolbox\**\*.mat'], fun, true) 52 | 53 | %% Specific display - No item matching filter 54 | % When some items match input path, but none match filter, a specific 55 | % message is displayed. 56 | rdir(matlabroot, 'strcmp(name, ''unknowtoolbox'')', 1) 57 | 58 | 59 | %% Specific display - Wrong filter 60 | % A warning is displayed after the non-filtered result list if entered 61 | % filter is wrong. 62 | rdir(matlabroot, 'wrong filter', 1) 63 | 64 | 65 | % EOF -------------------------------------------------------------------------------- /toolbox/factorize.m: -------------------------------------------------------------------------------- 1 | function [I,J] = factorize(N) 2 | I = []; 3 | J = []; 4 | for i = 1:N 5 | if rem(N, i) == 0 6 | I(end+1) = i; 7 | J(end+1) = N / i ; 8 | end 9 | end 10 | 11 | % 12 | d = abs(I - J); 13 | [~,v] = min(d); 14 | % 15 | I = I(v); 16 | J = J(v); 17 | -------------------------------------------------------------------------------- /toolbox/intersections.m: -------------------------------------------------------------------------------- 1 | function [x0,y0,iout,jout] = intersections(x1,y1,x2,y2,robust) 2 | %INTERSECTIONS Intersections of curves. 3 | % Computes the (x,y) locations where two curves intersect. The curves 4 | % can be broken with NaNs or have vertical segments. 5 | % 6 | % Example: 7 | % [X0,Y0] = intersections(X1,Y1,X2,Y2,ROBUST); 8 | % 9 | % where X1 and Y1 are equal-length vectors of at least two points and 10 | % represent curve 1. Similarly, X2 and Y2 represent curve 2. 11 | % X0 and Y0 are column vectors containing the points at which the two 12 | % curves intersect. 13 | % 14 | % ROBUST (optional) set to 1 or true means to use a slight variation of the 15 | % algorithm that might return duplicates of some intersection points, and 16 | % then remove those duplicates. The default is true, but since the 17 | % algorithm is slightly slower you can set it to false if you know that 18 | % your curves don't intersect at any segment boundaries. Also, the robust 19 | % version properly handles parallel and overlapping segments. 20 | % 21 | % The algorithm can return two additional vectors that indicate which 22 | % segment pairs contain intersections and where they are: 23 | % 24 | % [X0,Y0,I,J] = intersections(X1,Y1,X2,Y2,ROBUST); 25 | % 26 | % For each element of the vector I, I(k) = (segment number of (X1,Y1)) + 27 | % (how far along this segment the intersection is). For example, if I(k) = 28 | % 45.25 then the intersection lies a quarter of the way between the line 29 | % segment connecting (X1(45),Y1(45)) and (X1(46),Y1(46)). Similarly for 30 | % the vector J and the segments in (X2,Y2). 31 | % 32 | % You can also get intersections of a curve with itself. Simply pass in 33 | % only one curve, i.e., 34 | % 35 | % [X0,Y0] = intersections(X1,Y1,ROBUST); 36 | % 37 | % where, as before, ROBUST is optional. 38 | 39 | % Version: 1.12, 27 January 2010 40 | % Author: Douglas M. Schwarz 41 | % Email: dmschwarz=ieee*org, dmschwarz=urgrad*rochester*edu 42 | % Real_email = regexprep(Email,{'=','*'},{'@','.'}) 43 | 44 | 45 | % Theory of operation: 46 | % 47 | % Given two line segments, L1 and L2, 48 | % 49 | % L1 endpoints: (x1(1),y1(1)) and (x1(2),y1(2)) 50 | % L2 endpoints: (x2(1),y2(1)) and (x2(2),y2(2)) 51 | % 52 | % we can write four equations with four unknowns and then solve them. The 53 | % four unknowns are t1, t2, x0 and y0, where (x0,y0) is the intersection of 54 | % L1 and L2, t1 is the distance from the starting point of L1 to the 55 | % intersection relative to the length of L1 and t2 is the distance from the 56 | % starting point of L2 to the intersection relative to the length of L2. 57 | % 58 | % So, the four equations are 59 | % 60 | % (x1(2) - x1(1))*t1 = x0 - x1(1) 61 | % (x2(2) - x2(1))*t2 = x0 - x2(1) 62 | % (y1(2) - y1(1))*t1 = y0 - y1(1) 63 | % (y2(2) - y2(1))*t2 = y0 - y2(1) 64 | % 65 | % Rearranging and writing in matrix form, 66 | % 67 | % [x1(2)-x1(1) 0 -1 0; [t1; [-x1(1); 68 | % 0 x2(2)-x2(1) -1 0; * t2; = -x2(1); 69 | % y1(2)-y1(1) 0 0 -1; x0; -y1(1); 70 | % 0 y2(2)-y2(1) 0 -1] y0] -y2(1)] 71 | % 72 | % Let's call that A*T = B. We can solve for T with T = A\B. 73 | % 74 | % Once we have our solution we just have to look at t1 and t2 to determine 75 | % whether L1 and L2 intersect. If 0 <= t1 < 1 and 0 <= t2 < 1 then the two 76 | % line segments cross and we can include (x0,y0) in the output. 77 | % 78 | % In principle, we have to perform this computation on every pair of line 79 | % segments in the input data. This can be quite a large number of pairs so 80 | % we will reduce it by doing a simple preliminary check to eliminate line 81 | % segment pairs that could not possibly cross. The check is to look at the 82 | % smallest enclosing rectangles (with sides parallel to the axes) for each 83 | % line segment pair and see if they overlap. If they do then we have to 84 | % compute t1 and t2 (via the A\B computation) to see if the line segments 85 | % cross, but if they don't then the line segments cannot cross. In a 86 | % typical application, this technique will eliminate most of the potential 87 | % line segment pairs. 88 | 89 | 90 | % Input checks. 91 | error(nargchk(2,5,nargin)) 92 | 93 | % Adjustments when fewer than five arguments are supplied. 94 | switch nargin 95 | case 2 96 | robust = true; 97 | x2 = x1; 98 | y2 = y1; 99 | self_intersect = true; 100 | case 3 101 | robust = x2; 102 | x2 = x1; 103 | y2 = y1; 104 | self_intersect = true; 105 | case 4 106 | robust = true; 107 | self_intersect = false; 108 | case 5 109 | self_intersect = false; 110 | end 111 | 112 | % x1 and y1 must be vectors with same number of points (at least 2). 113 | if sum(size(x1) > 1) ~= 1 || sum(size(y1) > 1) ~= 1 || ... 114 | length(x1) ~= length(y1) 115 | error('X1 and Y1 must be equal-length vectors of at least 2 points.') 116 | end 117 | % x2 and y2 must be vectors with same number of points (at least 2). 118 | if sum(size(x2) > 1) ~= 1 || sum(size(y2) > 1) ~= 1 || ... 119 | length(x2) ~= length(y2) 120 | error('X2 and Y2 must be equal-length vectors of at least 2 points.') 121 | end 122 | 123 | 124 | % Force all inputs to be column vectors. 125 | x1 = x1(:); 126 | y1 = y1(:); 127 | x2 = x2(:); 128 | y2 = y2(:); 129 | 130 | % Compute number of line segments in each curve and some differences we'll 131 | % need later. 132 | n1 = length(x1) - 1; 133 | n2 = length(x2) - 1; 134 | xy1 = [x1 y1]; 135 | xy2 = [x2 y2]; 136 | dxy1 = diff(xy1); 137 | dxy2 = diff(xy2); 138 | 139 | % Determine the combinations of i and j where the rectangle enclosing the 140 | % i'th line segment of curve 1 overlaps with the rectangle enclosing the 141 | % j'th line segment of curve 2. 142 | [i,j] = find(repmat(min(x1(1:end-1),x1(2:end)),1,n2) <= ... 143 | repmat(max(x2(1:end-1),x2(2:end)).',n1,1) & ... 144 | repmat(max(x1(1:end-1),x1(2:end)),1,n2) >= ... 145 | repmat(min(x2(1:end-1),x2(2:end)).',n1,1) & ... 146 | repmat(min(y1(1:end-1),y1(2:end)),1,n2) <= ... 147 | repmat(max(y2(1:end-1),y2(2:end)).',n1,1) & ... 148 | repmat(max(y1(1:end-1),y1(2:end)),1,n2) >= ... 149 | repmat(min(y2(1:end-1),y2(2:end)).',n1,1)); 150 | 151 | % Force i and j to be column vectors, even when their length is zero, i.e., 152 | % we want them to be 0-by-1 instead of 0-by-0. 153 | i = reshape(i,[],1); 154 | j = reshape(j,[],1); 155 | 156 | % Find segments pairs which have at least one vertex = NaN and remove them. 157 | % This line is a fast way of finding such segment pairs. We take 158 | % advantage of the fact that NaNs propagate through calculations, in 159 | % particular subtraction (in the calculation of dxy1 and dxy2, which we 160 | % need anyway) and addition. 161 | % At the same time we can remove redundant combinations of i and j in the 162 | % case of finding intersections of a line with itself. 163 | if self_intersect 164 | remove = isnan(sum(dxy1(i,:) + dxy2(j,:),2)) | j <= i + 1; 165 | else 166 | remove = isnan(sum(dxy1(i,:) + dxy2(j,:),2)); 167 | end 168 | i(remove) = []; 169 | j(remove) = []; 170 | 171 | % Initialize matrices. We'll put the T's and B's in matrices and use them 172 | % one column at a time. AA is a 3-D extension of A where we'll use one 173 | % plane at a time. 174 | n = length(i); 175 | T = zeros(4,n); 176 | AA = zeros(4,4,n); 177 | AA([1 2],3,:) = -1; 178 | AA([3 4],4,:) = -1; 179 | AA([1 3],1,:) = dxy1(i,:).'; 180 | AA([2 4],2,:) = dxy2(j,:).'; 181 | B = -[x1(i) x2(j) y1(i) y2(j)].'; 182 | 183 | % Loop through possibilities. Trap singularity warning and then use 184 | % lastwarn to see if that plane of AA is near singular. Process any such 185 | % segment pairs to determine if they are colinear (overlap) or merely 186 | % parallel. That test consists of checking to see if one of the endpoints 187 | % of the curve 2 segment lies on the curve 1 segment. This is done by 188 | % checking the cross product 189 | % 190 | % (x1(2),y1(2)) - (x1(1),y1(1)) x (x2(2),y2(2)) - (x1(1),y1(1)). 191 | % 192 | % If this is close to zero then the segments overlap. 193 | 194 | % If the robust option is false then we assume no two segment pairs are 195 | % parallel and just go ahead and do the computation. If A is ever singular 196 | % a warning will appear. This is faster and obviously you should use it 197 | % only when you know you will never have overlapping or parallel segment 198 | % pairs. 199 | 200 | if robust 201 | overlap = false(n,1); 202 | warning_state = warning('off','MATLAB:singularMatrix'); 203 | % Use try-catch to guarantee original warning state is restored. 204 | try 205 | lastwarn('') 206 | for k = 1:n 207 | T(:,k) = AA(:,:,k)\B(:,k); 208 | [unused,last_warn] = lastwarn; 209 | lastwarn('') 210 | if strcmp(last_warn,'MATLAB:singularMatrix') 211 | % Force in_range(k) to be false. 212 | T(1,k) = NaN; 213 | % Determine if these segments overlap or are just parallel. 214 | overlap(k) = rcond([dxy1(i(k),:);xy2(j(k),:) - xy1(i(k),:)]) < eps; 215 | end 216 | end 217 | warning(warning_state) 218 | catch err 219 | warning(warning_state) 220 | rethrow(err) 221 | end 222 | % Find where t1 and t2 are between 0 and 1 and return the corresponding 223 | % x0 and y0 values. 224 | in_range = (T(1,:) >= 0 & T(2,:) >= 0 & T(1,:) <= 1 & T(2,:) <= 1).'; 225 | % For overlapping segment pairs the algorithm will return an 226 | % intersection point that is at the center of the overlapping region. 227 | if any(overlap) 228 | ia = i(overlap); 229 | ja = j(overlap); 230 | % set x0 and y0 to middle of overlapping region. 231 | T(3,overlap) = (max(min(x1(ia),x1(ia+1)),min(x2(ja),x2(ja+1))) + ... 232 | min(max(x1(ia),x1(ia+1)),max(x2(ja),x2(ja+1)))).'/2; 233 | T(4,overlap) = (max(min(y1(ia),y1(ia+1)),min(y2(ja),y2(ja+1))) + ... 234 | min(max(y1(ia),y1(ia+1)),max(y2(ja),y2(ja+1)))).'/2; 235 | selected = in_range | overlap; 236 | else 237 | selected = in_range; 238 | end 239 | xy0 = T(3:4,selected).'; 240 | 241 | % Remove duplicate intersection points. 242 | [xy0,index] = unique(xy0,'rows'); 243 | x0 = xy0(:,1); 244 | y0 = xy0(:,2); 245 | 246 | % Compute how far along each line segment the intersections are. 247 | if nargout > 2 248 | sel_index = find(selected); 249 | sel = sel_index(index); 250 | iout = i(sel) + T(1,sel).'; 251 | jout = j(sel) + T(2,sel).'; 252 | end 253 | else % non-robust option 254 | for k = 1:n 255 | [L,U] = lu(AA(:,:,k)); 256 | T(:,k) = U\(L\B(:,k)); 257 | end 258 | 259 | % Find where t1 and t2 are between 0 and 1 and return the corresponding 260 | % x0 and y0 values. 261 | in_range = (T(1,:) >= 0 & T(2,:) >= 0 & T(1,:) < 1 & T(2,:) < 1).'; 262 | x0 = T(3,in_range).'; 263 | y0 = T(4,in_range).'; 264 | 265 | % Compute how far along each line segment the intersections are. 266 | if nargout > 2 267 | iout = i(in_range) + T(1,in_range).'; 268 | jout = j(in_range) + T(2,in_range).'; 269 | end 270 | end 271 | 272 | % Plot the results (useful for debugging). 273 | % plot(x1,y1,x2,y2,x0,y0,'ok'); 274 | -------------------------------------------------------------------------------- /toolbox/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Thomas Vanaret 2 | Copyright (c) 2009, Gus Brown 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in 13 | the documentation and/or other materials provided with the distribution 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /toolbox/nms/nms.m: -------------------------------------------------------------------------------- 1 | function pick = nms(boxes, overlap, use_gpu) 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 | if ~exist('use_gpu', 'var') 26 | use_gpu = false; 27 | end 28 | 29 | if use_gpu 30 | s = boxes(:, end); 31 | if ~issorted(s(end:-1:1)) 32 | [~, I] = sort(s, 'descend'); 33 | boxes = boxes(I, :); 34 | pick = nms_gpu_mex(single(boxes)', double(overlap)); 35 | pick = I(pick); 36 | else 37 | pick = nms_gpu_mex(single(boxes)', double(overlap)); 38 | end 39 | return; 40 | end 41 | 42 | if size(boxes, 1) < 1000000 43 | pick = nms_mex(double(boxes), double(overlap)); 44 | return; 45 | end 46 | 47 | x1 = boxes(:,1); 48 | y1 = boxes(:,2); 49 | x2 = boxes(:,3); 50 | y2 = boxes(:,4); 51 | s = boxes(:,end); 52 | 53 | area = (x2-x1+1) .* (y2-y1+1); 54 | [vals, I] = sort(s); 55 | 56 | pick = s*0; 57 | counter = 1; 58 | while ~isempty(I) 59 | last = length(I); 60 | i = I(last); 61 | pick(counter) = i; 62 | counter = counter + 1; 63 | 64 | xx1 = max(x1(i), x1(I(1:last-1))); 65 | yy1 = max(y1(i), y1(I(1:last-1))); 66 | xx2 = min(x2(i), x2(I(1:last-1))); 67 | yy2 = min(y2(i), y2(I(1:last-1))); 68 | 69 | w = max(0.0, xx2-xx1+1); 70 | h = max(0.0, yy2-yy1+1); 71 | 72 | inter = w.*h; 73 | o = inter ./ (area(i) + area(I(1:last-1)) - inter); 74 | 75 | I = I(find(o<=overlap)); 76 | end 77 | 78 | pick = pick(1:(counter-1)); 79 | -------------------------------------------------------------------------------- /toolbox/nms/nms_gpu_mex.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Example of how to use the mxGPUArray API in a MEX file. This example shows 3 | * how to write a MEX function that takes a gpuArray input and returns a 4 | * gpuArray output, e.g. B=mexFunction(A). 5 | * 6 | * Copyright 2012 The MathWorks, Inc. 7 | */ 8 | 9 | #include "mex.h" 10 | #include 11 | #include 12 | 13 | #define DIVUP(m,n) ((m)/(n)+((m)%(n)>0)) 14 | int const threadsPerBlock = (sizeof(unsigned long long) * 8); 15 | 16 | /* 17 | * Device code 18 | */ 19 | __device__ inline float devIoU(float const * const a, float const * const b) 20 | { 21 | float left = max(a[0], b[0]), right = min(a[2], b[2]); 22 | float top = max(a[1], b[1]), bottom = min(a[3], b[3]); 23 | float width = max(right - left + 1, 0.f), height = max(bottom - top + 1, 0.f); 24 | float interS = width * height; 25 | float Sa = (a[2] - a[0] + 1) * (a[3] - a[1] + 1); 26 | float Sb = (b[2] - b[0] + 1) * (b[3] - b[1] + 1); 27 | return interS / (Sa + Sb - interS); 28 | } 29 | 30 | __global__ void nms_kernel(const int n_boxes, const float nms_overlap_thres, const float *dev_boxes, unsigned long long *dev_mask) 31 | { 32 | const int row_start = blockIdx.y, col_start = blockIdx.x; 33 | const int row_size = min(n_boxes - row_start * threadsPerBlock, threadsPerBlock), col_size = min(n_boxes - col_start * threadsPerBlock, threadsPerBlock); 34 | 35 | //if (row_start > col_start) return; 36 | 37 | __shared__ float block_boxes[threadsPerBlock * 5]; 38 | if (threadIdx.x < col_size) 39 | { 40 | block_boxes[threadIdx.x * 5 + 0] = dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 0]; 41 | block_boxes[threadIdx.x * 5 + 1] = dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 1]; 42 | block_boxes[threadIdx.x * 5 + 2] = dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 2]; 43 | block_boxes[threadIdx.x * 5 + 3] = dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 3]; 44 | block_boxes[threadIdx.x * 5 + 4] = dev_boxes[(threadsPerBlock * col_start + threadIdx.x) * 5 + 4]; 45 | } 46 | __syncthreads(); 47 | 48 | if (threadIdx.x < row_size) 49 | { 50 | const int cur_box_idx = threadsPerBlock * row_start + threadIdx.x; 51 | const float *cur_box = dev_boxes + cur_box_idx * 5; 52 | int i = 0; 53 | unsigned long long t = 0; 54 | int start = 0; 55 | if (row_start == col_start) start = threadIdx.x + 1; 56 | for (i = start; i < col_size; i++) 57 | { 58 | if (devIoU(cur_box, block_boxes + i * 5) > nms_overlap_thres) 59 | { 60 | t |= 1ULL << i; 61 | } 62 | } 63 | const int col_blocks = DIVUP(n_boxes, threadsPerBlock); 64 | dev_mask[cur_box_idx * col_blocks + col_start] = t; 65 | } 66 | } 67 | 68 | /* 69 | * Host code 70 | */ 71 | void mexFunction(int nlhs, mxArray *plhs[], 72 | int nrhs, const mxArray *prhs[]) 73 | { 74 | 75 | /* Declare all variables.*/ 76 | mxArray const *boxes, *ov_thres; 77 | float *boxes_host = NULL; 78 | float *boxes_dev = NULL; 79 | unsigned long long *mask_dev = NULL; 80 | 81 | /* Throw an error if the input is not a array. */ 82 | if (nrhs != 2) { 83 | mexErrMsgTxt("nms_gpu_mex::need 2 inputs"); 84 | } 85 | 86 | boxes = prhs[0]; 87 | if (mxGetClassID(boxes) != mxSINGLE_CLASS) { 88 | mexErrMsgTxt("nms_gpu_mex::input boxes must be single"); 89 | } 90 | 91 | ov_thres = prhs[1]; 92 | if (mxGetClassID(ov_thres) != mxDOUBLE_CLASS) { 93 | mexErrMsgTxt("nms_gpu_mex::input boxes must be double"); 94 | } 95 | 96 | float nms_overlap_thres = (float)mxGetScalar(ov_thres); 97 | 98 | int boxes_dim = mxGetM(boxes); 99 | int boxes_num = mxGetN(boxes); 100 | if (boxes_dim != 5) 101 | { 102 | mexErrMsgTxt("nms_gpu_mex::input boxes's row must be 5"); 103 | } 104 | 105 | boxes_host = (float *)(mxGetPr(boxes)); 106 | const int col_blocks = DIVUP(boxes_num, threadsPerBlock); 107 | 108 | cudaMalloc(&boxes_dev, mxGetNumberOfElements(boxes) * sizeof(float)); 109 | cudaMemcpy(boxes_dev, boxes_host, mxGetNumberOfElements(boxes) * sizeof(float), cudaMemcpyHostToDevice); 110 | 111 | /* Create a GPUArray to hold the result and get its underlying pointer. */ 112 | cudaMalloc(&mask_dev, boxes_num * col_blocks * sizeof(unsigned long long)); 113 | 114 | 115 | /* 116 | * Call the kernel using the CUDA runtime API. We are using a 1-d grid here, 117 | * and it would be possible for the number of elements to be too large for 118 | * the grid. For this example we are not guarding against this possibility. 119 | */ 120 | 121 | dim3 blocks(DIVUP(boxes_num, threadsPerBlock), DIVUP(boxes_num, threadsPerBlock)); 122 | dim3 threads(threadsPerBlock); 123 | nms_kernel << > >(boxes_num, nms_overlap_thres, boxes_dev, mask_dev); 124 | 125 | std::vector mask_host(boxes_num * col_blocks); 126 | cudaMemcpy(&mask_host[0], mask_dev, sizeof(unsigned long long) * boxes_num * col_blocks, cudaMemcpyDeviceToHost); 127 | 128 | std::vector remv(col_blocks); 129 | memset(&remv[0], 0, sizeof(unsigned long long) * col_blocks); 130 | 131 | std::vector keep; 132 | keep.reserve(boxes_num); 133 | for (int i = 0; i < boxes_num; i++) 134 | { 135 | int nblock = i / threadsPerBlock; 136 | int inblock = i % threadsPerBlock; 137 | 138 | if (!(remv[nblock] & (1ULL << inblock))) 139 | { 140 | keep.push_back(i + 1); // to matlab's index 141 | 142 | unsigned long long *p = &mask_host[0] + i * col_blocks; 143 | for (int j = nblock; j < col_blocks; j++) 144 | { 145 | remv[j] |= p[j]; 146 | } 147 | } 148 | } 149 | 150 | /* Wrap the result up as a MATLAB cpuArray for return. */ 151 | mwSize dims[4] = { (int)keep.size(), 1, 1, 1 }; 152 | plhs[0] = mxCreateNumericArray(4, dims, mxINT32_CLASS, mxREAL); 153 | 154 | int *output = (int *)(mxGetPr(plhs[0])); 155 | memcpy(output, &keep[0], (int)keep.size() * sizeof(int)); 156 | 157 | 158 | cudaFree(boxes_dev); 159 | cudaFree(mask_dev); 160 | } 161 | -------------------------------------------------------------------------------- /toolbox/nms/nms_gpu_mex.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/toolbox/nms/nms_gpu_mex.mexa64 -------------------------------------------------------------------------------- /toolbox/nms/nms_gpu_mex.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/toolbox/nms/nms_gpu_mex.o -------------------------------------------------------------------------------- /toolbox/nms/nms_mex.cpp: -------------------------------------------------------------------------------- 1 | #include "mex.h" 2 | #ifdef _MSC_VER 3 | #include 4 | #include 5 | #endif 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | struct score { 11 | double s; 12 | int idx; 13 | bool operator() (score i, score j) { return (i.idx < j.idx);} 14 | } score; 15 | 16 | template 17 | void nms(const mxArray *input_boxes, double overlap, vector &vPick, int &nPick) 18 | { 19 | int nSample = (int)mxGetM(input_boxes); 20 | int nDim_boxes = (int)mxGetN(input_boxes); 21 | 22 | T *pBoxes = (T*)mxGetData(input_boxes); 23 | 24 | vector vArea(nSample); 25 | for (int i = 0; i < nSample; ++i) 26 | { 27 | vArea[i] = double(pBoxes[2*nSample + i] - pBoxes[0*nSample + i] + 1) 28 | * (pBoxes[3*nSample + i] - pBoxes[1*nSample + i] + 1); 29 | if (vArea[i] < 0) 30 | mexErrMsgTxt("Boxes area must >= 0"); 31 | } 32 | 33 | std::multimap scores; 34 | for (int i = 0; i < nSample; ++i) 35 | scores.insert(std::pair(pBoxes[4*nSample + i], i)); 36 | 37 | nPick = 0; 38 | 39 | do 40 | { 41 | int last = scores.rbegin()->second; 42 | vPick[nPick] = last; 43 | nPick += 1; 44 | 45 | for (typename std::multimap::iterator it = scores.begin(); it != scores.end();) 46 | { 47 | int it_idx = it->second; 48 | T xx1 = max(pBoxes[0*nSample + last], pBoxes[0*nSample + it_idx]); 49 | T yy1 = max(pBoxes[1*nSample + last], pBoxes[1*nSample + it_idx]); 50 | T xx2 = min(pBoxes[2*nSample + last], pBoxes[2*nSample + it_idx]); 51 | T yy2 = min(pBoxes[3*nSample + last], pBoxes[3*nSample + it_idx]); 52 | 53 | double w = max(T(0.0), xx2-xx1+1), h = max(T(0.0), yy2-yy1+1); 54 | 55 | double ov = w*h / (vArea[last] + vArea[it_idx] - w*h); 56 | 57 | if (ov > overlap) 58 | { 59 | it = scores.erase(it); 60 | } 61 | else 62 | { 63 | it++; 64 | } 65 | } 66 | 67 | } while (scores.size() != 0); 68 | } 69 | 70 | 71 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 72 | { 73 | if (nrhs != 2) 74 | mexErrMsgTxt("Wrong number of inputs"); 75 | if (nlhs != 1) 76 | mexErrMsgTxt("One output"); 77 | 78 | const mxArray *input_boxes = prhs[0]; 79 | if (mxGetClassID(input_boxes) != mxDOUBLE_CLASS && mxGetClassID(input_boxes) != mxSINGLE_CLASS) 80 | mexErrMsgTxt("Input boxes must be Double or Single"); 81 | 82 | const mxArray *input_overlap = prhs[1]; 83 | if (mxGetClassID(input_overlap) != mxDOUBLE_CLASS ) 84 | mexErrMsgTxt("Input overlap must be Double"); 85 | 86 | double overlap = mxGetScalar(input_overlap); 87 | 88 | int nSample = (int)mxGetM(input_boxes); 89 | int nDim_boxes = (int)mxGetN(input_boxes); 90 | 91 | if (nSample * nDim_boxes == 0) 92 | { 93 | plhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); 94 | return; 95 | } 96 | 97 | if (nDim_boxes != 5) 98 | mexErrMsgTxt("nms_mex boxes must has 5 columns"); 99 | 100 | 101 | int nPick = 0; 102 | vector vPick(nSample); 103 | if(mxGetClassID(input_boxes) == mxDOUBLE_CLASS) 104 | nms(input_boxes, overlap, vPick, nPick); 105 | else 106 | nms(input_boxes, overlap, vPick, nPick); 107 | 108 | plhs[0] = mxCreateNumericMatrix(nPick, 1, mxDOUBLE_CLASS, mxREAL); 109 | double *pRst = mxGetPr(plhs[0]); 110 | for (int i = 0; i < nPick; ++i) 111 | pRst[i] = vPick[i] + 1; 112 | } 113 | -------------------------------------------------------------------------------- /toolbox/nms/nms_mex.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/toolbox/nms/nms_mex.mexa64 -------------------------------------------------------------------------------- /toolbox/nms/nms_multiclass.m: -------------------------------------------------------------------------------- 1 | function picks = nms_multiclass(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 | picks = {}; 22 | return; 23 | end 24 | 25 | if size(boxes, 1) < 10000 26 | picks = nms_multiclass_mex(double(boxes), double(overlap)); 27 | return; 28 | end 29 | 30 | x1 = boxes(:,1); 31 | y1 = boxes(:,2); 32 | x2 = boxes(:,3); 33 | y2 = boxes(:,4); 34 | 35 | area = (x2-x1+1) .* (y2-y1+1); 36 | 37 | picks = cell(size(boxes, 2)-4, 1); 38 | for iS = 5:size(boxes, 2) 39 | s = boxes(:,iS); 40 | [~, I] = sort(s); 41 | 42 | pick = s*0; 43 | counter = 1; 44 | while ~isempty(I) 45 | last = length(I); 46 | i = I(last); 47 | pick(counter) = i; 48 | counter = counter + 1; 49 | 50 | xx1 = max(x1(i), x1(I(1:last-1))); 51 | yy1 = max(y1(i), y1(I(1:last-1))); 52 | xx2 = min(x2(i), x2(I(1:last-1))); 53 | yy2 = min(y2(i), y2(I(1:last-1))); 54 | 55 | w = max(0.0, xx2-xx1+1); 56 | h = max(0.0, yy2-yy1+1); 57 | 58 | inter = w.*h; 59 | o = inter ./ (area(i) + area(I(1:last-1)) - inter); 60 | 61 | I = I(o<=overlap); 62 | end 63 | 64 | pick = pick(1:(counter-1)); 65 | picks{iS-4} = pick; 66 | end 67 | -------------------------------------------------------------------------------- /toolbox/nms/nms_multiclass_mex.cpp: -------------------------------------------------------------------------------- 1 | #include "mex.h" 2 | #ifdef WIN32 3 | #include 4 | #include 5 | #else 6 | #include 7 | #endif 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | 13 | struct score { 14 | double s; 15 | int idx; 16 | bool operator() (score i, score j) { return (i.idx < j.idx);} 17 | } score; 18 | 19 | template 20 | void nms(const mxArray *input_boxes, int iScoreIdx, double overlap, const vector &vArea, vector &vPick, int &nPick) 21 | { 22 | int nSample = (int)mxGetM(input_boxes); 23 | int nDim_boxes = (int)mxGetN(input_boxes); 24 | 25 | T *pBoxes = (T*)mxGetData(input_boxes); 26 | 27 | //vector vArea(nSample); 28 | //for (int i = 0; i < nSample; ++i) 29 | //{ 30 | // vArea[i] = double(pBoxes[2*nSample + i] - pBoxes[0*nSample + i] + 1) 31 | // * (pBoxes[3*nSample + i] - pBoxes[1*nSample + i] + 1); 32 | // if (vArea[i] < 0) 33 | // mexErrMsgTxt("Boxes area must >= 0"); 34 | //} 35 | 36 | std::multimap scores; 37 | for (int i = 0; i < nSample; ++i) 38 | scores.insert(std::pair(pBoxes[iScoreIdx*nSample + i], i)); 39 | 40 | nPick = 0; 41 | 42 | do 43 | { 44 | int last = scores.rbegin()->second; 45 | vPick[nPick] = last; 46 | nPick += 1; 47 | 48 | for (typename std::multimap::iterator it = scores.begin(); it != scores.end();) 49 | { 50 | int it_idx = it->second; 51 | T xx1 = std::max(pBoxes[0*nSample + last], pBoxes[0*nSample + it_idx]); 52 | T yy1 = std::max(pBoxes[1*nSample + last], pBoxes[1*nSample + it_idx]); 53 | T xx2 = std::min(pBoxes[2*nSample + last], pBoxes[2*nSample + it_idx]); 54 | T yy2 = std::min(pBoxes[3*nSample + last], pBoxes[3*nSample + it_idx]); 55 | 56 | double w = max(0.0, xx2-xx1+1), h = max(0.0, yy2-yy1+1); 57 | 58 | double ov = w*h / (vArea[last] + vArea[it_idx] - w*h); 59 | 60 | if (ov > overlap) 61 | { 62 | #ifdef WIN32 63 | it = scores.erase(it); 64 | #else 65 | typename std::multimap::iterator save=it; ++save; 66 | scores.erase(it); 67 | it=save; 68 | #endif 69 | } 70 | else 71 | { 72 | it++; 73 | } 74 | } 75 | 76 | } while (scores.size() != 0); 77 | } 78 | 79 | 80 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]) 81 | { 82 | if (nrhs != 2) 83 | mexErrMsgTxt("Wrong number of inputs"); 84 | if (nlhs != 1) 85 | mexErrMsgTxt("One output"); 86 | 87 | const mxArray *input_boxes = prhs[0]; 88 | if (mxGetClassID(input_boxes) != mxDOUBLE_CLASS && mxGetClassID(input_boxes) != mxSINGLE_CLASS) 89 | mexErrMsgTxt("Input boxes must be Double or Single"); 90 | 91 | const mxArray *input_overlap = prhs[1]; 92 | if (mxGetClassID(input_overlap) != mxDOUBLE_CLASS ) 93 | mexErrMsgTxt("Input overlap must be Double"); 94 | 95 | double overlap = mxGetScalar(input_overlap); 96 | 97 | int nSample = (int)mxGetM(input_boxes); 98 | int nDim_boxes = (int)mxGetN(input_boxes); 99 | 100 | if (nSample * nDim_boxes == 0) 101 | { 102 | plhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); 103 | return; 104 | } 105 | 106 | if (nDim_boxes < 5) 107 | mexErrMsgTxt("nms_mex boxes must has least 5 columns"); 108 | 109 | vector vArea(nSample); 110 | if(mxGetClassID(input_boxes) == mxDOUBLE_CLASS) 111 | { 112 | double *pBoxes = (double*)mxGetData(input_boxes); 113 | for (int i = 0; i < nSample; ++i) 114 | { 115 | vArea[i] = double(pBoxes[2*nSample + i] - pBoxes[0*nSample + i] + 1) 116 | * (pBoxes[3*nSample + i] - pBoxes[1*nSample + i] + 1); 117 | if (vArea[i] < 0) 118 | mexErrMsgTxt("Boxes area must >= 0"); 119 | } 120 | } 121 | else 122 | { 123 | if(mxGetClassID(input_boxes) == mxDOUBLE_CLASS) 124 | { 125 | float *pBoxes = (float*)mxGetData(input_boxes); 126 | for (int i = 0; i < nSample; ++i) 127 | { 128 | vArea[i] = double(pBoxes[2*nSample + i] - pBoxes[0*nSample + i] + 1) 129 | * (pBoxes[3*nSample + i] - pBoxes[1*nSample + i] + 1); 130 | if (vArea[i] < 0) 131 | mexErrMsgTxt("Boxes area must >= 0"); 132 | } 133 | } 134 | } 135 | 136 | vector nPick(nDim_boxes - 4, 0); 137 | vector > vPicks(nDim_boxes - 4); 138 | plhs[0] = mxCreateCellMatrix_730(nDim_boxes - 4, 1); 139 | 140 | #pragma omp parallel for ordered schedule(dynamic) 141 | for (int i = 0; i < vPicks.size(); ++i) 142 | { 143 | vPicks[i].resize(nSample); 144 | 145 | if(mxGetClassID(input_boxes) == mxDOUBLE_CLASS) 146 | nms(input_boxes, i+4, overlap, vArea, vPicks[i], nPick[i]); 147 | else 148 | nms(input_boxes, i+4, overlap, vArea, vPicks[i], nPick[i]); 149 | 150 | mxArray *mxPick = mxCreateNumericMatrix(nPick[i], 1, mxDOUBLE_CLASS, mxREAL); 151 | double *pRst = mxGetPr(mxPick); 152 | for (int j = 0; j < nPick[i]; ++j) 153 | pRst[j] = vPicks[i][j] + 1; 154 | 155 | mxSetCell(plhs[0], i, mxPick); 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /toolbox/nms/nvmex.m: -------------------------------------------------------------------------------- 1 | function nvmex(cuFileName, outDir) 2 | %NVMEX Compiles and links a CUDA file for MATLAB usage 3 | % NVMEX(FILENAME) will create a MEX-File (also with the name FILENAME) by 4 | % invoking the CUDA compiler, nvcc, and then linking with the MEX 5 | % function in MATLAB. 6 | 7 | if ispc % Windows 8 | Host_Compiler_Location = '-ccbin "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\x86_amd64"'; 9 | CUDA_INC_Location = ['"' getenv('CUDA_PATH') '\include"']; 10 | CUDA_SAMPLES_Location =['"' getenv('NVCUDASAMPLES6_5_ROOT') '\common\inc"']; 11 | PIC_Option = ''; 12 | if ( strcmp(computer('arch'),'win32') ==1) 13 | machine_str = ' --machine 32 '; 14 | CUDA_LIB_Location = ['"' getenv('CUDA_PATH') '\lib\Win32"']; 15 | elseif ( strcmp(computer('arch'),'win64') ==1) 16 | machine_str = ' --machine 64 '; 17 | CUDA_LIB_Location = ['"' getenv('CUDA_PATH') '\lib\x64"']; 18 | end 19 | NVCC = 'nvcc'; 20 | else % Mac and Linux (assuming gcc is on the path) 21 | CUDA_INC_Location = '/usr/local/cuda/include'; 22 | CUDA_SAMPLES_Location = '/usr/local/cuda/samples/common/inc'; 23 | Host_Compiler_Location = ' '; 24 | PIC_Option = ' --compiler-options -fPIC '; 25 | machine_str = []; 26 | CUDA_LIB_Location = '/usr/local/cuda/lib64'; 27 | NVCC = '/usr/local/cuda/bin/nvcc'; 28 | end 29 | % !!! End of things to modify !!! 30 | [~, filename] = fileparts(cuFileName); 31 | nvccCommandLine = [ ... 32 | NVCC ' --compile ' Host_Compiler_Location ' ' ... 33 | '-o ' filename '.o ' ... 34 | machine_str PIC_Option ... 35 | ' -I' '"' matlabroot '/extern/include "' ... 36 | ' -I' CUDA_INC_Location ' -I' CUDA_SAMPLES_Location ... 37 | ' "' cuFileName '" ' 38 | ]; 39 | mexCommandLine = ['mex ' '-outdir ' outDir ' ' filename '.o' ' -L' CUDA_LIB_Location ' -lcudart']; 40 | disp(nvccCommandLine); 41 | warning off; 42 | status = system(nvccCommandLine); 43 | warning on; 44 | if status < 0 45 | error 'Error invoking nvcc'; 46 | end 47 | disp(mexCommandLine); 48 | eval(mexCommandLine); 49 | end 50 | -------------------------------------------------------------------------------- /toolbox/nms_matlab.m: -------------------------------------------------------------------------------- 1 | function pick = nms_matlab(boxes, overlap) 2 | % top = nms_fast(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 | % NOTE: This is adapted from Pedro Felzenszwalb's version (nms.m), 8 | % but an inner loop has been eliminated to significantly speed it 9 | % up in the case of a large number of boxes 10 | % Tomasz Malisiewicz (tomasz@cmu.edu) 11 | 12 | if isempty(boxes) 13 | pick = []; 14 | return; 15 | end 16 | 17 | x1 = boxes(:,1); 18 | y1 = boxes(:,2); 19 | x2 = boxes(:,3); 20 | y2 = boxes(:,4); 21 | s = boxes(:,end); 22 | 23 | area = (x2-x1+1) .* (y2-y1+1); 24 | [vals, I] = sort(s); 25 | 26 | pick = s*0; 27 | counter = 1; 28 | while ~isempty(I) 29 | 30 | last = length(I); 31 | i = I(last); 32 | pick(counter) = i; 33 | counter = counter + 1; 34 | 35 | xx1 = max(x1(i), x1(I(1:last-1))); 36 | yy1 = max(y1(i), y1(I(1:last-1))); 37 | xx2 = min(x2(i), x2(I(1:last-1))); 38 | yy2 = min(y2(i), y2(I(1:last-1))); 39 | 40 | w = max(0.0, xx2-xx1+1); 41 | h = max(0.0, yy2-yy1+1); 42 | 43 | o = w.*h ./ area(I(1:last-1)); 44 | 45 | I([last; find(o>overlap)]) = []; 46 | end 47 | 48 | pick = pick(1:(counter-1)); 49 | -------------------------------------------------------------------------------- /toolbox/plotEllipses.m: -------------------------------------------------------------------------------- 1 | function h=plotEllipse(ra,rb,ang,x0,y0,C,Nb) 2 | % Ellipse adds ellipses to the current plot 3 | % 4 | % ELLIPSE(ra,rb,ang,x0,y0) adds an ellipse with semimajor axis of ra, 5 | % a semimajor axis of radius rb, a semimajor axis of ang, centered at 6 | % the point x0,y0. 7 | % 8 | % The length of ra, rb, and ang should be the same. 9 | % If ra is a vector of length L and x0,y0 scalars, L ellipses 10 | % are added at point x0,y0. 11 | % If ra is a scalar and x0,y0 vectors of length M, M ellipse are with the same 12 | % radii are added at the points x0,y0. 13 | % If ra, x0, y0 are vectors of the same length L=M, M ellipses are added. 14 | % If ra is a vector of length L and x0, y0 are vectors of length 15 | % M~=L, L*M ellipses are added, at each point x0,y0, L ellipses of radius ra. 16 | % 17 | % ELLIPSE(ra,rb,ang,x0,y0,C) 18 | % adds ellipses of color C. C may be a string ('r','b',...) or the RGB value. 19 | % If no color is specified, it makes automatic use of the colors specified by 20 | % the axes ColorOrder property. For several circles C may be a vector. 21 | % 22 | % ELLIPSE(ra,rb,ang,x0,y0,C,Nb), Nb specifies the number of points 23 | % used to draw the ellipse. The default value is 300. Nb may be used 24 | % for each ellipse individually. 25 | % 26 | % h=ELLIPSE(...) returns the handles to the ellipses. 27 | % 28 | % as a sample of how ellipse works, the following produces a red ellipse 29 | % tipped up at a 45 deg axis from the x axis 30 | % ellipse(1,2,pi/8,1,1,'r') 31 | % 32 | % note that if ra=rb, ELLIPSE plots a circle 33 | % 34 | 35 | % written by D.G. Long, Brigham Young University, based on the 36 | % CIRCLES.m original 37 | % written by Peter Blattner, Institute of Microtechnology, University of 38 | % Neuchatel, Switzerland, blattner@imt.unine.ch 39 | 40 | 41 | % Check the number of input arguments 42 | 43 | if nargin<1, 44 | ra=[]; 45 | end; 46 | if nargin<2, 47 | rb=[]; 48 | end; 49 | if nargin<3, 50 | ang=[]; 51 | end; 52 | 53 | %if nargin==1, 54 | % error('Not enough arguments'); 55 | %end; 56 | 57 | if nargin<5, 58 | x0=[]; 59 | y0=[]; 60 | end; 61 | 62 | if nargin<6, 63 | C=[]; 64 | end 65 | 66 | if nargin<7, 67 | Nb=[]; 68 | end 69 | 70 | % set up the default values 71 | 72 | if isempty(ra),ra=1;end; 73 | if isempty(rb),rb=1;end; 74 | if isempty(ang),ang=0;end; 75 | if isempty(x0),x0=0;end; 76 | if isempty(y0),y0=0;end; 77 | if isempty(Nb),Nb=300;end; 78 | if isempty(C),C=get(gca,'colororder');end; 79 | 80 | % work on the variable sizes 81 | 82 | x0=x0(:); 83 | y0=y0(:); 84 | ra=ra(:); 85 | rb=rb(:); 86 | ang=ang(:); 87 | Nb=Nb(:); 88 | 89 | if isstr(C),C=C(:);end; 90 | 91 | if length(ra)~=length(rb), 92 | error('length(ra)~=length(rb)'); 93 | end; 94 | if length(x0)~=length(y0), 95 | error('length(x0)~=length(y0)'); 96 | end; 97 | 98 | % how many inscribed elllipses are plotted 99 | 100 | if length(ra)~=length(x0) 101 | maxk=length(ra)*length(x0); 102 | else 103 | maxk=length(ra); 104 | end; 105 | 106 | % drawing loop 107 | 108 | for k=1:maxk 109 | 110 | if length(x0)==1 111 | xpos=x0; 112 | ypos=y0; 113 | radm=ra(k); 114 | radn=rb(k); 115 | if length(ang)==1 116 | an=ang; 117 | else 118 | an=ang(k); 119 | end; 120 | elseif length(ra)==1 121 | xpos=x0(k); 122 | ypos=y0(k); 123 | radm=ra; 124 | radn=rb; 125 | an=ang; 126 | elseif length(x0)==length(ra) 127 | xpos=x0(k); 128 | ypos=y0(k); 129 | radm=ra(k); 130 | radn=rb(k); 131 | an=ang(k) 132 | else 133 | rada=ra(fix((k-1)/size(x0,1))+1); 134 | radb=rb(fix((k-1)/size(x0,1))+1); 135 | an=ang(fix((k-1)/size(x0,1))+1); 136 | xpos=x0(rem(k-1,size(x0,1))+1); 137 | ypos=y0(rem(k-1,size(y0,1))+1); 138 | end; 139 | 140 | co=cos(an); 141 | si=sin(an); 142 | the=linspace(0,2*pi,Nb(rem(k-1,size(Nb,1))+1,:)+1); 143 | % x=radm*cos(the)*co-si*radn*sin(the)+xpos; 144 | % y=radm*cos(the)*si+co*radn*sin(the)+ypos; 145 | h(k)=line(radm*cos(the)*co-si*radn*sin(the)+xpos,radm*cos(the)*si+co*radn*sin(the)+ypos); 146 | set(h(k),'color',C(rem(k-1,size(C,1))+1,:)); 147 | 148 | end; 149 | -------------------------------------------------------------------------------- /toolbox/plotLandmarks.m: -------------------------------------------------------------------------------- 1 | function plotLandmarks(lands) 2 | [H, W, P, D] = size(pose4d); 3 | p = randsample(P,1); 4 | 5 | hold on ; 6 | cmap = hsv(H*W); 7 | for i = 1:H 8 | for j = 1:W 9 | id = (i-1)*W + j; 10 | c = cmap(id,:); 11 | x = pose4d(i,j,p,1:21); 12 | y = pose4d(i,j,p,22:42); 13 | scatter(x,y,30,'filled','MarkerFaceColor',c); 14 | 15 | x1 = min(x); 16 | y1 = min(y); 17 | x2 = max(x); 18 | y2 = max(y); 19 | rectangle('position', [x1 y1 x2-x1+1 y2-y1+1], ... 20 | 'EdgeColor', c, 'LineStyle', '--'); 21 | end 22 | end 23 | hold off; 24 | -------------------------------------------------------------------------------- /toolbox/rdir.m: -------------------------------------------------------------------------------- 1 | function [varargout] = rdir(rootdir,varargin) 2 | % RDIR - Recursive directory listing 3 | % 4 | % D = rdir(ROOT) 5 | % D = rdir(ROOT, TEST) 6 | % D = rdir(ROOT, TEST, RMPATH) 7 | % D = rdir(ROOT, TEST, 1) 8 | % D = rdir(ROOT, '', ...) 9 | % [D, P] = rdir(...) 10 | % rdir(...) 11 | % 12 | % 13 | % *Inputs* 14 | % 15 | % * ROOT 16 | % 17 | % rdir(ROOT) lists the specified files. 18 | % ROOT can be a pathname, filename, or can include both. One can use 19 | % absolute and relative pathnames and wildcards (*). Wildcard can be placed 20 | % anywhere and used many times like 'path*\*.m' 21 | % 22 | % One can also use a double wildcard (**) to match multiple directory 23 | % levels. For example ROOT = 'path\**\*.m' will match all ".m" files in 24 | % "path" and all subdirectories of "path". 25 | % 26 | % NOTE : ".svn" directories created by SubVersion (SVN) are excluded from 27 | % the recursive listing. 28 | % 29 | % * TEST 30 | % 31 | % Optional test that can be performed on the returned files. 32 | % 33 | % TEST is a string indicating expression to be evaluated on selected field 34 | % of rdir output. 35 | % All fields (ie name, date, bytes, isdir and datenum) can be used. 36 | % 37 | % Tests are strings similar to what one would use in a "if" statement e.g. 38 | % 'bytes>1024 & datenum>now-7' 39 | % 40 | % One can also use function like "regexp" or "strfind" with string fields 41 | % like "name" and "date" e.g 'regexp(name, 'expr')'. In that case, tests 42 | % that return a non empty value are considered as true. 43 | % 44 | % regexp(name, '(\.m$)|(\.mdl$)') 45 | % 46 | % Test can also be a function handle as used in arrayfun/cellfun, e.g. 47 | % @(f)f.bytes>1024 48 | % 49 | % * RMPATH 50 | % 51 | % Optional path to remove from beginning of "name" field in returned 52 | % output. Specified path must be common to all items found. 53 | % 54 | % If RMPATH = 1 or true, path to remove is part of ROOT before the first 55 | % wildcard. 56 | % 57 | % 58 | % *Outputs* 59 | % 60 | % * D 61 | % 62 | % D is a structure with the same fields as Matlab DIR output. 63 | % 64 | % The "name" field includes the relative path as well as the name to the 65 | % file that was found. Path can be shorten or ommited when using 3rd 66 | % argument RMPATH. 67 | % 68 | % * P 69 | % 70 | % Common path or RMPATH (if specified) for the file list returned in D. 71 | % 72 | % * Screen output 73 | % 74 | % If not output variable is specified then the output is sent to the 75 | % screen. 76 | % 77 | % 78 | % *Versions* 79 | % 80 | % * 1.0 - 2009, Gus Brown 81 | % * 2.0 - 26/05/2011 Thomas Vanaret 82 | % No longer exclude all directories from a simple search (no *); 83 | % Fixing bug on returned path; 84 | % Exclude ".svn" directories; 85 | % Extended test possibilies; 86 | % Subfunctions created; 87 | % * 2.1 - 14/07/2011 Thomas Vanaret 88 | % New argument allowing to remove common path from name; 89 | % Comments review; 90 | % * 2.2 - 20/12/2011 Thomas Vanaret 91 | % Fixing bug on display with 0b files; 92 | % Specific display when no file match filter; 93 | % * 2.3 - 19/01/2014 Thomas Vanaret 94 | % Adding improvements suggested by X. Mo : 95 | % - function handle as TEST input 96 | % - code optimisation (avoiding loop) 97 | % Fixing possible bug when using a wildcard at the beginning; 98 | % Common path as 2nd optionnal output; 99 | % 100 | % 101 | % *Examples* 102 | % 103 | % D = rdir('*.m'); 104 | % for ii=1:length(D), disp(D(ii).name); end; 105 | % 106 | % % to find all files in the current directory and sub directories 107 | % D = rdir('**\*') 108 | % 109 | % % If no output is specified then the files are sent to 110 | % % the screen. 111 | % rdir('c:\program files\windows *\*.exe'); 112 | % rdir('c:\program files\windows *\**\*.dll'); 113 | % 114 | % % Using the test function to find files modified today 115 | % rdir('c:\win*\*','datenum>floor(now)'); 116 | % % Using the test function to find files of a certain size 117 | % rdir('c:\program files\win*\*.exe','bytes>1024 & bytes<1048576'); 118 | % % Using the test function to find files modified in 2011 119 | % rdir('c:\win*\*','strfind(date, ''2011'')'); 120 | % 121 | % % Using the 3rd input to shorten output name 122 | % rdir([matlabroot, '\*.txt'], '', 'C:\Program Files\') 123 | % % Using the 3rd input to shorten output name 124 | % rdir([matlabroot, '\*.txt'], '', 1) 125 | % 126 | % 127 | % See also DIR 128 | % 129 | 130 | 131 | %-------------------------------------------------------------------------- 132 | %% Input validation 133 | 134 | % use the current directory if nothing is specified 135 | if ~exist('rootdir','var'), 136 | rootdir = '*'; 137 | end 138 | 139 | prepath = ''; % the path before the wild card 140 | wildpath = ''; % the path wild card 141 | postpath = rootdir; % the path after the wild card 142 | I = find(rootdir==filesep,1,'last'); 143 | 144 | % Directory separator for current platform 145 | if filesep == '\' 146 | % On PC, filesep is '\' 147 | anti_filesep = '/'; 148 | else 149 | % On UNIX system, filesep is '/' 150 | anti_filesep = '\'; 151 | end 152 | 153 | if isempty(I) && ~isempty(strfind(rootdir, anti_filesep)) 154 | error([mfilename, ':FileSep'],... 155 | 'Use correct directory separator "%s".', filesep) 156 | end 157 | 158 | 159 | %-------------------------------------------------------------------------- 160 | %% Split rootdir 161 | % split the file path around the wild card specifiers 162 | 163 | if ~isempty(I), 164 | prepath = rootdir(1:I); 165 | postpath = rootdir(I+1:end); 166 | I = find(prepath=='*',1,'first'); 167 | if ~isempty(I), 168 | postpath = [prepath(I:end) postpath]; 169 | prepath = prepath(1:I-1); 170 | I = find(prepath==filesep,1,'last'); 171 | if ~isempty(I), 172 | wildpath = prepath(I+1:end); 173 | prepath = prepath(1:I); 174 | end; 175 | I = find(postpath==filesep,1,'first'); 176 | if ~isempty(I), 177 | wildpath = [wildpath postpath(1:I-1)]; 178 | postpath = postpath(I:end); 179 | end; 180 | end; 181 | end; 182 | 183 | % disp([' "' prepath '" ~ "' wildpath '" ~ "' postpath '" ']); 184 | 185 | %-------------------------------------------------------------------------- 186 | %% Recursive listing 187 | % Search for matching files until all wildcards have been considered. 188 | 189 | if isempty(wildpath) 190 | % If no directory wildcards then just get files and directories list 191 | 192 | D = dir([prepath postpath]); 193 | 194 | % Exclude ".", ".." and ".svn" directories from the list 195 | excl = isdotdir(D) | issvndir(D); 196 | D(excl) = []; 197 | 198 | if isdir([prepath postpath]); 199 | fullpath = [prepath postpath]; 200 | else 201 | fullpath = prepath; 202 | end 203 | 204 | % Place directories on the top of the list 205 | is_dir = [D.isdir]'; 206 | D = [D(is_dir); D(~is_dir)]; 207 | 208 | % Add path before name 209 | for ii = 1:length(D) 210 | D(ii).name = fullfile(fullpath, D(ii).name); 211 | end 212 | 213 | % disp(sprintf('Scanning "%s" %g files found',[prepath postpath],length(D))); 214 | 215 | elseif strcmp(wildpath,'**') 216 | % A double wildcards directory means recurs down into sub directories 217 | 218 | % first look for files in the current directory (remove extra filesep) 219 | D = rdir([prepath postpath(2:end)]); 220 | 221 | % then look for sub directories 222 | D_sd = dir([prepath '*']); 223 | 224 | % Exclude ".", "..", ".svn" directories and files from the list 225 | excl = isdotdir(D_sd) | issvndir(D_sd) | ~([D_sd.isdir]'); 226 | D_sd(excl) = []; 227 | 228 | % Process each sub directory found 229 | % Performance tweak: avoid growing array within loop (X. Mo) 230 | c_D = arrayfun(@(x) rdir([prepath x.name filesep wildpath postpath]),... 231 | D_sd, 'UniformOutput', false); 232 | 233 | D = [D; cell2mat( c_D ) ]; 234 | 235 | else 236 | % Process directory wild card looking for sub directories that match 237 | 238 | D_sd = dir([prepath wildpath]); 239 | 240 | % Exclude ".", "..", ".svn" directories and files from the list 241 | excl = isdotdir(D_sd) | issvndir(D_sd) | ~([D_sd.isdir]'); 242 | D_sd(excl) = []; 243 | 244 | if ~isdir(prepath) || ( numel(D_sd)==1 && strcmp(D_sd.name, prepath)) 245 | % Fix case like rdir('path*\...') where prepath is not a full directoty 246 | % name OR case were prepath match a unique directory. 247 | % Previous "dir" return then the matching directory name(s). 248 | % prepath is cleaned to use them. 249 | % 250 | % In else case, prepath is a valid path which must be kept. 251 | prepath = ''; 252 | end 253 | 254 | % Process each directory found 255 | Dt = dir(''); 256 | 257 | c_D = arrayfun(@(x) rdir([prepath x.name postpath]),... 258 | D_sd, 'UniformOutput', false); 259 | 260 | D = [Dt; cell2mat( c_D ) ]; 261 | 262 | end 263 | 264 | 265 | %-------------------------------------------------------------------------- 266 | %% Apply filter 267 | % If specified, apply the filter to refine the search. 268 | 269 | nb_before_filt = length(D); 270 | warning_msg = ''; 271 | 272 | if (nargin>=2 && ~isempty(varargin{1})), 273 | try 274 | if isa(varargin{1}, 'function_handle') 275 | test_tf = arrayfun(varargin{1}, D); 276 | else 277 | test_tf = evaluate(D, varargin{1}); 278 | end 279 | 280 | D = D(test_tf); 281 | 282 | catch 283 | if isa(varargin{1}, 'function_handle') 284 | test_expr = func2str(varargin{1}); 285 | else 286 | test_expr = varargin{1}; 287 | end 288 | 289 | warning_msg = sprintf('Invalid TEST "%s" : %s', test_expr, lasterr); 290 | end 291 | end 292 | 293 | 294 | %-------------------------------------------------------------------------- 295 | %% Remove path 296 | % If specified, remove given or common path from each returned path. 297 | 298 | common_path = ''; 299 | if (nargin>=3 && ~isempty(varargin{2})), 300 | 301 | arg2 = varargin{2}; 302 | if ischar(arg2) 303 | common_path = arg2; 304 | elseif (isnumeric(arg2) || islogical(arg2)) && arg2 305 | common_path = prepath; 306 | end 307 | 308 | rm_path = regexptranslate('escape', common_path); 309 | 310 | % Check that path is common to all 311 | start = regexp({D.name}', ['^', rm_path]); 312 | 313 | % Convert to a logical. 314 | is_common = not( cellfun(@isempty, start) ); 315 | 316 | if all(is_common) 317 | for k = 1:length(D) 318 | D(k).name = regexprep(D(k).name, ['^', rm_path], ''); 319 | end 320 | 321 | else 322 | common_path = ''; 323 | end 324 | 325 | % 19/07/2012 : ajouter common_path en sortie optionnelle 326 | 327 | end 328 | 329 | 330 | %-------------------------------------------------------------------------- 331 | %% Display listing if no output variables are specified 332 | % Screen display. 333 | 334 | nout = nargout; 335 | 336 | if nout == 0 337 | if isempty(D) 338 | if nb_before_filt == 0 339 | fprintf('%s not found.\n', rootdir) 340 | else 341 | fprintf('No item matching filter.\n') 342 | end 343 | else 344 | 345 | if ~isempty(common_path) 346 | fprintf('All in : %s\n', common_path) 347 | end 348 | 349 | pp = {'' 'k' 'M' 'G' 'T'}; 350 | for ii = 1:length(D) 351 | if D(ii).isdir 352 | % Directory item : display name 353 | disp(sprintf(' %29s %-64s','',D(ii).name)); 354 | else 355 | % File item : display size, modification date and name 356 | sz = D(ii).bytes; 357 | if sz > 0 358 | ss = min(4,floor(log2(sz)/10)); 359 | else 360 | ss = 0; 361 | end 362 | disp(sprintf('%4.0f %1sb %20s %-64s ',... 363 | sz/1024^ss, pp{ss+1}, datestr(D(ii).datenum, 0), D(ii).name)); 364 | end 365 | end 366 | end 367 | elseif nout == 1 368 | % send list out 369 | varargout{1} = D; 370 | else 371 | % send list and common path out 372 | varargout{1} = D; 373 | varargout{2} = common_path; 374 | end; 375 | 376 | if ~isempty(warning_msg) 377 | warning([mfilename, ':InvalidTest'],... 378 | warning_msg); % ap aff 379 | end 380 | 381 | %---------------------------- end of main function ------------------------ 382 | 383 | 384 | %% ------------------------------------------------------------------------ 385 | function tf = issvndir(d) 386 | % True for ".svn" directories. 387 | % d is a structure returned by "dir" 388 | % 389 | 390 | is_dir = [d.isdir]'; 391 | 392 | is_svn = strcmp({d.name}, '.svn')'; 393 | %is_svn = false; % uncomment to disable ".svn" filtering 394 | 395 | tf = (is_dir & is_svn); 396 | 397 | %---------------------------- end of subfunction -------------------------- 398 | 399 | %% ------------------------------------------------------------------------ 400 | function tf = isdotdir(d) 401 | % True for "." and ".." directories. 402 | % d is a structure returned by "dir" 403 | % 404 | 405 | is_dir = [d.isdir]'; 406 | 407 | is_dot = strcmp({d.name}, '.')'; 408 | is_dotdot = strcmp({d.name}, '..')'; 409 | 410 | tf = (is_dir & (is_dot | is_dotdot) ); 411 | 412 | %---------------------------- end of subfunction -------------------------- 413 | 414 | %% ------------------------------------------------------------------------ 415 | function tf = evaluate(d, expr) 416 | % True for item where evaluated expression is correct or return a non empty 417 | % cell. 418 | % d is a structure returned by "dir" 419 | % 420 | 421 | % Get fields that can be used 422 | name = {d.name}'; %#ok 423 | date = {d.date}'; %#ok 424 | datenum = [d.datenum]'; %#ok 425 | bytes = [d.bytes]'; %#ok 426 | isdir = [d.isdir]'; %#ok 427 | 428 | tf = eval(expr); % low risk since done in a dedicated subfunction. 429 | 430 | % Convert cell outputs returned by "strfind" or "regexp" filters to a 431 | % logical. 432 | if iscell(tf) 433 | tf = not( cellfun(@isempty, tf) ); 434 | end 435 | 436 | %---------------------------- end of subfunction -------------------------- 437 | 438 | %---------------------------- END OF FUNCTION ----------------------------- 439 | -------------------------------------------------------------------------------- /toolbox/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) width height]); 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 | -------------------------------------------------------------------------------- /toolbox/subtightplot.m: -------------------------------------------------------------------------------- 1 | function h=subtightplot(m,n,p,gap,marg_h,marg_w,varargin) 2 | %function h=subtightplot(m,n,p,gap,marg_h,marg_w,varargin) 3 | % 4 | % Functional purpose: A wrapper function for Matlab function subplot. Adds the ability to define the gap between 5 | % neighbouring subplots. Unfotrtunately Matlab subplot function lacks this functionality, and the gap between 6 | % subplots can reach 40% of figure area, which is pretty lavish. 7 | % 8 | % Input arguments (defaults exist): 9 | % gap- two elements vector [vertical,horizontal] defining the gap between neighbouring axes. Default value 10 | % is 0.01. Note this vale will cause titles legends and labels to collide with the subplots, while presenting 11 | % relatively large axis. 12 | % marg_h margins in height in normalized units (0...1) 13 | % or [lower uppper] for different lower and upper margins 14 | % marg_w margins in width in normalized units (0...1) 15 | % or [left right] for different left and right margins 16 | % 17 | % Output arguments: same as subplot- none, or axes handle according to function call. 18 | % 19 | % Issues & Comments: Note that if additional elements are used in order to be passed to subplot, gap parameter must 20 | % be defined. For default gap value use empty element- []. 21 | % 22 | % Usage example: h=subtightplot((2,3,1:2,[0.5,0.2]) 23 | 24 | if (nargin<4) || isempty(gap), gap=0.01; end 25 | if (nargin<5) || isempty(marg_h), marg_h=0.05; end 26 | if (nargin<5) || isempty(marg_w), marg_w=marg_h; end 27 | if isscalar(gap), gap(2)=gap; end 28 | if isscalar(marg_h), marg_h(2)=marg_h; end 29 | if isscalar(marg_w), marg_w(2)=marg_w; end 30 | gap_vert = gap(1); 31 | gap_horz = gap(2); 32 | marg_lower = marg_h(1); 33 | marg_upper = marg_h(2); 34 | marg_left = marg_w(1); 35 | marg_right = marg_w(2); 36 | 37 | %note n and m are switched as Matlab indexing is column-wise, while subplot indexing is row-wise :( 38 | [subplot_col,subplot_row]=ind2sub([n,m],p); 39 | 40 | % note subplot suppors vector p inputs- so a merged subplot of higher dimentions will be created 41 | subplot_cols=1+max(subplot_col)-min(subplot_col); % number of column elements in merged subplot 42 | subplot_rows=1+max(subplot_row)-min(subplot_row); % number of row elements in merged subplot 43 | 44 | % single subplot dimensions: 45 | %height=(1-(m+1)*gap_vert)/m; 46 | %axh = (1-sum(marg_h)-(Nh-1)*gap(1))/Nh; 47 | height=(1-(marg_lower+marg_upper)-(m-1)*gap_vert)/m; 48 | %width =(1-(n+1)*gap_horz)/n; 49 | %axw = (1-sum(marg_w)-(Nw-1)*gap(2))/Nw; 50 | width =(1-(marg_left+marg_right)-(n-1)*gap_horz)/n; 51 | 52 | % merged subplot dimensions: 53 | merged_height=subplot_rows*( height+gap_vert )- gap_vert; 54 | merged_width= subplot_cols*( width +gap_horz )- gap_horz; 55 | 56 | % merged subplot position: 57 | merged_bottom=(m-max(subplot_row))*(height+gap_vert) +marg_lower; 58 | merged_left=(min(subplot_col)-1)*(width+gap_horz) +marg_left; 59 | pos_vec=[merged_left merged_bottom merged_width merged_height]; 60 | 61 | % h_subplot=subplot(m,n,p,varargin{:},'Position',pos_vec); 62 | % Above line doesn't work as subplot tends to ignore 'position' when same mnp is utilized 63 | h=subplot('Position',pos_vec,varargin{:}); 64 | 65 | if (nargout < 1), clear h; end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /toolbox/unpackColumns.m: -------------------------------------------------------------------------------- 1 | function varargout = unpackColumns(X) 2 | 3 | if ndims(X) > 2 4 | error('Please input a 1-d or 2-d matrix'); 5 | end 6 | for i = 1:size(X,2) 7 | varargout{i} = X(:,i); 8 | end -------------------------------------------------------------------------------- /utils/cluster_rects.m: -------------------------------------------------------------------------------- 1 | % FILE: cluster_rects.m 2 | % 3 | % This function derive canonical bounding box shapes by applying K-medoid 4 | % clustering on a set of bounding boxes. 5 | % 6 | % INPUT: imdb (dataset) 7 | % N (number of medoids) 8 | % minsz/maxsz (filter out boxes that are either too big or too small) 9 | % vis (whether we visualize the clustering results) 10 | % 11 | % OUTPUT: C (N medoids) 12 | 13 | function C = cluster_rects(imdb, N, minsz, maxsz, vis) 14 | if nargin < 5 15 | vis = 0; 16 | end 17 | 18 | %% cluster based on shapes of training examples 19 | idx = find(imdb.images.set == 1); 20 | rects = imdb.labels.rects(idx); 21 | rects = vertcat(rects{:}); 22 | 23 | %% centralize 24 | hs = rects(:,4) - rects(:,2) + 1; 25 | ws = rects(:,3) - rects(:,1) + 1; 26 | rects = [-(ws-1)/2, -(hs-1)/2, (ws-1)/2, (hs-1)/2]; 27 | 28 | %% ignore faces with size out of the range 29 | idx = find(hs<=maxsz(1)&ws<=maxsz(2)&hs>=minsz(1)&ws>=minsz(2)); 30 | rects = rects(idx,:); 31 | fprintf('Ignored faces smaller than %dx%d, %d bboxes left.\n',minsz(1),minsz(2),numel(idx)); 32 | 33 | %% subsample for faster clustering 34 | rects = rects(randsample(size(rects,1), min(size(rects,1), 1e5)), :); 35 | fprintf('Clustering on %d/%d face bounding boxes.\n', size(rects,1), numel(idx)); 36 | 37 | %% build kmedoids 38 | [Cidx,C,sumd,D,midx] = kmedoids(rects, N, 'Options', statset('UseParallel', true), 'Distance', @rect_dist); 39 | 40 | %% reorder clusters based on bounding box areas 41 | [~,I] = sort(C(:,3).*C(:,4),'descend'); 42 | C = C(I,:); 43 | 44 | if ~vis, return; end 45 | subplot = @(m,n,k) subtightplot(m,n,k,[0.1,0.1]); 46 | clf; 47 | [SI,SJ] = factorize(N); 48 | for i = 1:N 49 | subplot(SI,SJ,i); 50 | plotBoxes(C(i,1),C(i,2),C(i,3)-C(i,1)+1,C(i,4)-C(i,2)+1,rand(1,3),0.5); 51 | title(num2str(i)); 52 | axis([-250,250,-250,250]); 53 | end 54 | -------------------------------------------------------------------------------- /utils/compile_mex.m: -------------------------------------------------------------------------------- 1 | % FILE: cnn_widerface.m 2 | % 3 | % This script compiles compute_dense_overlap.cc 4 | % 5 | 6 | % mex compute_dense_overlap.cc CXXFLAGS='$CXXFLAGS -fopenmp' ... 7 | % LDFLAGS='$LDFLAGS -fopenmp' CXXOPTIMFLAGS='-O3 -DNDEBUG' 8 | mex compute_dense_overlap.cc CXXOPTIMFLAGS='-O3 -DNDEBUG' -------------------------------------------------------------------------------- /utils/compute_dense_overlap.cc: -------------------------------------------------------------------------------- 1 | /* FILE: compute_dense_overlap.cc 2 | 3 | This function implements the dense overlap computation between all sliding 4 | windows and all ground truth bounding boxes. Run compile_mex.m to compile 5 | this file. 6 | 7 | INPUT: ofx/ofy (pixel-wise offset when mapping feature location to pixel location) 8 | stx/sty (pixel-wise stride between two adjacent feature locations) 9 | vsx/vsy (feature-level spatial size) 10 | dx1/dy1/dx2/dy2 (bounding box coordinates for each feature location) 11 | (as if there is one sliding window centered at that location) 12 | gx1/gy1/gx2/gy2 (ground truth bounding box coordinates) 13 | zmx/zmy (compute overlap at a finer resolution and max pool back to feature-resolution) 14 | 15 | OUTPUT: overlap (vsy x vsx x M x N, where M is the number of canonical 16 | shapes, and N is the number of ground truth bounding boxes.) 17 | 18 | */ 19 | 20 | #include "mex.h" 21 | #include "math.h" 22 | #include 23 | #include 24 | using namespace std; 25 | 26 | /* 27 | * 0 1 2 3 4 5 28 | * function o = compute_overlap(bbox, fdimy, fdimx, dimy, dimx, scale, 29 | * 6 7 8 30 | * padx, pady, imsize) 31 | * bbox bounding box image coordinates [x1 y1 x2 y2] 32 | * fdimy number of rows in filter 33 | * fdimx number of cols in filter 34 | * dimy number of rows in feature map 35 | * dimx number of cols in feature map 36 | * scale image scale the feature map was computed at 37 | * padx x padding added to feature map 38 | * pady y padding added to feature map 39 | * imsize size of the image [h w] 40 | */ 41 | 42 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 43 | /* inputs */ 44 | const double ofx = mxGetScalar(prhs[0]); 45 | const double ofy = mxGetScalar(prhs[1]); 46 | const double stx = mxGetScalar(prhs[2]); 47 | const double sty = mxGetScalar(prhs[3]); 48 | const int vsx = mxGetScalar(prhs[4]); 49 | const int vsy = mxGetScalar(prhs[5]); 50 | 51 | const int nt = mxGetNumberOfElements(prhs[6]); 52 | const double *dx1 = mxGetPr(prhs[6]); 53 | const double *dy1 = mxGetPr(prhs[7]); 54 | const double *dx2 = mxGetPr(prhs[8]); 55 | const double *dy2 = mxGetPr(prhs[9]); 56 | 57 | const int ng = mxGetNumberOfElements(prhs[10]); 58 | const double *gx1 = mxGetPr(prhs[10]); 59 | const double *gy1 = mxGetPr(prhs[11]); 60 | const double *gx2 = mxGetPr(prhs[12]); 61 | const double *gy2 = mxGetPr(prhs[13]); 62 | 63 | const double zmx = mxGetScalar(prhs[14]); 64 | const double zmy = mxGetScalar(prhs[15]); 65 | 66 | /* outputs */ 67 | const mwSize dims[] = {vsy, vsx, nt, ng}; 68 | /* printf("dims: %d %d %d %d\n", vsy, vsx, nt, ng); */ 69 | 70 | mxArray *mx_overlap = mxCreateNumericArray(4, dims, mxDOUBLE_CLASS, mxREAL); 71 | double *overlap = (double *)mxGetPr(mx_overlap); 72 | plhs[0] = mx_overlap; 73 | 74 | /* temporary buffer */ 75 | const mwSize tmp_dims[] = {(vsy-1)*zmy+1, (vsx-1)*zmx+1, nt}; 76 | mxArray *mx_tmp_overlap = mxCreateNumericArray(3, tmp_dims, mxDOUBLE_CLASS, mxREAL); 77 | double *tmp_overlap = (double *)mxGetPr(mx_tmp_overlap); 78 | 79 | /* setup pooling input & output */ 80 | mxArray *inputs[6]; 81 | 82 | /* run max pooling over the temporary buffer */ 83 | inputs[0] = mx_tmp_overlap; 84 | mxArray *mx_pool = mxCreateNumericMatrix(1,2,mxDOUBLE_CLASS,mxREAL); 85 | double *pool = mxGetPr(mx_pool); 86 | pool[0] = zmy; 87 | pool[1] = zmx; 88 | inputs[1] = mx_pool; 89 | 90 | /* set stride */ 91 | inputs[2] = mxCreateString("Stride"); 92 | mxArray *mx_stride = mxCreateNumericMatrix(1,2,mxDOUBLE_CLASS,mxREAL); 93 | double *stride = mxGetPr(mx_stride); 94 | stride[0] = zmy; 95 | stride[1] = zmx; 96 | inputs[3] = mx_stride; 97 | 98 | /* set padding */ 99 | inputs[4] = mxCreateString("Pad"); 100 | mxArray *mx_pad = mxCreateNumericMatrix(1,4,mxDOUBLE_CLASS,mxREAL); 101 | double *pad = mxGetPr(mx_pad); 102 | pad[0] = floor(zmy/2); 103 | pad[1] = ceil(zmy/2); 104 | pad[2] = floor(zmx/2); 105 | pad[3] = ceil(zmx/2); 106 | inputs[5] = mx_pad; 107 | 108 | /* declare outputs */ 109 | mxArray *outputs[1]; 110 | 111 | int i, j, x, y; 112 | /* compute overlap for each placement of the filter */ 113 | for (int i = 0; i < ng; i ++) { 114 | double bbox_x1 = gx1[i]; 115 | double bbox_y1 = gy1[i]; 116 | double bbox_x2 = gx2[i]; 117 | double bbox_y2 = gy2[i]; 118 | 119 | double bbox_h = bbox_y2 - bbox_y1 + 1; 120 | double bbox_w = bbox_x2 - bbox_x1 + 1; 121 | double bbox_area = bbox_h * bbox_w; 122 | 123 | int gidx = vsy * vsx * nt * i; 124 | /* NOTE: we do not have to reset everytime, once we make sure we 125 | * overwrite every element down below */ 126 | /* memset(tmp_overlap, 0.0, tmp_dims[0]*tmp_dims[1]*tmp_dims[2]*sizeof(double)); */ 127 | 128 | for (j = 0; j < nt; j ++) { 129 | /*int tid = omp_get_thread_num(); 130 | printf("Thread id: %d\n", tid);*/ 131 | 132 | double delta_x1 = dx1[j]; 133 | double delta_y1 = dy1[j]; 134 | double delta_x2 = dx2[j]; 135 | double delta_y2 = dy2[j]; 136 | 137 | double filter_h = delta_y2 - delta_y1 + 1; 138 | double filter_w = delta_x2 - delta_x1 + 1; 139 | double filter_area = filter_h * filter_w; 140 | 141 | int tidx = tmp_dims[0] * tmp_dims[1] * j; 142 | 143 | int xmax = (vsx-1)*zmx; 144 | int ymax = (vsy-1)*zmy; 145 | 146 | /* enumerate spatial locations */ 147 | for (x = 0; x <= xmax; x ++){ 148 | for (y = 0; y <= ymax; y ++){ 149 | double cx = ofx + x*(stx/zmx); 150 | int xidx = tmp_dims[0] * x; 151 | double cy = ofy + y*(sty/zmy); 152 | 153 | double x1 = delta_x1 + cx; 154 | double y1 = delta_y1 + cy; 155 | double x2 = delta_x2 + cx; 156 | double y2 = delta_y2 + cy; 157 | 158 | double xx1 = max(x1, bbox_x1); 159 | double yy1 = max(y1, bbox_y1); 160 | double xx2 = min(x2, bbox_x2); 161 | double yy2 = min(y2, bbox_y2); 162 | 163 | double int_w = xx2 - xx1 + 1; 164 | double int_h = yy2 - yy1 + 1; 165 | if (int_w > 0 && int_h > 0){ 166 | double int_area = int_w * int_h; 167 | double union_area = filter_area + bbox_area - int_area; 168 | *(tmp_overlap+tidx+xidx+y) = int_area / union_area; 169 | }else{ 170 | *(tmp_overlap+tidx+xidx+y) = 0; 171 | } 172 | } 173 | } 174 | } 175 | 176 | /* call max pooling if needed */ 177 | double *pooled_overlap; 178 | if (zmx != 1 || zmy != 1){ 179 | mexCallMATLAB(1, outputs, 6, inputs, "vl_nnpool"); 180 | pooled_overlap = mxGetPr(outputs[0]); 181 | }else{ 182 | pooled_overlap = tmp_overlap; 183 | } 184 | 185 | /* copy results from buffer to final output */ 186 | memcpy(overlap+gidx, pooled_overlap, vsy*vsx*nt*sizeof(double)); 187 | 188 | /*for (int k = 0; k < 6; k ++ ) 189 | mxDestroyArray(inputs[k]); 190 | mxDestroyArray(outputs[0]);*/ 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /utils/measure_runtime.m: -------------------------------------------------------------------------------- 1 | % FILE: measure_runtime.m 2 | % 3 | % This script provides an analysis on the run-time of our detector regarding 4 | % different input resolution. In a multi-scale testing scenario, the run-time 5 | % is dominated by the time on the largest resolution. 6 | 7 | clear all; 8 | 9 | addpath matconvnet; 10 | addpath matconvnet/matlab; 11 | vl_setupnn; 12 | 13 | addpath toolbox/nms; 14 | addpath toolbox/export_fig; 15 | 16 | gpu_id = 1; 17 | model_path = 'trained_models/imagenet-resnet-101-dag.mat'; 18 | 19 | % loadng pretrained model (and some final touches) 20 | net = load(model_path); 21 | net = dagnn.DagNN.loadobj(net); 22 | if gpu_id > 0 % for matconvnet it starts with 1 23 | gpuDevice(gpu_id); 24 | net.move('gpu'); 25 | end 26 | 27 | % 28 | iter_num = 100; 29 | 30 | scale = 2; 31 | % 32 | input_size = [1080*scale, 1920*scale, 3, 1]; 33 | img = gpuArray(rand(input_size, 'single')); 34 | t1 = tic; 35 | for i = 1:iter_num 36 | net.eval({'data', img}); 37 | wait(gpuDevice) ; 38 | end 39 | t2 = toc(t1); 40 | fprintf('input size: [%d %d %d], time: %.6f\n', size(img), t2/iter_num); 41 | 42 | % 43 | input_size = [720*scale, 1280*scale, 3, 1]; 44 | img = gpuArray(rand(input_size, 'single')); 45 | t1 = tic; 46 | for i = 1:iter_num 47 | net.eval({'data', img}); 48 | wait(gpuDevice) ; 49 | end 50 | t2 = toc(t1); 51 | fprintf('input size: [%d %d %d], time: %.6f\n', size(img), t2/iter_num); 52 | 53 | % 54 | input_size = [480*scale, 640*scale, 3, 1]; 55 | img = gpuArray(rand(input_size, 'single')); 56 | t1 = tic; 57 | for i = 1:iter_num 58 | net.eval({'data', img}); 59 | wait(gpuDevice) ; 60 | end 61 | t2 = toc(t1); 62 | fprintf('input size: [%d %d %d], time: %.6f\n', size(img), t2/iter_num); -------------------------------------------------------------------------------- /utils/plotBoxes.m: -------------------------------------------------------------------------------- 1 | function plotBoxes(x, y, w, h, c, lw) 2 | nx = numel(x); 3 | ny = numel(y); 4 | nw = numel(w); 5 | nh = numel(h); 6 | nc = size(c,1); 7 | nl = size(lw,1); 8 | if any(nx ~= [ny nw nh]) 9 | error('Please input (x,y,w,h[,c,w]) with same dim'); 10 | end 11 | hold on; 12 | for i = 1:nx 13 | clr = c(min(nc,i),:); 14 | lwd = lw(min(nl,i)); 15 | if lwd == 0, continue; end; 16 | rectangle('position', [x(i), y(i), w(i), h(i)], ... 17 | 'EdgeColor', clr, 'LineWidth', lwd); 18 | end 19 | hold off; -------------------------------------------------------------------------------- /utils/rect_dist.m: -------------------------------------------------------------------------------- 1 | % FILE: rect_dist.m 2 | % 3 | % This function takes two sets of bounding boxes and computes the Jaccard 4 | % distance between every pair of bounding boxes. It is written in a way that 5 | % it can be used as a customized distance function, meaning one can use it 6 | % with pdist2 etc. 7 | % 8 | % INPUT: XI [Mx4] (where M is the number of bounding boxes) 9 | % XJ [Nx4] (where N is the number of bounding boxes) 10 | % 11 | % OUTPUT: D [MxN] 12 | % 13 | 14 | function D = rect_dist(XI,XJ) 15 | 16 | %XI = round(XI); 17 | %XJ = round(XJ); 18 | 19 | aI = (XI(:,3)-XI(:,1)+1) .* (XI(:,4)-XI(:,2)+1); 20 | aJ = (XJ(:,3)-XJ(:,1)+1) .* (XJ(:,4)-XJ(:,2)+1); 21 | 22 | x1 = max(XI(:,1), XJ(:,1)); 23 | y1 = max(XI(:,2), XJ(:,2)); 24 | x2 = min(XI(:,3), XJ(:,3)); 25 | y2 = min(XI(:,4), XJ(:,4)); 26 | 27 | aIJ = (x2-x1+1) .* (y2-y1+1) .* (x2>x1 & y2>y1); 28 | 29 | iou = aIJ ./ (aI+aJ-aIJ); 30 | D = max(0, min(1, 1 - iou)); 31 | -------------------------------------------------------------------------------- /utils/test_compute_dense_overlap.m: -------------------------------------------------------------------------------- 1 | load('test_data.mat') 2 | iou_ = compute_dense_overlap(ofx,ofy,stx,sty,vsx,vsy,dx1,dy1,dx2,dy2,gx1,gy1,gx2,gy2,1,1); 3 | err = abs(iou_ - iou); 4 | if all(err(:)) < 1e-12 5 | fprintf('Test for compute_dense_overlap [passed]\n'); 6 | else 7 | fprintf('Test for compute_dense_overlap [failed]\n'); 8 | end 9 | 10 | 11 | -------------------------------------------------------------------------------- /utils/test_data.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/peiyunh/tiny/37c44deacf53e0fbe23327ef3721b5fb5f22559f/utils/test_data.mat -------------------------------------------------------------------------------- /utils/tile3DHeat.m: -------------------------------------------------------------------------------- 1 | function Y = tile3DHeat(X) 2 | if isa(X, 'gpuArray') 3 | X = gather(X); 4 | end 5 | 6 | [I,J] = factorize(size(X,3)); 7 | 8 | % 9 | Y = zeros(size(X,1)*I, size(X,2)*J); 10 | for i = 1:I 11 | for j = 1:J 12 | Y(size(X,1)*(i-1)+1:size(X,1)*i, ... 13 | size(X,2)*(j-1)+1:size(X,2)*j) = X(:,:,(i-1)*J+j); 14 | end 15 | end 16 | 17 | -------------------------------------------------------------------------------- /utils/visualize_detection.m: -------------------------------------------------------------------------------- 1 | function visualize_detection(img, bbox, thr) 2 | 3 | if ~isempty(img), imshow(img); end 4 | 5 | colors = parula(100); 6 | scores = vl_nnsigmoid(bbox(:,end)); 7 | 8 | hold on; 9 | for i = 1:size(bbox, 1) 10 | if scores(i) < thr, continue; end 11 | color = colors(ceil(100*scores(i)), :); 12 | bw = bbox(i,3) - bbox(i,1) + 1; 13 | bh = bbox(i,4) - bbox(i,2) + 1; 14 | if min([bw bh]) <= 20 15 | lw = 1; 16 | else 17 | lw = max(2, min(3, min([bh/20, bw/20]))); 18 | end 19 | lw = lw * scores(i); 20 | % if 100*scores(i) < 75 21 | % lw = lw / 2; 22 | % end 23 | rectangle('position', [bbox(i,1:2) bbox(i,3:4)-bbox(i,1:2)+1], ... 24 | 'EdgeColor', color, 'LineWidth', lw); 25 | end 26 | hold off; 27 | %colormap parula; 28 | colormap(colors); 29 | colorbar; 30 | axis off; 31 | drawnow; --------------------------------------------------------------------------------