├── .gitignore ├── .idea ├── Mask-Insightface.iml ├── encodings.xml ├── misc.xml ├── modules.xml └── workspace.xml ├── 3rdparty └── operator │ ├── amsoftmax-inl.h │ ├── amsoftmax.cc │ ├── amsoftmax.cu │ ├── lsoftmax-inl.h │ ├── lsoftmax.cc │ └── lsoftmax.cu ├── LICENSE ├── PRNet_Mask ├── .idea │ ├── PRNet-master.iml │ ├── encodings.xml │ ├── misc.xml │ ├── modules.xml │ └── workspace.xml ├── .travis.yml ├── Data │ ├── net-data │ │ └── README.md │ └── uv-data │ │ ├── canonical_vertices_40k.npy │ │ ├── canonical_vertices_68_fan.npy │ │ ├── face_ind.txt │ │ ├── triangles.txt │ │ └── uv_kpt_ind.txt ├── LICENSE ├── README.md ├── api.py ├── gen_3daug_mesh.py ├── generate_mask.py ├── get_angle.py ├── predictor.py ├── requirements.txt └── utils │ ├── __init__.py │ ├── cv_plot.py │ ├── cython │ ├── __init__.py │ ├── mesh_core.cpp │ ├── mesh_core.h │ ├── mesh_core_cython.cpp │ ├── mesh_core_cython.pyx │ ├── readme.md │ └── setup.py │ ├── estimate_pose.py │ ├── render.py │ ├── render_app.py │ ├── rotate_vertices.py │ └── write.py ├── README.md ├── SSH ├── .idea │ ├── SSH.iml │ ├── encodings.xml │ ├── misc.xml │ ├── modules.xml │ ├── vcs.xml │ └── workspace.xml ├── Makefile ├── README.md ├── __init__.py ├── model │ └── readme ├── rcnn │ ├── __init__.py │ ├── config.py │ ├── cython │ │ ├── .gitignore │ │ ├── __init__.py │ │ ├── anchors.pyx │ │ ├── bbox.pyx │ │ ├── cpu_nms.pyx │ │ ├── gpu_nms.hpp │ │ ├── gpu_nms.pyx │ │ ├── nms_kernel.cu │ │ └── setup.py │ └── processing │ │ ├── __init__.py │ │ ├── bbox_regression.py │ │ ├── bbox_transform.py │ │ ├── generate_anchor.py │ │ └── nms.py └── ssh_detector.py ├── SSR-Net ├── LICENSE ├── README.md ├── data │ ├── TYY_IMDBWIKI_create_db.py │ ├── TYY_MORPH_create_db.py │ ├── TYY_XSDATA_create_db.py │ └── TYY_utils.py ├── demo │ ├── SSRNET_model.py │ ├── TGOP_tvbs.png │ └── TYY_demo_centerface_bbox_age_gender.py └── pre-trained │ ├── wiki_age_bbox_crop │ └── ssrnet_3_3_3_112_0.75_1.0.h5 │ └── wiki_gender_112_class3 │ └── ssrnet_3_3_3_112_1.0_1.0.h5 ├── TensorFace ├── .idea │ ├── TensorFace.iml │ ├── inspectionProfiles │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── workspace.xml ├── README.md ├── common │ ├── FaceQuality.py │ ├── face_align.py │ └── face_preprocess.py ├── config.py ├── demo.py ├── fd_retina.py ├── fr_arcface.py └── modules │ ├── configs.py │ ├── face_model.py │ ├── imagedata.py │ ├── model_zoo │ ├── detectors │ │ ├── centerface.py │ │ ├── common │ │ │ └── nms.py │ │ ├── dbface.py │ │ └── retinaface.py │ ├── exec_backends │ │ ├── onnxrt_backend.py │ │ ├── triton_backend.py │ │ ├── trt_backend.py │ │ └── trt_loader.py │ ├── face_detectors.py │ ├── face_processors.py │ └── getter.py │ └── utils │ ├── download.py │ ├── helpers.py │ └── model_store.py ├── datasets └── property ├── deploy ├── FUNCTION.py ├── RocTest.py ├── benchmark.py ├── clean_others_img.py ├── face_embedding.py ├── face_model_prnet_mask.py ├── ga_merge.py ├── gen_landmark_data.py ├── helper.py ├── model_slim.py ├── mtcnn_detector.py ├── reranking.py └── test_prnet_mask.py ├── faceQuality ├── FaceQNet.py ├── README.md ├── get_quality.py └── get_quality_clean.py ├── gen_datasets.py ├── images ├── Abner_Martinez_0001.jpg ├── Akbar_Al_Baker_0001.jpg ├── mask.png └── src.png ├── make_rec ├── README.md ├── common │ ├── __init__.py │ ├── face_image.py │ ├── face_preprocess.py │ └── noise_sgd.py ├── face2rec2.py ├── gen_datasets_lst.py ├── gen_val_bin.sh ├── gen_valdatasets.py ├── generate_lst.sh └── generate_rec.sh ├── remove_lowshot.py ├── src ├── --target ├── align │ ├── __init__.py │ ├── align_celeb.py │ ├── align_dataset.py │ ├── align_dataset_mtcnn.py │ ├── align_dlib.py │ ├── align_facescrub.py │ ├── align_insight.py │ ├── align_lfw.py │ ├── align_megaface.py │ ├── det1.npy │ ├── det2.npy │ ├── det3.npy │ └── detect_face.py ├── api │ ├── app.py │ └── face_model.py ├── common │ ├── __init__.py │ ├── face_align_util.py │ ├── face_image.py │ ├── face_preprocess.py │ └── noise_sgd.py ├── data.py ├── data │ ├── agedb2pack.py │ ├── agedb2pack2.py │ ├── cfp2pack.py │ ├── dataset_c2c.py │ ├── dataset_clean.py │ ├── dataset_info.py │ ├── dataset_merge.py │ ├── dataset_relabel.py │ ├── face2rec2.py │ └── lfw2pack.py ├── eval │ ├── do_ver.sh │ ├── lfw.py │ ├── verification.py │ ├── ytf.py │ └── ytf_badcases.py ├── image_iter.py ├── log.txt ├── losses │ └── center_loss.py ├── megaface │ ├── README.md │ ├── facescrub_noises.txt │ ├── gen_megaface.py │ ├── megaface_noises.txt │ └── remove_noises.py ├── memonger.py ├── symbols │ ├── VarGFaceNet.py │ ├── fdensenet.py │ ├── fdpn.py │ ├── finception_resnet_v2.py │ ├── fmobilenet.py │ ├── fmobilenetv2.py │ ├── fnasnet.py │ ├── fresnet.py │ ├── fxception.py │ ├── spherenet.py │ └── symbol_utils.py ├── train.py ├── train_myself.sh ├── train_softmax.py └── utils │ └── benchmark.py └── verification.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /.idea/Mask-Insightface.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /3rdparty/operator/amsoftmax.cc: -------------------------------------------------------------------------------- 1 | #include "./amsoftmax-inl.h" 2 | 3 | namespace mshadow { 4 | 5 | template 6 | inline void AmSoftmaxForward(const Tensor &x, 7 | const Tensor &w, 8 | const Tensor &label, 9 | const Tensor &out, 10 | const Tensor &oout, 11 | const DType margin, 12 | const DType s) { 13 | LOG(FATAL) << "Not Implemented."; 14 | } 15 | 16 | template 17 | inline void AmSoftmaxBackward(const Tensor &x, 18 | const Tensor &w, 19 | const Tensor &label, 20 | const Tensor &out, 21 | const Tensor &oout, 22 | const Tensor &o_grad, 23 | const Tensor &x_grad, 24 | const Tensor &w_grad, 25 | const Tensor &workspace, 26 | const DType margin, 27 | const DType s) { 28 | LOG(FATAL) << "Not Implemented."; 29 | } 30 | 31 | } // namespace mshadow 32 | 33 | namespace mxnet { 34 | namespace op { 35 | 36 | template<> 37 | Operator *CreateOp(AmSoftmaxParam param, int dtype) { 38 | Operator *op = NULL; 39 | MSHADOW_REAL_TYPE_SWITCH(dtype, DType, { 40 | op = new AmSoftmaxOp(param); 41 | }) 42 | return op; 43 | } 44 | 45 | Operator *AmSoftmaxProp::CreateOperatorEx(Context ctx, std::vector *in_shape, 46 | std::vector *in_type) const { 47 | std::vector out_shape, aux_shape; 48 | std::vector out_type, aux_type; 49 | CHECK(InferType(in_type, &out_type, &aux_type)); 50 | CHECK(InferShape(in_shape, &out_shape, &aux_shape)); 51 | DO_BIND_DISPATCH(CreateOp, param_, in_type->at(0)); 52 | } 53 | 54 | DMLC_REGISTER_PARAMETER(AmSoftmaxParam); 55 | 56 | MXNET_REGISTER_OP_PROPERTY(AmSoftmax, AmSoftmaxProp) 57 | .describe("AmSoftmax from ") 58 | .add_argument("data", "Symbol", "data") 59 | .add_argument("weight", "Symbol", "weight") 60 | .add_argument("label", "Symbol", "label") 61 | .add_arguments(AmSoftmaxParam::__FIELDS__()); 62 | 63 | } // namespace op 64 | } // namespace mxnet 65 | -------------------------------------------------------------------------------- /3rdparty/operator/lsoftmax.cc: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2016 by Contributors 3 | * \file lsoftmax.cc 4 | * \brief LSoftmax from 5 | * \author luoyetx 6 | */ 7 | #include "./lsoftmax-inl.h" 8 | 9 | namespace mshadow { 10 | 11 | template 12 | inline void LSoftmaxForward(const Tensor &x, 13 | const Tensor &w, 14 | const Tensor &label, 15 | const Tensor &out, 16 | const Tensor &x_norm, 17 | const Tensor &w_norm, 18 | const Tensor &k_table, 19 | const Tensor &c_table, 20 | const int margin, 21 | const DType beta) { 22 | LOG(FATAL) << "Not Implemented."; 23 | } 24 | 25 | template 26 | inline void LSoftmaxBackward(const Tensor &x, 27 | const Tensor &w, 28 | const Tensor &label, 29 | const Tensor &x_norm, 30 | const Tensor &w_norm, 31 | const Tensor &o_grad, 32 | const Tensor &x_grad, 33 | const Tensor &w_grad, 34 | const Tensor &workspace, 35 | const Tensor &k_table, 36 | const Tensor &c_table, 37 | const int margin, 38 | const DType beta) { 39 | LOG(FATAL) << "Not Implemented."; 40 | } 41 | 42 | } // namespace mshadow 43 | 44 | namespace mxnet { 45 | namespace op { 46 | 47 | template<> 48 | Operator *CreateOp(LSoftmaxParam param, int dtype) { 49 | Operator *op = NULL; 50 | MSHADOW_REAL_TYPE_SWITCH(dtype, DType, { 51 | op = new LSoftmaxOp(param); 52 | }) 53 | return op; 54 | } 55 | 56 | Operator *LSoftmaxProp::CreateOperatorEx(Context ctx, std::vector *in_shape, 57 | std::vector *in_type) const { 58 | std::vector out_shape, aux_shape; 59 | std::vector out_type, aux_type; 60 | CHECK(InferType(in_type, &out_type, &aux_type)); 61 | CHECK(InferShape(in_shape, &out_shape, &aux_shape)); 62 | DO_BIND_DISPATCH(CreateOp, param_, in_type->at(0)); 63 | } 64 | 65 | DMLC_REGISTER_PARAMETER(LSoftmaxParam); 66 | 67 | MXNET_REGISTER_OP_PROPERTY(LSoftmax, LSoftmaxProp) 68 | .describe("LSoftmax from ") 69 | .add_argument("data", "Symbol", "data") 70 | .add_argument("weight", "Symbol", "weight") 71 | .add_argument("label", "Symbol", "label") 72 | .add_arguments(LSoftmaxParam::__FIELDS__()); 73 | 74 | } // namespace op 75 | } // namespace mxnet 76 | -------------------------------------------------------------------------------- /PRNet_Mask/.idea/PRNet-master.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /PRNet_Mask/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /PRNet_Mask/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /PRNet_Mask/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PRNet_Mask/.travis.yml: -------------------------------------------------------------------------------- 1 | group: travis_latest 2 | language: python 3 | cache: pip 4 | python: 5 | - 2.7 6 | - 3.6 7 | #- nightly 8 | #- pypy 9 | #- pypy3 10 | matrix: 11 | allow_failures: 12 | - python: nightly 13 | - python: pypy 14 | - python: pypy3 15 | install: 16 | - pip install -r requirements.txt 17 | - pip install flake8 # pytest # add another testing frameworks later 18 | before_script: 19 | # stop the build if there are Python syntax errors or undefined names 20 | - flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics 21 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 22 | - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 23 | script: 24 | - ls 25 | - wget "https://drive.google.com/uc?export=download&confirm=D2ug&id=1UoE-XuW1SDLUjZmJPkIZ1MLxvQFgmTFH" 26 | - ls 27 | - python run_basics.py # Can run only with python and tensorflow 28 | notifications: 29 | on_success: change 30 | on_failure: change # `always` will be the setting once code changes slow down 31 | -------------------------------------------------------------------------------- /PRNet_Mask/Data/net-data/README.md: -------------------------------------------------------------------------------- 1 | Download the PRN trained model at [BaiduDrive](https://pan.baidu.com/s/10vuV7m00OHLcsihaC-Adsw) or [GoogleDrive](https://drive.google.com/file/d/1UoE-XuW1SDLUjZmJPkIZ1MLxvQFgmTFH/view?usp=sharing), and put it into `Data/net-data` 2 | -------------------------------------------------------------------------------- /PRNet_Mask/Data/uv-data/canonical_vertices_40k.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/PRNet_Mask/Data/uv-data/canonical_vertices_40k.npy -------------------------------------------------------------------------------- /PRNet_Mask/Data/uv-data/canonical_vertices_68_fan.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/PRNet_Mask/Data/uv-data/canonical_vertices_68_fan.npy -------------------------------------------------------------------------------- /PRNet_Mask/Data/uv-data/uv_kpt_ind.txt: -------------------------------------------------------------------------------- 1 | 1.500000000000000000e+01 2.200000000000000000e+01 2.600000000000000000e+01 3.200000000000000000e+01 4.500000000000000000e+01 6.700000000000000000e+01 9.100000000000000000e+01 1.120000000000000000e+02 1.280000000000000000e+02 1.430000000000000000e+02 1.640000000000000000e+02 1.880000000000000000e+02 2.100000000000000000e+02 2.230000000000000000e+02 2.290000000000000000e+02 2.330000000000000000e+02 2.400000000000000000e+02 5.800000000000000000e+01 7.100000000000000000e+01 8.500000000000000000e+01 9.700000000000000000e+01 1.060000000000000000e+02 1.490000000000000000e+02 1.580000000000000000e+02 1.700000000000000000e+02 1.840000000000000000e+02 1.970000000000000000e+02 1.280000000000000000e+02 1.280000000000000000e+02 1.280000000000000000e+02 1.280000000000000000e+02 1.170000000000000000e+02 1.220000000000000000e+02 1.280000000000000000e+02 1.330000000000000000e+02 1.380000000000000000e+02 7.800000000000000000e+01 8.600000000000000000e+01 9.500000000000000000e+01 1.020000000000000000e+02 9.600000000000000000e+01 8.700000000000000000e+01 1.530000000000000000e+02 1.600000000000000000e+02 1.690000000000000000e+02 1.770000000000000000e+02 1.680000000000000000e+02 1.590000000000000000e+02 1.080000000000000000e+02 1.160000000000000000e+02 1.240000000000000000e+02 1.280000000000000000e+02 1.310000000000000000e+02 1.390000000000000000e+02 1.460000000000000000e+02 1.370000000000000000e+02 1.320000000000000000e+02 1.280000000000000000e+02 1.230000000000000000e+02 1.180000000000000000e+02 1.100000000000000000e+02 1.220000000000000000e+02 1.280000000000000000e+02 1.330000000000000000e+02 1.450000000000000000e+02 1.320000000000000000e+02 1.280000000000000000e+02 1.230000000000000000e+02 2 | 9.600000000000000000e+01 1.180000000000000000e+02 1.410000000000000000e+02 1.650000000000000000e+02 1.830000000000000000e+02 1.900000000000000000e+02 1.880000000000000000e+02 1.870000000000000000e+02 1.930000000000000000e+02 1.870000000000000000e+02 1.880000000000000000e+02 1.900000000000000000e+02 1.830000000000000000e+02 1.650000000000000000e+02 1.410000000000000000e+02 1.180000000000000000e+02 9.600000000000000000e+01 4.900000000000000000e+01 4.200000000000000000e+01 3.900000000000000000e+01 4.000000000000000000e+01 4.200000000000000000e+01 4.200000000000000000e+01 4.000000000000000000e+01 3.900000000000000000e+01 4.200000000000000000e+01 4.900000000000000000e+01 5.900000000000000000e+01 7.300000000000000000e+01 8.600000000000000000e+01 9.600000000000000000e+01 1.110000000000000000e+02 1.130000000000000000e+02 1.150000000000000000e+02 1.130000000000000000e+02 1.110000000000000000e+02 6.700000000000000000e+01 6.000000000000000000e+01 6.100000000000000000e+01 6.500000000000000000e+01 6.800000000000000000e+01 6.900000000000000000e+01 6.500000000000000000e+01 6.100000000000000000e+01 6.000000000000000000e+01 6.700000000000000000e+01 6.900000000000000000e+01 6.800000000000000000e+01 1.420000000000000000e+02 1.310000000000000000e+02 1.270000000000000000e+02 1.280000000000000000e+02 1.270000000000000000e+02 1.310000000000000000e+02 1.420000000000000000e+02 1.480000000000000000e+02 1.500000000000000000e+02 1.500000000000000000e+02 1.500000000000000000e+02 1.480000000000000000e+02 1.410000000000000000e+02 1.350000000000000000e+02 1.340000000000000000e+02 1.350000000000000000e+02 1.420000000000000000e+02 1.430000000000000000e+02 1.420000000000000000e+02 1.430000000000000000e+02 3 | -------------------------------------------------------------------------------- /PRNet_Mask/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Yao Feng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRNet_Mask/gen_3daug_mesh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | from glob import glob 4 | import scipy.io as sio 5 | from skimage.io import imread, imsave 6 | from skimage.transform import rescale, resize 7 | from time import time 8 | import argparse 9 | import ast 10 | import sys 11 | 12 | from PRNet_Mask.api import PRN 13 | 14 | # from PRNet_Mask.utils.estimate_pose import estimate_pose 15 | # from PRNet_Mask.utils.rotate_vertices import frontalize 16 | # from PRNet_Mask.utils.render_app import get_visibility, get_uv_mask, get_depth_image 17 | # from PRNet_Mask.utils.write import write_obj_with_colors, write_obj_with_texture 18 | 19 | 20 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 21 | # add ssh face detection 22 | from SSH.ssh_detector import SSHDetector 23 | from SSH.rcnn.config import config 24 | 25 | # load ssh detecte model 26 | detector = SSHDetector(gpu=0, test_mode=False) 27 | 28 | 29 | def get_max_face(bounding_boxes): 30 | det = bounding_boxes[:, 0:4] 31 | bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1]) 32 | bindex = np.argmax(bounding_box_size) # some extra weight on the centering 33 | return bindex 34 | 35 | 36 | def main(args): 37 | # ---- init PRN 38 | os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu # GPU number, -1 for CPU 39 | prn = PRN(is_dlib = args.isDlib) 40 | 41 | # ------------- load data 42 | image_folder = args.inputDir 43 | save_folder = args.outputDir 44 | if not os.path.exists(save_folder): 45 | os.mkdir(save_folder) 46 | 47 | types = ('*.jpg', '*.png', '*.bmp') 48 | image_path_list= [] 49 | for files in types: 50 | image_path_list.extend(glob(os.path.join(image_folder, files))) 51 | 52 | for i, image_path in enumerate(image_path_list): 53 | 54 | name = image_path.strip().split('/')[-1][:-4] 55 | 56 | if os.path.exists(os.path.join(save_folder, name + '_mesh.mat')): 57 | continue 58 | try: 59 | image = imread(image_path) 60 | except: 61 | continue 62 | if len(image.shape)<3: 63 | continue 64 | [h, w, c] = image.shape 65 | if c>3: 66 | image = image[:,:,:3] 67 | 68 | max_size = max(image.shape[0], image.shape[1]) 69 | if max_size> 800: 70 | image = rescale(image, 800./max_size) 71 | image = (image*255).astype(np.uint8) 72 | # the core: regress position map 73 | if args.isDlib: 74 | pos = prn.process(image) # use dlib to detect face 75 | else: 76 | ret = detector.detect(image, threshold=config.TEST.SCORE_THRESH, scales=config.TEST.PYRAMID_SCALES) 77 | # ssh face detection 78 | if ret is None: 79 | continue 80 | if ret.shape[0] < 1: 81 | continue 82 | bindex = get_max_face(ret) 83 | bbox = ret[bindex, :4] 84 | pos = prn.process(image, bbox) 85 | 86 | image = image/255. 87 | if pos is None: 88 | continue 89 | 90 | # 3D vertices 91 | vertices = prn.get_vertices(pos) 92 | 93 | if args.isMat: 94 | # corresponding colors 95 | colors = prn.get_colors(image, vertices) 96 | sio.savemat(os.path.join(save_folder, name + '_mesh.mat'), {'vertices': vertices, 'colors': colors, 'triangles': prn.triangles}) 97 | 98 | 99 | if __name__ == '__main__': 100 | parser = argparse.ArgumentParser(description='Joint 3D Face Reconstruction and Dense Alignment with Position Map Regression Network') 101 | 102 | parser.add_argument('-i', '--inputDir', default='TestImages/', type=str, 103 | help='path to the input directory, where input images are stored.') 104 | parser.add_argument('-o', '--outputDir', default='TestImages/results', type=str, 105 | help='path to the output directory, where results(obj,txt files) will be stored.') 106 | parser.add_argument('--gpu', default='0', type=str, 107 | help='set gpu id, -1 for CPU') 108 | parser.add_argument('--isDlib', default=False, type=ast.literal_eval, 109 | help='whether to use dlib for detecting face, default is True, if False, the input image should be cropped in advance') 110 | parser.add_argument('--isMat', default=False, type=ast.literal_eval, 111 | help='whether to save vertices,color,triangles as mat for matlab showing') 112 | main(parser.parse_args()) 113 | -------------------------------------------------------------------------------- /PRNet_Mask/get_angle.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import cv2 4 | import math 5 | 6 | from PRNet_Mask.api import PRN 7 | from PRNet_Mask.utils.estimate_pose import estimate_pose 8 | 9 | def load_mask_model(DEVICES): 10 | # ---- init PRN 11 | os.environ['CUDA_VISIBLE_DEVICES'] = str(DEVICES) # GPU number, -1 for CPU 12 | prn = PRN() 13 | return prn 14 | 15 | def get_angle(image, prn, max_bbox): 16 | if image.shape[2] > 3: 17 | image = image[:, :, :3] 18 | 19 | # the core: regress position map 20 | pos = prn.process(image, max_bbox) 21 | if pos is None: 22 | print('depths_img is error') 23 | return None 24 | else: 25 | # 3D vertices with 40k 26 | vertices = prn.get_vertices(pos) 27 | _, pose = estimate_pose(vertices, prn.canonical_vertices_40) # canonical_vertices_40: pos angle with 40k points, add by sai 28 | # 3D vertices with 68 29 | # landmarks = np.float32(prn.get_landmarks(pos)) 30 | # landmarks = gen_landmark(image, max_bbox) 31 | # canonical_vertices_fan transform array with 68 points, which is generate by fannet 32 | # canonical_vertices_3d std 3d model whit 68 points 33 | # _, pose = estimate_pose(landmarks, prn.canonical_vertices_40) 34 | angle = np.array(pose) * 180 / math.pi 35 | # for k in landmarks: 36 | # image = cv2.circle(image, (int(k[0]), int(k[1])), 1, (255, 0, 255), 1) 37 | 38 | return image, angle 39 | -------------------------------------------------------------------------------- /PRNet_Mask/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.14.3 2 | scikit-image 3 | scipy 4 | tensorflow 5 | -------------------------------------------------------------------------------- /PRNet_Mask/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/PRNet_Mask/utils/__init__.py -------------------------------------------------------------------------------- /PRNet_Mask/utils/cv_plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | end_list = np.array([17, 22, 27, 42, 48, 31, 36, 68], dtype = np.int32) - 1 5 | def plot_kpt(image, kpt): 6 | ''' Draw 68 key points 7 | Args: 8 | image: the input image 9 | kpt: (68, 3). 10 | ''' 11 | image = image.copy() 12 | kpt = np.round(kpt).astype(np.int32) 13 | for i in range(kpt.shape[0]): 14 | st = kpt[i, :2] 15 | image = cv2.circle(image,(st[0], st[1]), 1, (0,0,255), 2) 16 | if i in end_list: 17 | continue 18 | ed = kpt[i + 1, :2] 19 | image = cv2.line(image, (st[0], st[1]), (ed[0], ed[1]), (255, 255, 255), 1) 20 | return image 21 | 22 | 23 | def plot_vertices(image, vertices): 24 | image = image.copy() 25 | vertices = np.round(vertices).astype(np.int32) 26 | for i in range(0, vertices.shape[0], 2): 27 | st = vertices[i, :2] 28 | image = cv2.circle(image,(st[0], st[1]), 1, (255,0,0), -1) 29 | return image 30 | 31 | 32 | def plot_pose_box(image, P, kpt, color=(0, 255, 0), line_width=2): 33 | ''' Draw a 3D box as annotation of pose. Ref:https://github.com/yinguobing/head-pose-estimation/blob/master/pose_estimator.py 34 | Args: 35 | image: the input image 36 | P: (3, 4). Affine Camera Matrix. 37 | kpt: (68, 3). 38 | ''' 39 | image = image.copy() 40 | 41 | point_3d = [] 42 | rear_size = 90 43 | rear_depth = 0 44 | point_3d.append((-rear_size, -rear_size, rear_depth)) 45 | point_3d.append((-rear_size, rear_size, rear_depth)) 46 | point_3d.append((rear_size, rear_size, rear_depth)) 47 | point_3d.append((rear_size, -rear_size, rear_depth)) 48 | point_3d.append((-rear_size, -rear_size, rear_depth)) 49 | 50 | front_size = 105 51 | front_depth = 110 52 | point_3d.append((-front_size, -front_size, front_depth)) 53 | point_3d.append((-front_size, front_size, front_depth)) 54 | point_3d.append((front_size, front_size, front_depth)) 55 | point_3d.append((front_size, -front_size, front_depth)) 56 | point_3d.append((-front_size, -front_size, front_depth)) 57 | point_3d = np.array(point_3d, dtype=np.float).reshape(-1, 3) 58 | 59 | # Map to 2d image points 60 | point_3d_homo = np.hstack((point_3d, np.ones([point_3d.shape[0],1]))) #n x 4 61 | point_2d = point_3d_homo.dot(P.T)[:,:2] 62 | point_2d[:,:2] = point_2d[:,:2] - np.mean(point_2d[:4,:2], 0) + np.mean(kpt[:27,:2], 0) 63 | point_2d = np.int32(point_2d.reshape(-1, 2)) 64 | 65 | # Draw all the lines 66 | cv2.polylines(image, [point_2d], True, color, line_width, cv2.LINE_AA) 67 | cv2.line(image, tuple(point_2d[1]), tuple( 68 | point_2d[6]), color, line_width, cv2.LINE_AA) 69 | cv2.line(image, tuple(point_2d[2]), tuple( 70 | point_2d[7]), color, line_width, cv2.LINE_AA) 71 | cv2.line(image, tuple(point_2d[3]), tuple( 72 | point_2d[8]), color, line_width, cv2.LINE_AA) 73 | 74 | return image -------------------------------------------------------------------------------- /PRNet_Mask/utils/cython/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/PRNet_Mask/utils/cython/__init__.py -------------------------------------------------------------------------------- /PRNet_Mask/utils/cython/mesh_core.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Yao Feng (https://github.com/YadiraF) 3 | Modified by cleardusk (https://github.com/cleardusk) 4 | */ 5 | 6 | #ifndef MESH_CORE_HPP_ 7 | #define MESH_CORE_HPP_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | 18 | class point { 19 | public: 20 | float x; 21 | float y; 22 | 23 | float dot(point p) 24 | { 25 | return this->x * p.x + this->y * p.y; 26 | } 27 | 28 | point operator-(const point& p) 29 | { 30 | point np; 31 | np.x = this->x - p.x; 32 | np.y = this->y - p.y; 33 | return np; 34 | } 35 | 36 | point operator+(const point& p) 37 | { 38 | point np; 39 | np.x = this->x + p.x; 40 | np.y = this->y + p.y; 41 | return np; 42 | } 43 | 44 | point operator*(float s) 45 | { 46 | point np; 47 | np.x = s * this->x; 48 | np.y = s * this->y; 49 | return np; 50 | } 51 | }; 52 | 53 | bool is_point_in_tri(point p, point p0, point p1, point p2, int h, int w); 54 | void get_point_weight(float* weight, point p, point p0, point p1, point p2); 55 | void _get_normal_core(float* normal, float* tri_normal, int* triangles, int ntri); 56 | void _render_colors_core( 57 | float* image, float* vertices, int* triangles, 58 | float* colors, 59 | float* depth_buffer, 60 | int nver, int ntri, 61 | int h, int w, int c); 62 | 63 | #endif -------------------------------------------------------------------------------- /PRNet_Mask/utils/cython/mesh_core_cython.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | cimport numpy as np 3 | from libcpp.string cimport string 4 | 5 | # use the Numpy-C-API from Cython 6 | np.import_array() 7 | 8 | # cdefine the signature of our c function 9 | cdef extern from "mesh_core.h": 10 | void _render_colors_core( 11 | float* image, float* vertices, int* triangles, 12 | float* colors, 13 | float* depth_buffer, 14 | int nver, int ntri, 15 | int h, int w, int c 16 | ) 17 | 18 | void _get_normal_core( 19 | float* normal, float* tri_normal, int* triangles, 20 | int ntri 21 | ) 22 | 23 | def get_normal_core(np.ndarray[float, ndim=2, mode = "c"] normal not None, 24 | np.ndarray[float, ndim=2, mode = "c"] tri_normal not None, 25 | np.ndarray[int, ndim=2, mode="c"] triangles not None, 26 | int ntri 27 | ): 28 | _get_normal_core( 29 | np.PyArray_DATA(normal), np.PyArray_DATA(tri_normal), np.PyArray_DATA(triangles), 30 | ntri 31 | ) 32 | 33 | def render_colors_core(np.ndarray[float, ndim=3, mode = "c"] image not None, 34 | np.ndarray[float, ndim=2, mode = "c"] vertices not None, 35 | np.ndarray[int, ndim=2, mode="c"] triangles not None, 36 | np.ndarray[float, ndim=2, mode = "c"] colors not None, 37 | np.ndarray[float, ndim=2, mode = "c"] depth_buffer not None, 38 | int nver, int ntri, 39 | int h, int w, int c 40 | ): 41 | _render_colors_core( 42 | np.PyArray_DATA(image), np.PyArray_DATA(vertices), np.PyArray_DATA(triangles), 43 | np.PyArray_DATA(colors), 44 | np.PyArray_DATA(depth_buffer), 45 | nver, ntri, 46 | h, w, c 47 | ) -------------------------------------------------------------------------------- /PRNet_Mask/utils/cython/readme.md: -------------------------------------------------------------------------------- 1 | ### Cython compiling 2 | ``` 3 | python3 setup.py build_ext -i 4 | ``` 5 | 6 | The `mesh_core_cython.*.so` will be generated. The specific name depends on your system. -------------------------------------------------------------------------------- /PRNet_Mask/utils/cython/setup.py: -------------------------------------------------------------------------------- 1 | ''' 2 | python setup.py build_ext -i 3 | to compile 4 | ''' 5 | 6 | # setup.py 7 | from distutils.core import setup, Extension 8 | # from Cython.Build import cythonize 9 | from Cython.Distutils import build_ext 10 | import numpy 11 | 12 | setup( 13 | name='mesh_core_cython', 14 | cmdclass={'build_ext': build_ext}, 15 | ext_modules=[Extension("mesh_core_cython", 16 | sources=["mesh_core_cython.pyx", "mesh_core.cpp"], 17 | language='c++', 18 | include_dirs=[numpy.get_include()])], 19 | ) 20 | -------------------------------------------------------------------------------- /PRNet_Mask/utils/estimate_pose.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from math import cos, sin, atan2, asin 3 | 4 | 5 | def isRotationMatrix(R): 6 | ''' checks if a matrix is a valid rotation matrix(whether orthogonal or not) 7 | ''' 8 | Rt = np.transpose(R) 9 | shouldBeIdentity = np.dot(Rt, R) 10 | I = np.identity(3, dtype = R.dtype) 11 | n = np.linalg.norm(I - shouldBeIdentity) 12 | return n < 1e-6 13 | 14 | 15 | def matrix2angle(R): 16 | ''' compute three Euler angles from a Rotation Matrix. Ref: http://www.gregslabaugh.net/publications/euler.pdf 17 | Args: 18 | R: (3,3). rotation matrix 19 | Returns: 20 | x: yaw 21 | y: pitch 22 | z: roll 23 | ''' 24 | # assert(isRotationMatrix(R)) 25 | 26 | if R[2,0] !=1 or R[2,0] != -1: 27 | x = asin(R[2,0]) 28 | y = atan2(R[2,1]/cos(x), R[2,2]/cos(x)) 29 | z = atan2(R[1,0]/cos(x), R[0,0]/cos(x)) 30 | 31 | else:# Gimbal lock 32 | z = 0 #can be anything 33 | if R[2,0] == -1: 34 | x = np.pi/2 35 | y = z + atan2(R[0,1], R[0,2]) 36 | else: 37 | x = -np.pi/2 38 | y = -z + atan2(-R[0,1], -R[0,2]) 39 | 40 | return x, y, z 41 | 42 | 43 | def P2sRt(P): 44 | ''' decompositing camera matrix P. 45 | Args: 46 | P: (3, 4). Affine Camera Matrix. 47 | Returns: 48 | s: scale factor. 49 | R: (3, 3). rotation matrix. 50 | t2d: (2,). 2d translation. 51 | ''' 52 | t2d = P[:2, 3] 53 | R1 = P[0:1, :3] 54 | R2 = P[1:2, :3] 55 | s = (np.linalg.norm(R1) + np.linalg.norm(R2))/2.0 56 | r1 = R1/np.linalg.norm(R1) 57 | r2 = R2/np.linalg.norm(R2) 58 | r3 = np.cross(r1, r2) 59 | 60 | R = np.concatenate((r1, r2, r3), 0) 61 | return s, R, t2d 62 | 63 | 64 | def compute_similarity_transform(points_static, points_to_transform): 65 | #http://nghiaho.com/?page_id=671 66 | p0 = np.copy(points_static).T 67 | p1 = np.copy(points_to_transform).T 68 | 69 | t0 = -np.mean(p0, axis=1).reshape(3,1) 70 | t1 = -np.mean(p1, axis=1).reshape(3,1) 71 | t_final = t1 -t0 72 | 73 | p0c = p0+t0 74 | p1c = p1+t1 75 | 76 | covariance_matrix = p0c.dot(p1c.T) 77 | U,S,V = np.linalg.svd(covariance_matrix) 78 | R = U.dot(V) 79 | if np.linalg.det(R) < 0: 80 | R[:,2] *= -1 81 | 82 | rms_d0 = np.sqrt(np.mean(np.linalg.norm(p0c, axis=0)**2)) 83 | rms_d1 = np.sqrt(np.mean(np.linalg.norm(p1c, axis=0)**2)) 84 | 85 | s = (rms_d0/rms_d1) 86 | P = np.c_[s*np.eye(3).dot(R), t_final] 87 | return P 88 | 89 | def estimate_pose(vertices, canonical_vertices): 90 | # canonical_vertices = np.load('Data/uv-data/canonical_vertices.npy') 91 | P = compute_similarity_transform(vertices, canonical_vertices) 92 | _,R,_ = P2sRt(P) # decompose affine matrix to s, R, t 93 | pose = matrix2angle(R) 94 | 95 | return P, pose 96 | -------------------------------------------------------------------------------- /PRNet_Mask/utils/render_app.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from PRNet_Mask.utils.render import vis_of_vertices, render_texture 3 | from scipy import ndimage 4 | 5 | from .cython import mesh_core_cython 6 | 7 | def crender_colors(vertices, triangles, colors, h, w, c=3, BG=None): 8 | """ render mesh with colors 9 | Args: 10 | vertices: [nver, 3] 11 | triangles: [ntri, 3] 12 | colors: [nver, 3] 13 | h: height 14 | w: width 15 | c: channel 16 | BG: background image 17 | Returns: 18 | image: [h, w, c]. rendered image./rendering. 19 | """ 20 | 21 | if BG is None: 22 | image = np.zeros((h, w, c), dtype=np.float32) 23 | else: 24 | assert BG.shape[0] == h and BG.shape[1] == w and BG.shape[2] == c 25 | image = BG 26 | depth_buffer = np.zeros([h, w], dtype=np.float32, order='C') - 999999. 27 | 28 | # to C order 29 | vertices = vertices.T.astype(np.float32).copy(order='C') 30 | triangles = triangles.T.astype(np.int32).copy(order='C') 31 | colors = colors.T.astype(np.float32).copy(order='C') 32 | 33 | mesh_core_cython.render_colors_core( 34 | image, vertices, triangles, 35 | colors, 36 | depth_buffer, 37 | vertices.shape[0], triangles.shape[0], 38 | h, w, c 39 | ) 40 | return image 41 | 42 | def get_visibility(vertices, triangles, h, w): 43 | triangles = triangles.T 44 | vertices_vis = vis_of_vertices(vertices.T, triangles, h, w) 45 | vertices_vis = vertices_vis.astype(bool) 46 | for k in range(2): 47 | tri_vis = vertices_vis[triangles[0, :]] | vertices_vis[triangles[1, :]] | vertices_vis[triangles[2, :]] 48 | ind = triangles[:, tri_vis] 49 | vertices_vis[ind] = True 50 | # for k in range(2): 51 | # tri_vis = vertices_vis[triangles[0,:]] & vertices_vis[triangles[1,:]] & vertices_vis[triangles[2,:]] 52 | # ind = triangles[:, tri_vis] 53 | # vertices_vis[ind] = True 54 | vertices_vis = vertices_vis.astype(np.float32) # 1 for visible and 0 for non-visible 55 | return vertices_vis 56 | 57 | 58 | def get_uv_mask(vertices_vis, triangles, uv_coords, h, w, resolution): 59 | triangles = triangles.T 60 | vertices_vis = vertices_vis.astype(np.float32) 61 | uv_mask = render_texture(uv_coords.T, vertices_vis[np.newaxis, :], triangles, resolution, resolution, 1) 62 | uv_mask = np.squeeze(uv_mask > 0) 63 | uv_mask = ndimage.binary_closing(uv_mask) 64 | uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) 65 | uv_mask = ndimage.binary_closing(uv_mask) 66 | uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) 67 | uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) 68 | uv_mask = ndimage.binary_erosion(uv_mask, structure=np.ones((4, 4))) 69 | uv_mask = uv_mask.astype(np.float32) 70 | 71 | return np.squeeze(uv_mask) 72 | 73 | 74 | def get_depth_image(vertices, triangles, h, w, isShow = False): 75 | z = vertices[:, 2:] 76 | if isShow: 77 | z = z/max(z) 78 | depth_image = crender_colors(vertices.T, triangles.T, z.T, h, w, 1) 79 | # depth_image = render_texture(vertices.T, z.T, triangles.T, h, w, 1) # time is so large 80 | depth_image = np.squeeze(depth_image) 81 | depth_image = depth_image / 255. 82 | return np.squeeze(depth_image) 83 | 84 | def faceCrop(img, maxbbox, scale_ratio=2): 85 | ''' 86 | crop face from image, the scale_ratio used to control margin size around face. 87 | using a margin, when aligning faces you will not lose information of face 88 | ''' 89 | xmin, ymin, xmax, ymax = maxbbox 90 | hmax, wmax, _ = img.shape 91 | x = (xmin + xmax) / 2 92 | y = (ymin + ymax) / 2 93 | w = (xmax - xmin) * scale_ratio 94 | h = (ymax - ymin) * scale_ratio 95 | # new xmin, ymin, xmax and ymax 96 | xmin = x - w / 2 97 | xmax = x + w / 2 98 | ymin = y - h / 2 99 | ymax = y + h / 2 100 | 101 | xmin = max(0, int(xmin)) 102 | ymin = max(0, int(ymin)) 103 | xmax = min(wmax, int(xmax)) 104 | ymax = min(hmax, int(ymax)) 105 | face = img[ymin:ymax, xmin:xmax, :] 106 | return face 107 | -------------------------------------------------------------------------------- /PRNet_Mask/utils/rotate_vertices.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | # import scipy.io as 4 | def frontalize(vertices): 5 | canonical_vertices = np.load('Data/uv-data/canonical_vertices.npy') 6 | 7 | vertices_homo = np.hstack((vertices, np.ones([vertices.shape[0],1]))) #n x 4 8 | P = np.linalg.lstsq(vertices_homo, canonical_vertices)[0].T # Affine matrix. 3 x 4 9 | front_vertices = vertices_homo.dot(P.T) 10 | 11 | return front_vertices 12 | -------------------------------------------------------------------------------- /SSH/.idea/SSH.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /SSH/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SSH/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /SSH/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SSH/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SSH/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd rcnn/cython/; python3 setup.py build_ext --inplace; rm -rf build; cd ../../ 3 | #cd rcnn/pycocotools/; python setup.py build_ext --inplace; rm -rf build; cd ../../ 4 | clean: 5 | cd rcnn/cython/; rm *.so *.c *.cpp; cd ../../ 6 | #cd rcnn/pycocotools/; rm *.so; cd ../../ 7 | -------------------------------------------------------------------------------- /SSH/README.md: -------------------------------------------------------------------------------- 1 | SSH, single stage face detector 2 | 3 | 预训练模型参见 4 | https://github.com/bleakie/mxnet-ssh-face-detection/tree/master/model 5 | 6 | -------------------------------------------------------------------------------- /SSH/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSH/__init__.py -------------------------------------------------------------------------------- /SSH/model/readme: -------------------------------------------------------------------------------- 1 | # 更新说明 2 | 2019.01.09: v4是release的第一个版本 3 | 2018.01.20: v5.0是新数据上的第一个方法,在error上只有头巾错误 4 | 2018.01.23: v5.1是新数据上COLOR_JITTERING=0,在error上只有头巾错误,目前是效果最好的 5 | pre-train model: https://github.com/bleakie/mxnet-ssh-face-detection/tree/master/model 6 | -------------------------------------------------------------------------------- /SSH/rcnn/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSH/rcnn/__init__.py -------------------------------------------------------------------------------- /SSH/rcnn/config.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from easydict import EasyDict as edict 3 | 4 | config = edict() 5 | 6 | config.TEST = edict() 7 | 8 | # RCNN nms 9 | config.TEST.NMS = 0.3 10 | 11 | config.TEST.SCORE_THRESH = 0.85 12 | 13 | # scale changed as smallhard face 14 | config.TEST.SCALES = [100, 1000]#[50,100,300,600,] 15 | config.TEST.PYRAMID_SCALES = [1.0] 16 | config.TEST.CONSTANT = 30 17 | # default settings 18 | default = edict() 19 | -------------------------------------------------------------------------------- /SSH/rcnn/cython/.gitignore: -------------------------------------------------------------------------------- 1 | *.c 2 | *.cpp 3 | *.so 4 | -------------------------------------------------------------------------------- /SSH/rcnn/cython/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSH/rcnn/cython/__init__.py -------------------------------------------------------------------------------- /SSH/rcnn/cython/anchors.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | import numpy as np 3 | cimport numpy as np 4 | 5 | DTYPE = np.float32 6 | ctypedef np.float32_t DTYPE_t 7 | 8 | def anchors_cython(int height, int width, int stride, np.ndarray[DTYPE_t, ndim=2] base_anchors): 9 | """ 10 | Parameters 11 | ---------- 12 | height: height of plane 13 | width: width of plane 14 | stride: stride ot the original image 15 | anchors_base: (A, 4) a base set of anchors 16 | Returns 17 | ------- 18 | all_anchors: (height, width, A, 4) ndarray of anchors spreading over the plane 19 | """ 20 | cdef unsigned int A = base_anchors.shape[0] 21 | cdef np.ndarray[DTYPE_t, ndim=4] all_anchors = np.zeros((height, width, A, 4), dtype=DTYPE) 22 | cdef unsigned int iw, ih 23 | cdef unsigned int k 24 | cdef unsigned int sh 25 | cdef unsigned int sw 26 | for iw in range(width): 27 | sw = iw * stride 28 | for ih in range(height): 29 | sh = ih * stride 30 | for k in range(A): 31 | all_anchors[ih, iw, k, 0] = base_anchors[k, 0] + sw 32 | all_anchors[ih, iw, k, 1] = base_anchors[k, 1] + sh 33 | all_anchors[ih, iw, k, 2] = base_anchors[k, 2] + sw 34 | all_anchors[ih, iw, k, 3] = base_anchors[k, 3] + sh 35 | return all_anchors -------------------------------------------------------------------------------- /SSH/rcnn/cython/bbox.pyx: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------- 2 | # Fast R-CNN 3 | # Copyright (c) 2015 Microsoft 4 | # Licensed under The MIT License [see LICENSE for details] 5 | # Written by Sergey Karayev 6 | # -------------------------------------------------------- 7 | 8 | cimport cython 9 | import numpy as np 10 | cimport numpy as np 11 | 12 | DTYPE = np.float 13 | ctypedef np.float_t DTYPE_t 14 | 15 | def bbox_overlaps_cython( 16 | np.ndarray[DTYPE_t, ndim=2] boxes, 17 | np.ndarray[DTYPE_t, ndim=2] query_boxes): 18 | """ 19 | Parameters 20 | ---------- 21 | boxes: (N, 4) ndarray of float 22 | query_boxes: (K, 4) ndarray of float 23 | Returns 24 | ------- 25 | overlaps: (N, K) ndarray of overlap between boxes and query_boxes 26 | """ 27 | cdef unsigned int N = boxes.shape[0] 28 | cdef unsigned int K = query_boxes.shape[0] 29 | cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE) 30 | cdef DTYPE_t iw, ih, box_area 31 | cdef DTYPE_t ua 32 | cdef unsigned int k, n 33 | for k in range(K): 34 | box_area = ( 35 | (query_boxes[k, 2] - query_boxes[k, 0] + 1) * 36 | (query_boxes[k, 3] - query_boxes[k, 1] + 1) 37 | ) 38 | for n in range(N): 39 | iw = ( 40 | min(boxes[n, 2], query_boxes[k, 2]) - 41 | max(boxes[n, 0], query_boxes[k, 0]) + 1 42 | ) 43 | if iw > 0: 44 | ih = ( 45 | min(boxes[n, 3], query_boxes[k, 3]) - 46 | max(boxes[n, 1], query_boxes[k, 1]) + 1 47 | ) 48 | if ih > 0: 49 | ua = float( 50 | (boxes[n, 2] - boxes[n, 0] + 1) * 51 | (boxes[n, 3] - boxes[n, 1] + 1) + 52 | box_area - iw * ih 53 | ) 54 | overlaps[n, k] = iw * ih / ua 55 | return overlaps 56 | -------------------------------------------------------------------------------- /SSH/rcnn/cython/cpu_nms.pyx: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------- 2 | # Fast R-CNN 3 | # Copyright (c) 2015 Microsoft 4 | # Licensed under The MIT License [see LICENSE for details] 5 | # Written by Ross Girshick 6 | # -------------------------------------------------------- 7 | 8 | import numpy as np 9 | cimport numpy as np 10 | 11 | cdef inline np.float32_t max(np.float32_t a, np.float32_t b): 12 | return a if a >= b else b 13 | 14 | cdef inline np.float32_t min(np.float32_t a, np.float32_t b): 15 | return a if a <= b else b 16 | 17 | def cpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh): 18 | cdef np.ndarray[np.float32_t, ndim=1] x1 = dets[:, 0] 19 | cdef np.ndarray[np.float32_t, ndim=1] y1 = dets[:, 1] 20 | cdef np.ndarray[np.float32_t, ndim=1] x2 = dets[:, 2] 21 | cdef np.ndarray[np.float32_t, ndim=1] y2 = dets[:, 3] 22 | cdef np.ndarray[np.float32_t, ndim=1] scores = dets[:, 4] 23 | 24 | cdef np.ndarray[np.float32_t, ndim=1] areas = (x2 - x1 + 1) * (y2 - y1 + 1) 25 | cdef np.ndarray[np.int_t, ndim=1] order = scores.argsort()[::-1] 26 | 27 | cdef int ndets = dets.shape[0] 28 | cdef np.ndarray[np.int_t, ndim=1] suppressed = \ 29 | np.zeros((ndets), dtype=np.int) 30 | 31 | # nominal indices 32 | cdef int _i, _j 33 | # sorted indices 34 | cdef int i, j 35 | # temp variables for box i's (the box currently under consideration) 36 | cdef np.float32_t ix1, iy1, ix2, iy2, iarea 37 | # variables for computing overlap with box j (lower scoring box) 38 | cdef np.float32_t xx1, yy1, xx2, yy2 39 | cdef np.float32_t w, h 40 | cdef np.float32_t inter, ovr 41 | 42 | keep = [] 43 | for _i in range(ndets): 44 | i = order[_i] 45 | if suppressed[i] == 1: 46 | continue 47 | keep.append(i) 48 | ix1 = x1[i] 49 | iy1 = y1[i] 50 | ix2 = x2[i] 51 | iy2 = y2[i] 52 | iarea = areas[i] 53 | for _j in range(_i + 1, ndets): 54 | j = order[_j] 55 | if suppressed[j] == 1: 56 | continue 57 | xx1 = max(ix1, x1[j]) 58 | yy1 = max(iy1, y1[j]) 59 | xx2 = min(ix2, x2[j]) 60 | yy2 = min(iy2, y2[j]) 61 | w = max(0.0, xx2 - xx1 + 1) 62 | h = max(0.0, yy2 - yy1 + 1) 63 | inter = w * h 64 | ovr = inter / (iarea + areas[j] - inter) 65 | if ovr >= thresh: 66 | suppressed[j] = 1 67 | 68 | return keep 69 | -------------------------------------------------------------------------------- /SSH/rcnn/cython/gpu_nms.hpp: -------------------------------------------------------------------------------- 1 | void _nms(int* keep_out, int* num_out, const float* boxes_host, int boxes_num, 2 | int boxes_dim, float nms_overlap_thresh, int device_id); 3 | -------------------------------------------------------------------------------- /SSH/rcnn/cython/gpu_nms.pyx: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------- 2 | # Faster R-CNN 3 | # Copyright (c) 2015 Microsoft 4 | # Licensed under The MIT License [see LICENSE for details] 5 | # Written by Ross Girshick 6 | # -------------------------------------------------------- 7 | 8 | import numpy as np 9 | cimport numpy as np 10 | 11 | assert sizeof(int) == sizeof(np.int32_t) 12 | 13 | cdef extern from "gpu_nms.hpp": 14 | void _nms(np.int32_t*, int*, np.float32_t*, int, int, float, int) 15 | 16 | def gpu_nms(np.ndarray[np.float32_t, ndim=2] dets, np.float thresh, 17 | np.int32_t device_id=0): 18 | cdef int boxes_num = dets.shape[0] 19 | cdef int boxes_dim = dets.shape[1] 20 | cdef int num_out 21 | cdef np.ndarray[np.int32_t, ndim=1] \ 22 | keep = np.zeros(boxes_num, dtype=np.int32) 23 | cdef np.ndarray[np.float32_t, ndim=1] \ 24 | scores = dets[:, 4] 25 | cdef np.ndarray[np.int_t, ndim=1] \ 26 | order = scores.argsort()[::-1] 27 | cdef np.ndarray[np.float32_t, ndim=2] \ 28 | sorted_dets = dets[order, :] 29 | _nms(&keep[0], &num_out, &sorted_dets[0, 0], boxes_num, boxes_dim, thresh, device_id) 30 | keep = keep[:num_out] 31 | return list(order[keep]) 32 | -------------------------------------------------------------------------------- /SSH/rcnn/processing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSH/rcnn/processing/__init__.py -------------------------------------------------------------------------------- /SSH/rcnn/processing/generate_anchor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generate base anchors on index 0 3 | """ 4 | from __future__ import print_function 5 | import sys 6 | #from builtins import range 7 | import numpy as np 8 | from ..cython.anchors import anchors_cython 9 | 10 | 11 | def anchors_plane(feat_h, feat_w, stride, base_anchor): 12 | return anchors_cython(feat_h, feat_w, stride, base_anchor) 13 | 14 | def generate_anchors(base_size=16, ratios=[0.5, 1, 2], 15 | scales=2 ** np.arange(3, 6)): 16 | """ 17 | Generate anchor (reference) windows by enumerating aspect ratios X 18 | scales wrt a reference (0, 0, 15, 15) window. 19 | """ 20 | 21 | base_anchor = np.array([1, 1, base_size, base_size]) - 1 22 | ratio_anchors = _ratio_enum(base_anchor, ratios) 23 | anchors = np.vstack([_scale_enum(ratio_anchors[i, :], scales) 24 | for i in range(ratio_anchors.shape[0])]) 25 | return anchors 26 | 27 | def generate_anchors_fpn(base_size=[64,32,16,8,4], ratios=[0.5, 1, 2], 28 | scales=8): 29 | """ 30 | Generate anchor (reference) windows by enumerating aspect ratios X 31 | scales wrt a reference (0, 0, 15, 15) window. 32 | """ 33 | anchors = [] 34 | _ratios = ratios.reshape( (len(base_size), -1) ) 35 | _scales = scales.reshape( (len(base_size), -1) ) 36 | for i,bs in enumerate(base_size): 37 | __ratios = _ratios[i] 38 | __scales = _scales[i] 39 | #print('anchors_fpn', bs, __ratios, __scales, file=sys.stderr) 40 | r = generate_anchors(bs, __ratios, __scales) 41 | #print('anchors_fpn', r.shape, file=sys.stderr) 42 | anchors.append(r) 43 | 44 | return anchors 45 | 46 | def _whctrs(anchor): 47 | """ 48 | Return width, height, x center, and y center for an anchor (window). 49 | """ 50 | 51 | w = anchor[2] - anchor[0] + 1 52 | h = anchor[3] - anchor[1] + 1 53 | x_ctr = anchor[0] + 0.5 * (w - 1) 54 | y_ctr = anchor[1] + 0.5 * (h - 1) 55 | return w, h, x_ctr, y_ctr 56 | 57 | 58 | def _mkanchors(ws, hs, x_ctr, y_ctr): 59 | """ 60 | Given a vector of widths (ws) and heights (hs) around a center 61 | (x_ctr, y_ctr), output a set of anchors (windows). 62 | """ 63 | 64 | ws = ws[:, np.newaxis] 65 | hs = hs[:, np.newaxis] 66 | anchors = np.hstack((x_ctr - 0.5 * (ws - 1), 67 | y_ctr - 0.5 * (hs - 1), 68 | x_ctr + 0.5 * (ws - 1), 69 | y_ctr + 0.5 * (hs - 1))) 70 | return anchors 71 | 72 | 73 | def _ratio_enum(anchor, ratios): 74 | """ 75 | Enumerate a set of anchors for each aspect ratio wrt an anchor. 76 | """ 77 | 78 | w, h, x_ctr, y_ctr = _whctrs(anchor) 79 | size = w * h 80 | size_ratios = size / ratios 81 | ws = np.round(np.sqrt(size_ratios)) 82 | hs = np.round(ws * ratios) 83 | anchors = _mkanchors(ws, hs, x_ctr, y_ctr) 84 | return anchors 85 | 86 | 87 | def _scale_enum(anchor, scales): 88 | """ 89 | Enumerate a set of anchors for each scale wrt an anchor. 90 | """ 91 | 92 | w, h, x_ctr, y_ctr = _whctrs(anchor) 93 | ws = w * scales 94 | hs = h * scales 95 | anchors = _mkanchors(ws, hs, x_ctr, y_ctr) 96 | return anchors 97 | -------------------------------------------------------------------------------- /SSH/rcnn/processing/nms.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..cython.cpu_nms import cpu_nms 3 | try: 4 | from ..cython.gpu_nms import gpu_nms 5 | except ImportError: 6 | gpu_nms = None 7 | 8 | 9 | def py_nms_wrapper(thresh): 10 | def _nms(dets): 11 | return nms(dets, thresh) 12 | return _nms 13 | 14 | 15 | def cpu_nms_wrapper(thresh): 16 | def _nms(dets): 17 | return cpu_nms(dets, thresh) 18 | return _nms 19 | 20 | 21 | def gpu_nms_wrapper(thresh, device_id): 22 | def _nms(dets): 23 | return gpu_nms(dets, thresh, device_id) 24 | if gpu_nms is not None: 25 | return _nms 26 | else: 27 | return cpu_nms_wrapper(thresh) 28 | 29 | 30 | def nms(dets, thresh): 31 | """ 32 | greedily select boxes with high confidence and overlap with current maximum <= thresh 33 | rule out overlap >= thresh 34 | :param dets: [[x1, y1, x2, y2 score]] 35 | :param thresh: retain overlap < thresh 36 | :return: indexes to keep 37 | """ 38 | x1 = dets[:, 0] 39 | y1 = dets[:, 1] 40 | x2 = dets[:, 2] 41 | y2 = dets[:, 3] 42 | scores = dets[:, 4] 43 | 44 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 45 | order = scores.argsort()[::-1] 46 | 47 | keep = [] 48 | while order.size > 0: 49 | i = order[0] 50 | keep.append(i) 51 | xx1 = np.maximum(x1[i], x1[order[1:]]) 52 | yy1 = np.maximum(y1[i], y1[order[1:]]) 53 | xx2 = np.minimum(x2[i], x2[order[1:]]) 54 | yy2 = np.minimum(y2[i], y2[order[1:]]) 55 | 56 | w = np.maximum(0.0, xx2 - xx1 + 1) 57 | h = np.maximum(0.0, yy2 - yy1 + 1) 58 | inter = w * h 59 | ovr = inter / (areas[i] + areas[order[1:]] - inter) 60 | 61 | inds = np.where(ovr <= thresh)[0] 62 | order = order[inds + 1] 63 | 64 | return keep 65 | 66 | def bbox_vote(det): 67 | order = det[:, 4].ravel().argsort()[::-1] 68 | det = det[order, :] 69 | while det.shape[0] > 0: 70 | # IOU 71 | area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) 72 | xx1 = np.maximum(det[0, 0], det[:, 0]) 73 | yy1 = np.maximum(det[0, 1], det[:, 1]) 74 | xx2 = np.minimum(det[0, 2], det[:, 2]) 75 | yy2 = np.minimum(det[0, 3], det[:, 3]) 76 | w = np.maximum(0.0, xx2 - xx1 + 1) 77 | h = np.maximum(0.0, yy2 - yy1 + 1) 78 | inter = w * h 79 | o = inter / (area[0] + area[:] - inter) 80 | 81 | # get needed merge det and delete these det 82 | merge_index = np.where(o >= 0.3)[0] 83 | det_accu = det[merge_index, :] 84 | det = np.delete(det, merge_index, 0) 85 | 86 | if merge_index.shape[0] <= 1: 87 | continue 88 | det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) 89 | max_score = np.max(det_accu[:, 4]) 90 | det_accu_sum = np.zeros((1, 5)) 91 | det_accu_sum[:, 0:4] = np.sum(det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) 92 | det_accu_sum[:, 4] = max_score 93 | try: 94 | dets = np.row_stack((dets, det_accu_sum)) 95 | except: 96 | dets = det_accu_sum 97 | 98 | dets = dets[0:750, :] 99 | return dets 100 | -------------------------------------------------------------------------------- /SSR-Net/README.md: -------------------------------------------------------------------------------- 1 | # SSR-Net 2 | **[IJCAI18] SSR-Net: A Compact Soft Stagewise Regression Network for Age Estimation** 3 | + A real-time age estimation model with 0.32MB. 4 | + Gender regression is also added! 5 | + Megaage-Asian is provided in https://github.com/b02901145/SSR-Net_megaage-asian 6 | + Coreml model (0.17MB) is provided in https://github.com/shamangary/Keras-to-coreml-multiple-inputs-example 7 | 8 | **Code Author: Tsun-Yi Yang** 9 | 10 | ## Paper 11 | 12 | ### PDF 13 | https://github.com/shamangary/SSR-Net/blob/master/ijcai18_ssrnet_pdfa_2b.pdf 14 | 15 | ### Paper authors 16 | **[Tsun-Yi Yang](http://shamangary.logdown.com/), [Yi-Husan Huang](https://github.com/b02901145), [Yen-Yu Lin](https://www.citi.sinica.edu.tw/pages/yylin/index_zh.html), [Pi-Cheng Hsiu](https://www.citi.sinica.edu.tw/pages/pchsiu/index_en.html), and [Yung-Yu Chuang](https://www.csie.ntu.edu.tw/~cyy/)** 17 | 18 | ## Abstract 19 | This paper presents a novel CNN model called Soft Stagewise Regression Network (SSR-Net) for age estimation from a single image with a compact model size. Inspired by DEX, we address age estimation by performing multi-class classification and then turning classification results into regression by calculating the expected values. SSR-Net takes a coarse-to-fine strategy and performs multi-class classification with multiple stages. Each stage is only responsible for refining the decision of the previous stage. Thus, each stage performs a task with few classes and requires few neurons, greatly reducing the model size. For addressing the quantization issue introduced by grouping ages into classes, SSR-Net assigns a dynamic range to each age class by allowing it to be shifted and scaled according to the input face image. Both the multi-stage strategy and the dynamic range are incorporated into the formulation of soft stagewise regression. A novel network architecture is proposed for carrying out soft stagewise regression. The resultant SSR-Net model is very compact and takes only **0.32 MB**. Despite of its compact size, SSR-Net’s performance approaches those of the state-of-the-art methods whose model sizes are more than 1500x larger. 20 | 21 | ## Test 22 | ``` 23 | python3 TYY_demo_centerface_bbox_age_gender.py 24 | ``` 25 | 26 | 27 | ## Result 28 | | gender(%) | age MAE | age RMSE | Speed(ms) | 29 | |--------------|-----------|--------------|----------| 30 | |98.53 | 3.29 | 4.25 | 3 | 31 | 32 | ``` 33 | 34 | ## Third Party Implementation 35 | + MXNET: 36 | https://github.com/wayen820/gender_age_estimation_mxnet 37 | 38 | + Pytorch: 39 | https://github.com/oukohou/SSR_Net_Pytorch 40 | 41 | + Pytorch: 42 | https://github.com/CrazySummerday/SSR-Net 43 | -------------------------------------------------------------------------------- /SSR-Net/data/TYY_IMDBWIKI_create_db.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import os 4 | import csv 5 | import argparse 6 | from tqdm import tqdm 7 | from TYY_utils import get_meta 8 | 9 | 10 | def get_args(): 11 | parser = argparse.ArgumentParser(description="This script cleans-up noisy labels " 12 | "and creates database for training.", 13 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 14 | parser.add_argument("--output", "-o", type=str, default='/home/sai/YANG/datasets/face_datasets/wiki/', 15 | help="path to output database mat file") 16 | parser.add_argument("--input", type=str, default="/home/sai/YANG/datasets/face_datasets/wiki/gender_age_bbox_crop/", 17 | help="dataset; wiki or imdb") 18 | parser.add_argument("--img_size", type=int, default=112, 19 | help="output image size") 20 | parser.add_argument("--min_score", type=float, default=1.0, 21 | help="minimum face_score") 22 | parser.add_argument("--label", type=str, default='/home/sai/YANG/datasets/face_datasets/wiki/label.csv', 23 | help="path to output database mat file") 24 | args = parser.parse_args() 25 | return args 26 | 27 | 28 | def main_gender_age(): 29 | args = get_args() 30 | labelList = csv.reader(open(args.label, "rt", encoding="utf-8-sig")) 31 | out_ages = [] 32 | out_imgs = [] 33 | out_genders = [] 34 | for row in labelList: 35 | true_age = row[2] 36 | true_gender = row[1] 37 | img_id = row[0] 38 | img_path = os.path.join(args.input, img_id) 39 | img = cv2.imread(img_path) 40 | if img is None: 41 | continue 42 | out_genders.append(int(true_gender)) 43 | out_ages.append(int(true_age)) 44 | out_imgs.append(cv2.resize(img, (args.img_size, args.img_size))) 45 | print('len:', len(out_imgs)) 46 | np.savez('train_data/wiki_bbox_crop.npz',image=np.array(out_imgs), gender=np.array(out_genders), age=np.array(out_ages), img_size=args.img_size) 47 | 48 | 49 | def main_csv(): 50 | args = get_args() 51 | output_path = args.output 52 | db = args.input 53 | min_score = args.min_score 54 | 55 | mat_path = os.path.join(db, "{}.mat".format('wiki')) 56 | full_path, dob, gender, photo_taken, face_score, second_face_score, age = get_meta(mat_path, 'wiki') 57 | output_data = [] 58 | for i in tqdm(range(len(face_score))): 59 | if face_score[i] < min_score: 60 | continue 61 | if (~np.isnan(second_face_score[i])) and second_face_score[i] > 0.0: 62 | continue 63 | if ~(0 <= age[i] <= 100): 64 | continue 65 | if np.isnan(gender[i]): 66 | continue 67 | img_id = str(full_path[i][0]) 68 | 69 | save_path = os.path.join(output_path, img_id.split('/')[1]) 70 | img_path = os.path.join(db, str(full_path[i][0])) 71 | import shutil 72 | shutil.copy(img_path, save_path) 73 | output_data.append({'gender':gender[i], 'age':age[i], 'id': img_id.split('/')[1]}) 74 | with open(args.label, 'w') as f: 75 | headers = ['id', 'gender', 'age'] 76 | f_scv = csv.DictWriter(f, headers) 77 | f_scv.writeheader() 78 | f_scv.writerows(np.array(output_data)) 79 | 80 | if __name__ == '__main__': 81 | main_gender_age() 82 | -------------------------------------------------------------------------------- /SSR-Net/data/TYY_XSDATA_create_db.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import os 4 | import argparse 5 | import csv 6 | 7 | 8 | def get_args(): 9 | parser = argparse.ArgumentParser(description="This script cleans-up noisy labels " 10 | "and creates database for training.", 11 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 12 | parser.add_argument("--input", type=str, default="/home/sai/YANG/datasets/face_datasets/megaage_asian/megaage_asian/train_crop/", 13 | help="dataset; wiki or imdb") 14 | parser.add_argument("--output", type=str, default='/home/sai/YANG/datasets/face_datasets/megaage_asian/megaage_asian/megaage_asian.npz', 15 | help="path to output database mat file") 16 | parser.add_argument('--label', default='/home/sai/YANG/datasets/face_datasets/megaage_asian/megaage_asian/train.csv', help='') 17 | parser.add_argument("--img_size", type=int, default=112, 18 | help="output image size") 19 | args = parser.parse_args() 20 | return args 21 | 22 | 23 | def main(): 24 | args = get_args() 25 | 26 | out_genders = [] 27 | out_ages = [] 28 | out_imgs = [] 29 | labelList = csv.reader(open(args.label, "rt", encoding="utf-8-sig")) 30 | for row in labelList: 31 | true_age = int(row[1]) 32 | true_gender = int(0) 33 | img_id = row[0] 34 | img = cv2.imread(os.path.join(args.input, img_id)) 35 | if img is None: 36 | continue 37 | out_genders.append(true_gender) 38 | out_ages.append(true_age) 39 | out_imgs.append(cv2.resize(img, (args.img_size, args.img_size))) 40 | 41 | np.savez(args.output, image=np.array(out_imgs), gender=np.array(out_genders), age=np.array(out_ages), 42 | img_size=args.img_size) 43 | 44 | 45 | if __name__ == '__main__': 46 | main() 47 | -------------------------------------------------------------------------------- /SSR-Net/data/TYY_utils.py: -------------------------------------------------------------------------------- 1 | from scipy.io import loadmat 2 | from datetime import datetime 3 | import os 4 | import numpy as np 5 | 6 | def calc_age(taken, dob): 7 | birth = datetime.fromordinal(max(int(dob) - 366, 1)) 8 | 9 | # assume the photo was taken in the middle of the year 10 | if birth.month < 7: 11 | return taken - birth.year 12 | else: 13 | return taken - birth.year - 1 14 | 15 | 16 | def get_meta(mat_path, db): 17 | meta = loadmat(mat_path) 18 | full_path = meta[db][0, 0]["full_path"][0] 19 | dob = meta[db][0, 0]["dob"][0] # Matlab serial date number 20 | gender = meta[db][0, 0]["gender"][0] 21 | photo_taken = meta[db][0, 0]["photo_taken"][0] # year 22 | face_score = meta[db][0, 0]["face_score"][0] 23 | second_face_score = meta[db][0, 0]["second_face_score"][0] 24 | age = [calc_age(photo_taken[i], dob[i]) for i in range(len(dob))] 25 | 26 | return full_path, dob, gender, photo_taken, face_score, second_face_score, age 27 | 28 | 29 | def load_data(mat_path): 30 | d = loadmat(mat_path) 31 | 32 | return d["image"], d["gender"][0], d["age"][0], d["db"][0], d["img_size"][0, 0], d["min_score"][0, 0] 33 | 34 | def load_data_npz(npz_path): 35 | d = np.load(npz_path) 36 | 37 | return d["image"], d["gender"], d["age"], d["img_size"] 38 | 39 | def mk_dir(dir): 40 | try: 41 | os.mkdir( dir ) 42 | except OSError: 43 | pass 44 | -------------------------------------------------------------------------------- /SSR-Net/demo/TGOP_tvbs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSR-Net/demo/TGOP_tvbs.png -------------------------------------------------------------------------------- /SSR-Net/demo/TYY_demo_centerface_bbox_age_gender.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | import numpy as np 4 | import argparse 5 | from SSRNET_model import SSR_net, SSR_net_general 6 | import csv 7 | import math 8 | import time 9 | from keras import backend as K 10 | # cudnn error 11 | from tensorflow.compat.v1 import ConfigProto 12 | from tensorflow.compat.v1 import InteractiveSession 13 | 14 | config = ConfigProto() 15 | config.gpu_options.allow_growth = True 16 | session = InteractiveSession(config=config) 17 | 18 | 19 | def model_init(args): 20 | K.set_learning_phase(0) # make sure its testing mode 21 | # load model and weights 22 | stage_num = [3, 3, 3] 23 | lambda_local = 1 24 | lambda_d = 1 25 | model_age = SSR_net(args.image_size, stage_num, lambda_local, lambda_d)() 26 | model_age.load_weights(args.age_model) 27 | 28 | model_gender = SSR_net_general(args.image_size, stage_num, lambda_local, lambda_d)() 29 | model_gender.load_weights(args.gender_model) 30 | return model_gender, model_age 31 | 32 | def parse_args(): 33 | parser = argparse.ArgumentParser(description='face model test') 34 | # general 35 | parser.add_argument('--image_size', default=112, type=int) 36 | parser.add_argument('--image', default='images', help='') 37 | parser.add_argument('--label', default='label.csv', help='') 38 | parser.add_argument('--result', default='result_age_gender.csv', help='') 39 | parser.add_argument('--age_model', 40 | default='../pre-trained/wiki_age_bbox_crop/ssrnet_3_3_3_112_0.75_1.0.h5', 41 | help='path to load model.') 42 | parser.add_argument('--gender_model', 43 | default='../pre-trained/wiki_gender_112_class3/ssrnet_3_3_3_112_1.0_1.0.h5', 44 | help='path to load model.') 45 | parser.add_argument('--gpu', default=0, type=int, help='gpu id') 46 | return parser.parse_args() 47 | 48 | 49 | def get_gender_age(args, model_age, model_gender): 50 | count = 0.; 51 | age_mae = 0.; age_rmse = 0.;gender_num = 0 52 | output_data = [] 53 | times = 0. 54 | labelList = csv.reader(open(args.label, "rt", encoding="utf-8-sig")) 55 | for row in labelList: 56 | img_id = row[0] 57 | true_age = int(row[2]) 58 | true_gender = int(row[1]) 59 | img = cv2.imread(os.path.join(args.image, img_id)) 60 | if img is None: 61 | continue 62 | count += 1 63 | if count % 5000 == 0: 64 | print(count) 65 | start_time = time.time() 66 | face = cv2.resize(img, (args.image_size, args.image_size)) 67 | face = face[np.newaxis, :] 68 | # age 69 | predicted_ages = float(model_age.predict(face)) 70 | age_mae += abs(predicted_ages - true_age) 71 | age_rmse += math.pow(predicted_ages - true_age, 2) 72 | # gender 73 | predicted_genders = float(model_gender.predict(face)) # predicted_genders < 0.5 female 74 | times += (time.time() - start_time) 75 | if (predicted_genders < 0 and true_gender < 1) or (predicted_genders >= 0 and true_gender > 0): 76 | gender_num += 1 77 | output_data.append({'id':img_id, 'true_gender': true_gender, 'true_age': true_age, 78 | 'estimate_gender': predicted_genders, 'estimate_age':predicted_ages}) 79 | age_mae = age_mae / count 80 | age_rmse = math.sqrt(age_rmse / count) 81 | gender_acc = gender_num / count 82 | print('Mean time:', times/count) 83 | 84 | with open(args.result, 'w') as f: 85 | headers = ['id', 'true_gender', 'true_age', 'estimate_gender', 'estimate_age'] 86 | f_scv = csv.DictWriter(f, headers) 87 | f_scv.writeheader() 88 | f_scv.writerows(np.array(output_data)) 89 | return gender_acc, age_mae, age_rmse 90 | 91 | if __name__ == '__main__': 92 | args = parse_args() 93 | model_gender, model_age = model_init(args) 94 | gender_acc, age_mae, age_rmse = get_gender_age(args, model_age, model_gender) 95 | print('gender_acc:', gender_acc, 'age_mae:', age_mae, 'age_rmse:', age_rmse) 96 | 97 | # gender: 0.9853605560382276 98 | # age_mae: 3.2959095643355885 99 | # age_rmse: 4.256980842189304 -------------------------------------------------------------------------------- /SSR-Net/pre-trained/wiki_age_bbox_crop/ssrnet_3_3_3_112_0.75_1.0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSR-Net/pre-trained/wiki_age_bbox_crop/ssrnet_3_3_3_112_0.75_1.0.h5 -------------------------------------------------------------------------------- /SSR-Net/pre-trained/wiki_gender_112_class3/ssrnet_3_3_3_112_1.0_1.0.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/SSR-Net/pre-trained/wiki_gender_112_class3/ssrnet_3_3_3_112_1.0_1.0.h5 -------------------------------------------------------------------------------- /TensorFace/.idea/TensorFace.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 15 | -------------------------------------------------------------------------------- /TensorFace/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /TensorFace/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /TensorFace/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TensorFace/README.md: -------------------------------------------------------------------------------- 1 | ## insightface TensorRT转换 ## 2 | 3 | ### 0.安装 4 | 5 | ``` 6 | tensorrt>=7.2 7 | ``` 8 | 9 | ### 1.模型转换 10 | 11 | 参见InsightFace-REST:[**InsightFace-REST**](https://github.com/SthPhoenix/InsightFace-REST) 12 | 13 | 14 | ### List of supported models: 15 | 16 | #### Detection: 17 | 18 | | Model | Auto download | Inference code | Source | 19 | |:----------------------|:--------------|:---------------|:------------------------------------------------------------------------------------------------| 20 | | retinaface_r50_v1 | Yes | Yes | [official package](https://github.com/deepinsight/insightface/tree/master/python-package) | 21 | | retinaface_mnet025_v1 | Yes | Yes | [official package](https://github.com/deepinsight/insightface/tree/master/python-package) | 22 | | retinaface_mnet025_v2 | Yes | Yes | [official package](https://github.com/deepinsight/insightface/tree/master/python-package) | 23 | | mnet_cov2 | No | Yes | [mnet_cov2](https://github.com/deepinsight/insightface/tree/master/detection/RetinaFaceAntiCov) | 24 | | centerface | Yes | Yes | [Star-Clouds/CenterFace](https://github.com/Star-Clouds/CenterFace) | 25 | 26 | #### Recognition: 27 | 28 | | Model | Auto download | Inference code | Source | 29 | |:-----------------------|:--------------|:---------------|:----------------------------------------------------------------------------------------------------------| 30 | | arcface_r100_v1 | Yes | Yes | [official package](https://github.com/deepinsight/insightface/tree/master/python-package) | 31 | | r100-arcface-msfdrop75 | No | Yes | [SubCenter-ArcFace](https://github.com/deepinsight/insightface/tree/master/recognition/SubCenter-ArcFace) | 32 | | r50-arcface-msfdrop75 | No | Yes | [SubCenter-ArcFace](https://github.com/deepinsight/insightface/tree/master/recognition/SubCenter-ArcFace) | 33 | | glint360k_r100FC_1.0 | No | Yes | [Partial-FC](https://github.com/deepinsight/insightface/tree/master/recognition/partial_fc) | 34 | | glint360k_r100FC_0.1 | No | Yes | [Partial-FC](https://github.com/deepinsight/insightface/tree/master/recognition/partial_fc) | 35 | 36 | #### Other: 37 | 38 | | Model | Auto download | Inference code | Source | 39 | |:-------------|:--------------|:---------------|:------------------------------------------------------------------------------------------------| 40 | | genderage_v1 | Yes | Yes | [official package](https://github.com/deepinsight/insightface/tree/master/python-package) | 41 | | 2d106det | No | No | [coordinateReg](https://github.com/deepinsight/insightface/tree/master/alignment/coordinateReg) | 42 | 43 | 44 | ### 2.训练 45 | #### 运行测试 46 | 47 | ``` 48 | python demo.py 49 | ``` 50 | 51 | 52 | #### 2.1.模型下载 53 | 54 | | Backbone | 差距 | Speed | Download | 55 | |---------------------|-----------|---------|------------| 56 | |glint360k_r100FC_1.0 | 0.0001 | 8× |[**code:ty5u**]() | 57 | 58 | -------------------------------------------------------------------------------- /TensorFace/common/face_align.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from skimage import transform as trans 4 | 5 | src1 = np.array([ 6 | [51.642, 50.115], 7 | [57.617, 49.990], 8 | [35.740, 69.007], 9 | [51.157, 89.050], 10 | [57.025, 89.702]], dtype=np.float32) 11 | # <--left 12 | src2 = np.array([ 13 | [45.031, 50.118], 14 | [65.568, 50.872], 15 | [39.677, 68.111], 16 | [45.177, 86.190], 17 | [64.246, 86.758]], dtype=np.float32) 18 | 19 | # ---frontal 20 | src3 = np.array([ 21 | [39.730, 51.138], 22 | [72.270, 51.138], 23 | [56.000, 68.493], 24 | [42.463, 87.010], 25 | [69.537, 87.010]], dtype=np.float32) 26 | 27 | # -->right 28 | src4 = np.array([ 29 | [46.845, 50.872], 30 | [67.382, 50.118], 31 | [72.737, 68.111], 32 | [48.167, 86.758], 33 | [67.236, 86.190]], dtype=np.float32) 34 | 35 | # -->right profile 36 | src5 = np.array([ 37 | [54.796, 49.990], 38 | [60.771, 50.115], 39 | [76.673, 69.007], 40 | [55.388, 89.702], 41 | [61.257, 89.050]], dtype=np.float32) 42 | 43 | src = np.array([src1, src2, src3, src4, src5]) 44 | src_map = {112: src, 224: src * 2} 45 | 46 | arcface_src = np.array([ 47 | [38.2946, 51.6963], 48 | [73.5318, 51.5014], 49 | [56.0252, 71.7366], 50 | [41.5493, 92.3655], 51 | [70.7299, 92.2041]], dtype=np.float32) 52 | 53 | REFERENCE_FACIAL_POINTS = np.array([ 54 | [38.29459953, 51.69630051], 55 | [73.53179932, 51.50139999], 56 | [56.02519989, 71.73660278], 57 | [41.54930115, 92.3655014], 58 | [70.72990036, 92.20410156]], np.float32) 59 | 60 | arcface_src = np.expand_dims(arcface_src, axis=0) 61 | 62 | # In[66]: 63 | from numpy.linalg import inv, norm, lstsq 64 | from numpy.linalg import matrix_rank as rank 65 | 66 | 67 | def findNonreflectiveSimilarity(uv, xy, K=2): 68 | M = xy.shape[0] 69 | x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector 70 | y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector 71 | 72 | tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1)))) 73 | tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1)))) 74 | X = np.vstack((tmp1, tmp2)) 75 | 76 | u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector 77 | v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector 78 | U = np.vstack((u, v)) 79 | 80 | # We know that X * r = U 81 | if rank(X) >= 2 * K: 82 | r, _, _, _ = lstsq(X, U) 83 | r = np.squeeze(r) 84 | else: 85 | raise Exception('cp2tform:twoUniquePointsReq') 86 | sc = r[0] 87 | ss = r[1] 88 | tx = r[2] 89 | ty = r[3] 90 | 91 | Tinv = np.array([ 92 | [sc, -ss, 0], 93 | [ss, sc, 0], 94 | [tx, ty, 1] 95 | ]) 96 | T = inv(Tinv) 97 | T[:, 2] = np.array([0, 0, 1]) 98 | T = T[:, 0:2].T 99 | return T 100 | 101 | 102 | # lmk is prediction; src is template 103 | def estimate_norm(lmk, image_size=112, mode='arcface'): 104 | assert lmk.shape == (5, 2) 105 | tform = trans.SimilarityTransform() 106 | lmk_tran = np.insert(lmk, 2, values=np.ones(5), axis=1) 107 | min_M = [] 108 | min_index = [] 109 | min_error = float('inf') 110 | if mode == 'arcface': 111 | assert image_size == 112 112 | src = arcface_src 113 | else: 114 | src = src_map[image_size] 115 | for i in np.arange(src.shape[0]): 116 | tform.estimate(lmk, src[i]) 117 | M = tform.params[0:2, :] 118 | results = np.dot(M, lmk_tran.T) 119 | results = results.T 120 | error = np.sum(np.sqrt(np.sum((results - src[i]) ** 2, axis=1))) 121 | # print(error) 122 | if error < min_error: 123 | min_error = error 124 | min_M = M 125 | min_index = i 126 | return min_M, min_index 127 | 128 | 129 | def norm_crop(img, landmark, image_size=[112,112], mode='arcface'): 130 | M, pose_index = estimate_norm(landmark, image_size[0], mode) 131 | # M = findNonreflectiveSimilarity(landmark, REFERENCE_FACIAL_POINTS) 132 | warped = cv2.warpAffine(img, M, (image_size[0], image_size[1]), borderValue=0.0) 133 | # align_landmark = landmark.copy() 134 | # for k in range(len(landmark)): 135 | # x_tans = M[0][0] * landmark[k][0] + M[0][1] * landmark[k][1] + M[0][2]; 136 | # y_tans = M[1][0] * landmark[k][0] + M[1][1] * landmark[k][1] + M[1][2]; 137 | # align_landmark[k][0] = x_tans 138 | # align_landmark[k][1] = y_tans 139 | return warped # , align_landmark 140 | -------------------------------------------------------------------------------- /TensorFace/common/face_preprocess.py: -------------------------------------------------------------------------------- 1 | 2 | import cv2 3 | import numpy as np 4 | from skimage import transform as trans 5 | 6 | 7 | def read_image(img_path, **kwargs): 8 | mode = kwargs.get('mode', 'rgb') 9 | layout = kwargs.get('layout', 'HWC') 10 | if mode=='gray': 11 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_GRAYSCALE) 12 | else: 13 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_COLOR) 14 | if mode=='rgb': 15 | #print('to rgb') 16 | img = img[...,::-1] 17 | if layout=='CHW': 18 | img = np.transpose(img, (2,0,1)) 19 | return img 20 | 21 | 22 | def preprocess(img, bbox=None, landmark=None, **kwargs): 23 | if isinstance(img, str): 24 | img = read_image(img, **kwargs) 25 | M = None 26 | image_size = [] 27 | str_image_size = kwargs.get('image_size', '') 28 | if len(str_image_size)>0: 29 | image_size = [int(x) for x in str_image_size.split(',')] 30 | if len(image_size)==1: 31 | image_size = [image_size[0], image_size[0]] 32 | assert len(image_size)==2 33 | assert image_size[0]==112 34 | assert image_size[0]==112 or image_size[1]==96 35 | if landmark is not None: 36 | assert len(image_size)==2 37 | src = np.array([ 38 | [30.2946, 51.6963], 39 | [65.5318, 51.5014], 40 | [48.0252, 71.7366], 41 | [33.5493, 92.3655], 42 | [62.7299, 92.2041] ], dtype=np.float32 ) 43 | if image_size[1]==112: 44 | src[:,0] += 8.0 45 | dst = landmark.astype(np.float32) 46 | 47 | tform = trans.SimilarityTransform() 48 | tform.estimate(dst, src) 49 | M = tform.params[0:2,:] 50 | #M = cv2.estimateRigidTransform( dst.reshape(1,5,2), src.reshape(1,5,2), False) 51 | 52 | if M is None: 53 | if bbox is None: #use center crop 54 | det = np.zeros(4, dtype=np.int32) 55 | det[0] = int(img.shape[1]*0.0625) 56 | det[1] = int(img.shape[0]*0.0625) 57 | det[2] = img.shape[1] - det[0] 58 | det[3] = img.shape[0] - det[1] 59 | else: 60 | det = bbox 61 | margin = kwargs.get('margin', 44) 62 | bb = np.zeros(4, dtype=np.int32) 63 | bb[0] = np.maximum(det[0]-margin/2, 0) 64 | bb[1] = np.maximum(det[1]-margin/2, 0) 65 | bb[2] = np.minimum(det[2]+margin/2, img.shape[1]) 66 | bb[3] = np.minimum(det[3]+margin/2, img.shape[0]) 67 | ret = img[bb[1]:bb[3],bb[0]:bb[2],:] 68 | if len(image_size)>0: 69 | ret = cv2.resize(ret, (image_size[1], image_size[0])) 70 | return ret 71 | else: #do align using landmark 72 | assert len(image_size)==2 73 | 74 | warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), borderValue = 0.0) 75 | return warped 76 | 77 | 78 | -------------------------------------------------------------------------------- /TensorFace/config.py: -------------------------------------------------------------------------------- 1 | from easydict import EasyDict as edict 2 | 3 | config = edict() 4 | config.INPUT = './imgs' 5 | 6 | 7 | config.FD = edict() 8 | config.FD.fd_conf = 0.9 9 | config.FD.image_size = [640, 640] 10 | config.FD.network = 'retinaface_r50_v1' # 'retinaface_mnet025_v2' 11 | 12 | config.FR = edict() 13 | config.FR.fr_conf = 0.3 14 | config.FR.image_size = [112, 112] 15 | config.FR.network = 'glint360k_r100FC_1.0' -------------------------------------------------------------------------------- /TensorFace/demo.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | import time 4 | import argparse 5 | import sys 6 | import numpy as np 7 | sys.path.append(os.path.dirname(__file__)) 8 | from modules.imagedata import ImageData 9 | from common.face_preprocess import preprocess 10 | from config import config 11 | from fd_retina import FD 12 | from fr_arcface import FR 13 | 14 | 15 | def face_align(src_img, fd, args): 16 | src_image = ImageData(src_img, fd.input_shape) 17 | src_image.resize_image(mode='pad') 18 | 19 | dets, lmks = fd.detector.detect(src_image.transformed_image, threshold=args.fd_conf) 20 | if dets.shape[0] > 0: 21 | bindex = fd.get_max_face(dets) 22 | landmark = lmks[bindex] 23 | bbox = dets[bindex, :4].astype(np.int) 24 | image_size = '%d,%d' % (args.fr_input_size[1], args.fr_input_size[0]) 25 | warped = preprocess(src_image.transformed_image, bbox, landmark, image_size = image_size) 26 | return warped 27 | else: 28 | return None 29 | 30 | 31 | def parse_arguments(): 32 | parser = argparse.ArgumentParser() 33 | parser.add_argument('--gpu', type=str, help='gpu id', default=0) 34 | parser.add_argument('--input', type=str, help='Directory with unaligned images.', 35 | default=config.INPUT) 36 | # FD 37 | parser.add_argument('--fd_input_size', default=config.FD.image_size) 38 | parser.add_argument('--fd_model', default=config.FD.network, help='path to load model.') 39 | parser.add_argument('--fd_conf', default=config.FD.fd_conf, help='path to load model.') 40 | # FR 41 | parser.add_argument('--fr_input_size', default=config.FR.image_size) 42 | parser.add_argument('--fr_model', default=config.FR.network, help='path to load model.') 43 | parser.add_argument('--fr_conf', default=config.FR.fr_conf, help='path to load model.') 44 | 45 | return parser.parse_args() 46 | 47 | 48 | if __name__ == '__main__': 49 | args = parse_arguments() 50 | fd = FD() 51 | fr = FR() 52 | idList = os.listdir(args.input) 53 | for id in idList: 54 | imgList = os.listdir(os.path.join(args.input, id)) 55 | start = time.time() 56 | for im in imgList: 57 | src_img = cv2.imread(os.path.join(args.input, id, 'src.jpg'), cv2.IMREAD_COLOR) 58 | card_img = cv2.imread(os.path.join(args.input, id, 'card.jpg'), cv2.IMREAD_COLOR) 59 | if src_img is None or card_img is None: 60 | continue 61 | src_warped = face_align(src_img, fd, args) 62 | if src_warped is None: 63 | continue 64 | card_warped = face_align(card_img, fd, args) 65 | if card_warped is None: 66 | continue 67 | src_emb = fr.normalize(src_warped) 68 | card_emb = fr.normalize(card_warped) 69 | sim = np.dot(src_emb, card_emb) 70 | print(id, sim) 71 | 72 | -------------------------------------------------------------------------------- /TensorFace/fd_retina.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | import time 4 | import sys 5 | import numpy as np 6 | sys.path.append(os.path.dirname(__file__)) 7 | from modules.imagedata import ImageData 8 | from modules.model_zoo.getter import get_model 9 | 10 | class FD: 11 | def __init__(self, model_name = 'retinaface_r50_v1', model_path = './models', im_size=[640, 640], fd_conf = 0.5): 12 | # model_name = 'retinaface_mnet025_v2' 13 | print('FD init...') 14 | self.detector = get_model(model_name, im_size=im_size, root_dir=model_path, force_fp16=False) 15 | self.detector.prepare(nms=0.4) 16 | self.input_shape = self.detector.input_shape[2:][::-1] 17 | self.fd_conf = fd_conf 18 | 19 | def detect(self, image): 20 | image = ImageData(image, self.input_shape) 21 | image.resize_image(mode='pad') 22 | 23 | dets, lmks = self.detector.detect(image.transformed_image, threshold=self.fd_conf) 24 | DETS, LMKS = [], [] 25 | for i in range(len(dets)): 26 | face = self.faceCrop(image, dets[i]) 27 | if min(face[2], face[3]) > 0: 28 | DETS.append(face) 29 | LMKS.append(lmks[i]) 30 | return np.array(DETS), np.array(LMKS) 31 | 32 | def faceCrop(self, img, maxbbox, scale_ratio=1.0): 33 | ''' 34 | crop face from image, the scale_ratio used to control margin size around face. 35 | using a margin, when aligning faces you will not lose information of face 36 | ''' 37 | xmin, ymin, xmax, ymax, score = maxbbox 38 | hmax, wmax, _ = img.shape 39 | x = (xmin + xmax) / 2 40 | y = (ymin + ymax) / 2 41 | w = (xmax - xmin) * scale_ratio 42 | h = (ymax - ymin) * scale_ratio 43 | # new xmin, ymin, xmax and ymax 44 | xmin = x - w / 2 45 | xmax = x + w / 2 46 | ymin = y - h / 2 47 | ymax = y + h / 2 48 | 49 | xmin = max(0, int(xmin)) 50 | ymin = max(0, int(ymin)) 51 | xmax = min(wmax, int(xmax)) 52 | ymax = min(hmax, int(ymax)) 53 | return [xmin, ymin, xmax, ymax, score] 54 | 55 | def get_max_face(self, bounding_boxes): 56 | det = bounding_boxes[:, 0:4] 57 | bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1]) 58 | bindex = np.argmax(bounding_box_size) # some extra weight on the centering 59 | return bindex 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | fd = FD() 65 | INPUT = '/media/sai/机械1/datasets/face/anti_spoofing/手机银行/imgs/XSB' 66 | imgList = os.listdir(INPUT) 67 | start = time.time() 68 | for im in imgList: 69 | image = cv2.imread(os.path.join(INPUT, im), cv2.IMREAD_COLOR) 70 | image = ImageData(image, fd.input_shape) 71 | image.resize_image(mode='pad') 72 | 73 | dets, lmks = fd.detector.detect(image.transformed_image, threshold=0.5) 74 | 75 | for i in range(dets.shape[0]): 76 | landmark5 = lmks[i].astype(np.int) 77 | for l in range(landmark5.shape[0]): 78 | cv2.circle(image.transformed_image, (landmark5[l][0], landmark5[l][1]), 1, (0, 255, 255), 2) 79 | box = dets[i].astype(np.int) 80 | cv2.rectangle(image.transformed_image, (box[0], box[1]), (box[2], box[3]), (0, 0, 255), 2) 81 | cv2.imshow('', image.transformed_image) 82 | cv2.waitKey() 83 | print((time.time()-start)/len(imgList)) 84 | -------------------------------------------------------------------------------- /TensorFace/fr_arcface.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import numpy as np 4 | import cv2 5 | import sys 6 | import numpy as np 7 | from numpy.linalg import norm 8 | sys.path.append(os.path.dirname(__file__)) 9 | from modules.model_zoo.getter import get_model 10 | 11 | class FR: 12 | def __init__(self, model_name = 'glint360k_r100FC_1.0', model_path = './models'): 13 | print('FR init...') 14 | self.model = get_model(model_name, root_dir=model_path, force_fp16=False) 15 | self.model.prepare() 16 | 17 | def normalize(self, img): 18 | embedding = self.model.get_embedding(img)[0].tolist() 19 | embedding_norm = norm(embedding) 20 | normed_embedding = embedding / embedding_norm 21 | return normed_embedding 22 | 23 | 24 | if __name__ == '__main__': 25 | fr = FR() 26 | img1 = cv2.imread('/media/sai/机械2/FACE/Test_datasets/img_ours/retina-5/02/wangwenhuan.jpg', cv2.IMREAD_COLOR) 27 | emb1 = fr.normalize(img1) 28 | 29 | import os 30 | imgList = os.listdir('/media/sai/机械2/FACE/Test_datasets/img_ours/retina-5/02') 31 | for im in imgList: 32 | img2 = cv2.imread(os.path.join('/media/sai/机械2/FACE/Test_datasets/img_ours/retina-5/02', im), cv2.IMREAD_COLOR) 33 | emb2 = fr.normalize(img2) 34 | sim = np.dot(emb1, emb2) 35 | print(im, sim) 36 | 37 | 38 | -------------------------------------------------------------------------------- /TensorFace/modules/imagedata.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | import cv2 3 | 4 | class ImageData: 5 | def __init__(self, image, max_size: List[int] = None): 6 | 7 | if max_size is None: 8 | max_size = [640, 480] 9 | 10 | if len(max_size) == 1: 11 | max_size = [max_size[0]] * 2 12 | 13 | self.orig_image = image 14 | self.transformed_image = self.orig_image 15 | self.const_width = max_size[0] 16 | self.const_height = max_size[1] 17 | self.resize_times = 0 18 | self.scale_factor = 1.0 19 | 20 | def resize_image(self, pad: bool = True, mode: str = 'pad'): 21 | self.resize_times += 1 22 | cw = int(self.const_width / self.resize_times) 23 | ch = int(self.const_height / self.resize_times) 24 | h, w, _ = self.transformed_image.shape 25 | if mode == 'stretch': 26 | self.transformed_image = cv2.resize(self.transformed_image, dsize=(self.const_width, self.const_height)) 27 | else: 28 | self.scale_factor = min(cw / w, ch / h) 29 | # If image is too small, it may contain only single face, which leads to decreased detection accuracy, 30 | # so we reduce scale factor by some factor 31 | if self.scale_factor > 5: 32 | self.scale_factor = self.scale_factor * 0.7 33 | 34 | self.transformed_image = cv2.resize(self.transformed_image, (0, 0), fx=self.scale_factor, fy=self.scale_factor, 35 | interpolation=cv2.INTER_LINEAR) 36 | if pad: 37 | # # Pad right and bottom with black border for fixed image proportions 38 | h, w, _ = self.transformed_image.shape 39 | if w < cw: 40 | self.transformed_image = cv2.copyMakeBorder(self.transformed_image, 0, 0, 0, cw - w, 41 | cv2.BORDER_CONSTANT) 42 | self.left_border = cw - w 43 | if h < ch: 44 | self.transformed_image = cv2.copyMakeBorder(self.transformed_image, 0, ch - h, 0, 0, 45 | cv2.BORDER_CONSTANT) 46 | self.bottom_border = ch - h 47 | -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/detectors/centerface.py: -------------------------------------------------------------------------------- 1 | import time 2 | import numpy as np 3 | import logging 4 | 5 | from .common.nms import nms 6 | from typing import Union 7 | from ..exec_backends.onnxrt_backend import DetectorInfer as DIO 8 | 9 | # Since TensorRT and pycuda are optional dependencies it might be not available 10 | try: 11 | from ..exec_backends.trt_backend import DetectorInfer as DIT 12 | except: 13 | DIT = None 14 | 15 | 16 | 17 | class CenterFace(object): 18 | def __init__(self, inference_backend: Union[DIT, DIO], landmarks=True): 19 | self.landmarks = landmarks 20 | self.net = inference_backend 21 | self.nms_threshold = 0.3 22 | self.input_shape = (1, 3, 480, 640) 23 | 24 | def __call__(self, img, threshold=0.5): 25 | return self.detect(img, threshold) 26 | 27 | def prepare(self, nms: float = 0.3, **kwargs): 28 | self.nms_threshold = nms 29 | self.net.prepare() 30 | self.input_shape = self.net.input_shape 31 | 32 | def detect(self, img: np.ndarray, threshold: float = 0.4): 33 | h, w = img.shape[:2] 34 | blob = np.expand_dims(img[:, :, (2, 1, 0)].transpose(2, 0, 1), axis=0).astype("float32") 35 | t0 = time.time() 36 | heatmap, scale, offset, lms = self.net.run(blob) 37 | t1 = time.time() 38 | logging.debug(f"Centerface inference took: {t1 - t0}") 39 | return self.postprocess(heatmap, lms, offset, scale, (h, w), threshold) 40 | 41 | def postprocess(self, heatmap, lms, offset, scale, size, threshold): 42 | t0 = time.time() 43 | if self.landmarks: 44 | dets, lms = self.decode(heatmap, scale, offset, lms, size, threshold=threshold) 45 | else: 46 | dets = self.decode(heatmap, scale, offset, None, size, threshold=threshold) 47 | if len(dets) > 0: 48 | dets[:, 0:4:2], dets[:, 1:4:2] = dets[:, 0:4:2], dets[:, 1:4:2] 49 | if self.landmarks: 50 | lms[:, 0:10:2], lms[:, 1:10:2] = lms[:, 0:10:2], lms[:, 1:10:2] 51 | else: 52 | dets = np.empty(shape=[0, 5], dtype=np.float32) 53 | if self.landmarks: 54 | lms = np.empty(shape=[0, 10], dtype=np.float32) 55 | t1 = time.time() 56 | logging.debug(f"Centerface postprocess took: {t1 - t0}") 57 | 58 | if self.landmarks: 59 | return dets, lms 60 | else: 61 | return dets 62 | 63 | def decode(self, heatmap, scale, offset, landmark, size, threshold=0.1): 64 | heatmap = np.squeeze(heatmap) 65 | scale0, scale1 = scale[0, 0, :, :], scale[0, 1, :, :] 66 | offset0, offset1 = offset[0, 0, :, :], offset[0, 1, :, :] 67 | c0, c1 = np.where(heatmap > threshold) 68 | if self.landmarks: 69 | boxes, lms = [], [] 70 | else: 71 | boxes = [] 72 | if len(c0) > 0: 73 | for i in range(len(c0)): 74 | s0, s1 = np.exp(scale0[c0[i], c1[i]]) * 4, np.exp(scale1[c0[i], c1[i]]) * 4 75 | o0, o1 = offset0[c0[i], c1[i]], offset1[c0[i], c1[i]] 76 | s = heatmap[c0[i], c1[i]] 77 | x1, y1 = max(0, (c1[i] + o1 + 0.5) * 4 - s1 / 2), max(0, (c0[i] + o0 + 0.5) * 4 - s0 / 2) 78 | x1, y1 = min(x1, size[1]), min(y1, size[0]) 79 | boxes.append([x1, y1, min(x1 + s1, size[1]), min(y1 + s0, size[0]), s]) 80 | if self.landmarks: 81 | lm = [] 82 | for j in range(5): 83 | lm.append(landmark[0, j * 2 + 1, c0[i], c1[i]] * s1 + x1) 84 | lm.append(landmark[0, j * 2, c0[i], c1[i]] * s0 + y1) 85 | lms.append(lm) 86 | boxes = np.asarray(boxes, dtype=np.float32) 87 | keep = nms(boxes, self.nms_threshold) 88 | boxes = boxes[keep, :] 89 | if self.landmarks: 90 | lms = np.asarray(lms, dtype=np.float32) 91 | lms = lms[keep, :] 92 | lms = lms.reshape((-1, 5, 2)) 93 | if self.landmarks: 94 | return boxes, lms 95 | else: 96 | return boxes 97 | -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/detectors/common/nms.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from numba import njit 3 | 4 | @njit() 5 | def nms(dets, thresh = 0.4): 6 | x1 = dets[:, 0] 7 | y1 = dets[:, 1] 8 | x2 = dets[:, 2] 9 | y2 = dets[:, 3] 10 | scores = dets[:, 4] 11 | 12 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 13 | order = scores.argsort()[::-1] 14 | 15 | keep = [] 16 | while order.size > 0: 17 | i = order[0] 18 | keep.append(i) 19 | xx1 = np.maximum(x1[i], x1[order[1:]]) 20 | yy1 = np.maximum(y1[i], y1[order[1:]]) 21 | xx2 = np.minimum(x2[i], x2[order[1:]]) 22 | yy2 = np.minimum(y2[i], y2[order[1:]]) 23 | 24 | w = np.maximum(0.0, xx2 - xx1 + 1) 25 | h = np.maximum(0.0, yy2 - yy1 + 1) 26 | inter = w * h 27 | ovr = inter / (areas[i] + areas[order[1:]] - inter) 28 | 29 | inds = np.where(ovr <= thresh)[0] 30 | order = order[inds + 1] 31 | 32 | return keep -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/exec_backends/onnxrt_backend.py: -------------------------------------------------------------------------------- 1 | import onnxruntime 2 | import cv2 3 | import numpy as np 4 | import logging 5 | 6 | class Arcface: 7 | def __init__(self, rec_name='/models/onnx/arcface_r100_v1/arcface_r100_v1.onnx'): 8 | self.rec_model = onnxruntime.InferenceSession(rec_name) 9 | self.outputs = [e.name for e in self.rec_model.get_outputs()] 10 | 11 | # warmup 12 | def prepare(self, **kwargs): 13 | logging.info("Warming up ArcFace ONNX Runtime engine...") 14 | self.rec_model.run(self.outputs, {self.rec_model.get_inputs()[0].name: [np.zeros((3, 112, 112), np.float32)]}) 15 | 16 | def get_embedding(self, face_img): 17 | if not isinstance(face_img, list): 18 | face_img = [face_img] 19 | 20 | for i, img in enumerate(face_img): 21 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 22 | img = np.transpose(img, (2, 0, 1)) 23 | face_img[i] = img.astype(np.float32) 24 | 25 | face_img = np.stack(face_img) 26 | net_out = self.rec_model.run(self.outputs, {self.rec_model.get_inputs()[0].name: face_img}) 27 | return net_out[0] 28 | 29 | 30 | class FaceGenderage: 31 | 32 | def __init__(self, rec_name='/models/onnx/genderage_v1/genderage_v1.onnx', outputs=None): 33 | self.rec_model = onnxruntime.InferenceSession(rec_name) 34 | self.input = self.rec_model.get_inputs()[0] 35 | if outputs is None: 36 | outputs = [e.name for e in self.rec_model.get_outputs()] 37 | self.outputs = outputs 38 | 39 | # warmup 40 | def prepare(self, **kwargs): 41 | logging.info("Warming up GenderAge ONNX Runtime engine...") 42 | self.rec_model.run(self.outputs, 43 | {self.rec_model.get_inputs()[0].name: [np.zeros(tuple(self.input.shape[1:]), np.float32)]}) 44 | 45 | def get(self, face_img): 46 | face_img = cv2.cvtColor(face_img, cv2.COLOR_BGR2RGB) 47 | face_img = np.transpose(face_img, (2, 0, 1)) 48 | face_img = np.expand_dims(face_img, axis=0) 49 | face_img = face_img.astype(np.float32) 50 | 51 | ret = self.rec_model.run(self.outputs, {self.input.name: face_img})[0] 52 | g = ret[:, 0:2].flatten() 53 | gender = np.argmax(g) 54 | a = ret[:, 2:202].reshape((100, 2)) 55 | a = np.argmax(a, axis=1) 56 | age = int(sum(a)) 57 | return gender, age 58 | 59 | 60 | class DetectorInfer: 61 | 62 | def __init__(self, model='/models/onnx/centerface/centerface.onnx', 63 | output_order=None): 64 | 65 | self.rec_model = onnxruntime.InferenceSession(model) 66 | self.input = self.rec_model.get_inputs()[0] 67 | 68 | if output_order is None: 69 | output_order = [e.name for e in self.rec_model.get_outputs()] 70 | self.output_order = output_order 71 | 72 | self.input_shape = tuple(self.input.shape) 73 | print(self.input_shape) 74 | 75 | # warmup 76 | def prepare(self, ctx=0): 77 | logging.info("Warming up face detection ONNX Runtime engine...") 78 | self.rec_model.run(self.output_order, 79 | {self.rec_model.get_inputs()[0].name: [np.zeros(tuple(self.input.shape[1:]), np.float32)]}) 80 | 81 | def run(self, input): 82 | net_out = self.rec_model.run(self.output_order, {self.input.name: input}) 83 | return net_out -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/exec_backends/trt_backend.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | import numpy as np 4 | import time 5 | import logging 6 | 7 | from .trt_loader import TrtModel 8 | 9 | class Arcface: 10 | 11 | def __init__(self, rec_name: str='./models/trt-engines/glint360k_r100FC_1.0/glint360k_r100FC_1.0.plan'): 12 | self.rec_model = TrtModel(rec_name) 13 | self.input_shape = None 14 | self.max_batch_size = 1 15 | 16 | # warmup 17 | def prepare(self, ctx_id=0): 18 | logging.info("Warming up ArcFace TensorRT engine...") 19 | self.rec_model.build() 20 | self.input_shape = self.rec_model.input_shapes[0] 21 | self.max_batch_size = self.rec_model.max_batch_size 22 | if self.input_shape[0] == -1: 23 | self.input_shape = (1,) + self.input_shape[1:] 24 | 25 | self.rec_model.run(np.zeros(self.input_shape, np.float32)) 26 | logging.info(f"Engine warmup complete! Expecting input shape: {self.input_shape}. Max batch size: {self.max_batch_size}") 27 | 28 | def get_embedding(self, face_img): 29 | 30 | if not isinstance(face_img, list): 31 | face_img = [face_img] 32 | 33 | for i, img in enumerate(face_img): 34 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 35 | img = np.transpose(img, (2, 0, 1)) 36 | #img = np.expand_dims(img, axis=0) 37 | face_img[i] = img 38 | #assert face_img.shape == self.rec_model.input_shapes[0] 39 | face_img = np.stack(face_img) 40 | embeddings = self.rec_model.run(face_img, deflatten=True)[0] 41 | return embeddings 42 | 43 | 44 | class DetectorInfer: 45 | 46 | def __init__(self, model='/models/trt-engines/centerface/centerface.plan', 47 | output_order=None): 48 | self.rec_model = TrtModel(model) 49 | self.model_name = os.path.basename(model) 50 | self.input_shape = None 51 | self.output_order = output_order 52 | 53 | # warmup 54 | def prepare(self, ctx_id=0): 55 | logging.info(f"Warming up face detector TensorRT engine...") 56 | self.rec_model.build() 57 | self.input_shape = self.rec_model.input_shapes[0] 58 | if not self.output_order: 59 | self.output_order = self.rec_model.out_names 60 | self.rec_model.run(np.zeros(self.input_shape, np.float32)) 61 | logging.info(f"Engine warmup complete! Expecting input shape: {self.input_shape}") 62 | 63 | def run(self, input): 64 | net_out = self.rec_model.run(input, deflatten=True, as_dict=True) 65 | net_out = [net_out[e] for e in self.output_order] 66 | return net_out -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/exec_backends/trt_loader.py: -------------------------------------------------------------------------------- 1 | import pycuda.driver as cuda 2 | import pycuda.autoinit 3 | import numpy as np 4 | import glob 5 | 6 | import tensorrt as trt 7 | 8 | TRT_LOGGER = trt.Logger() 9 | 10 | # Simple helper data class that's a little nicer to use than a 2-tuple. 11 | class HostDeviceMem(object): 12 | def __init__(self, host_mem, device_mem): 13 | self.host = host_mem 14 | self.device = device_mem 15 | 16 | def __str__(self): 17 | return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device) 18 | 19 | def __repr__(self): 20 | return self.__str__() 21 | 22 | # Allocates all buffers required for an engine, i.e. host/device inputs/outputs. 23 | def allocate_buffers(engine): 24 | inputs = [] 25 | outputs = [] 26 | bindings = [] 27 | stream = cuda.Stream() 28 | out_shapes = [] 29 | input_shapes = [] 30 | out_names = [] 31 | max_batch_size = engine.max_batch_size 32 | for binding in engine: 33 | binding_shape = engine.get_binding_shape(binding) 34 | #Fix -1 dimension for proper memory allocation for batch_size > 1 35 | if binding_shape[0] == -1: 36 | binding_shape = (1,) + binding_shape[1:] 37 | size = trt.volume(binding_shape) * max_batch_size 38 | dtype = trt.nptype(engine.get_binding_dtype(binding)) 39 | # Allocate host and device buffers 40 | host_mem = cuda.pagelocked_empty(size, dtype) 41 | device_mem = cuda.mem_alloc(host_mem.nbytes) 42 | # Append the device buffer to device bindings. 43 | bindings.append(int(device_mem)) 44 | # Append to the appropriate list. 45 | if engine.binding_is_input(binding): 46 | inputs.append(HostDeviceMem(host_mem, device_mem)) 47 | input_shapes.append(engine.get_binding_shape(binding)) 48 | else: 49 | outputs.append(HostDeviceMem(host_mem, device_mem)) 50 | #Collect original output shapes and names from engine 51 | out_shapes.append(engine.get_binding_shape(binding)) 52 | out_names.append(binding) 53 | return inputs, outputs, bindings, stream, input_shapes, out_shapes, out_names, max_batch_size 54 | 55 | # This function is generalized for multiple inputs/outputs. 56 | # inputs and outputs are expected to be lists of HostDeviceMem objects. 57 | def do_inference(context, bindings, inputs, outputs, stream): 58 | # Transfer input data to the GPU. 59 | [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs] 60 | # Run inference. 61 | context.execute_async_v2(bindings=bindings, stream_handle=stream.handle) 62 | # Transfer predictions back from the GPU. 63 | [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs] 64 | # Synchronize the stream 65 | stream.synchronize() 66 | # Return only the host outputs. 67 | return [out.host for out in outputs] 68 | 69 | class TrtModel(object): 70 | def __init__(self, model): 71 | self.engine_file = model 72 | self.engine = None 73 | self.inputs = None 74 | self.outputs = None 75 | self.bindings = None 76 | self.stream = None 77 | self.context = None 78 | self.input_shapes = None 79 | self.out_shapes = None 80 | self.max_batch_size = 1 81 | 82 | def build(self): 83 | with open(self.engine_file, 'rb') as f, trt.Runtime(TRT_LOGGER) as runtime: 84 | self.engine = runtime.deserialize_cuda_engine(f.read()) 85 | self.inputs, self.outputs, self.bindings, self.stream, self.input_shapes, self.out_shapes, self.out_names, self.max_batch_size = allocate_buffers( 86 | self.engine) 87 | 88 | self.context = self.engine.create_execution_context() 89 | self.context.active_optimization_profile = 0 90 | 91 | def run(self, input, deflatten: bool = True, as_dict=False): 92 | # lazy load implementation 93 | if self.engine is None: 94 | self.build() 95 | 96 | input = np.asarray(input) 97 | batch_size = input.shape[0] 98 | allocate_place = np.prod(input.shape) 99 | self.inputs[0].host[:allocate_place] = input.flatten(order='C').astype(np.float32) 100 | self.context.set_binding_shape(0, input.shape) 101 | trt_outputs = do_inference( 102 | self.context, bindings=self.bindings, 103 | inputs=self.inputs, outputs=self.outputs, stream=self.stream) 104 | #Reshape TRT outputs to original shape instead of flattened array 105 | if deflatten: 106 | trt_outputs = [output.reshape(shape) for output, shape in zip(trt_outputs, self.out_shapes)] 107 | if as_dict: 108 | return {name: trt_outputs[i] for i, name in enumerate(self.out_names)} 109 | 110 | return [trt_outputs[0][:batch_size]] 111 | 112 | -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/face_detectors.py: -------------------------------------------------------------------------------- 1 | from .detectors.retinaface import RetinaFace 2 | from .detectors.centerface import CenterFace 3 | from .detectors.dbface import DBFace 4 | 5 | 6 | def get_retinaface(model_path, backend, outputs, rac, masks=False): 7 | 8 | inference_backend = backend.DetectorInfer(model=model_path, output_order=outputs) 9 | model = RetinaFace(inference_backend=inference_backend, rac=rac, masks=masks) 10 | return model 11 | 12 | 13 | def retinaface_r50_v1(model_path, backend, outputs): 14 | model = get_retinaface(model_path, backend, outputs, rac="net3") 15 | return model 16 | 17 | 18 | def retinaface_mnet025_v1(model_path, backend, outputs): 19 | model = get_retinaface(model_path, backend, outputs, rac="net3") 20 | return model 21 | 22 | 23 | def retinaface_mnet025_v2(model_path, backend, outputs): 24 | model = get_retinaface(model_path, backend, outputs, rac="net3l") 25 | return model 26 | 27 | def mnet_cov2(model_path, backend, outputs): 28 | model = get_retinaface(model_path, backend, outputs, rac="net3l", masks=True) 29 | return model 30 | 31 | 32 | 33 | def centerface(model_path, backend, outputs): 34 | inference_backend = backend.DetectorInfer(model=model_path, output_order=outputs) 35 | model = CenterFace(inference_backend=inference_backend) 36 | return model 37 | 38 | def dbface(model_path, backend, outputs): 39 | inference_backend = backend.DetectorInfer(model=model_path, output_order=outputs) 40 | model = DBFace(inference_backend=inference_backend) 41 | return model 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/face_processors.py: -------------------------------------------------------------------------------- 1 | from .detectors.retinaface import RetinaFace 2 | from .detectors.centerface import CenterFace 3 | 4 | 5 | def arcface_r100_v1(model_path, backend, outputs): 6 | model = backend.Arcface(rec_name=model_path) 7 | return model 8 | 9 | 10 | def r50_arcface_msfdrop75(model_path, backend, outputs): 11 | model = backend.Arcface(rec_name=model_path) 12 | return model 13 | 14 | 15 | def r100_arcface_msfdrop75(model_path, backend, outputs): 16 | model = backend.Arcface(rec_name=model_path) 17 | return model 18 | 19 | 20 | def glint360k_r100FC_1_0(model_path, backend, outputs): 21 | model = backend.Arcface(rec_name=model_path) 22 | return model 23 | 24 | 25 | def glint360k_r100FC_0_1(model_path, backend, outputs): 26 | model = backend.Arcface(rec_name=model_path) 27 | return model 28 | 29 | 30 | def genderage_v1(model_path, backend, outputs): 31 | model = backend.FaceGenderage(rec_name=model_path) 32 | return model 33 | -------------------------------------------------------------------------------- /TensorFace/modules/model_zoo/getter.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import List 3 | 4 | from .face_detectors import * 5 | from .face_processors import * 6 | from ..utils.helpers import prepare_folders 7 | from ..configs import Configs 8 | from .exec_backends import trt_backend 9 | 10 | # Map model names to corresponding functions 11 | models = { 12 | 'arcface_r100_v1': arcface_r100_v1, 13 | 'r50-arcface-msfdrop75': r50_arcface_msfdrop75, 14 | 'r100-arcface-msfdrop75': r100_arcface_msfdrop75, 15 | 'glint360k_r100FC_1.0': glint360k_r100FC_1_0, 16 | 'glint360k_r100FC_0.1': glint360k_r100FC_0_1, 17 | 'genderage_v1': genderage_v1, 18 | 'retinaface_r50_v1': retinaface_r50_v1, 19 | 'retinaface_mnet025_v1': retinaface_mnet025_v1, 20 | 'retinaface_mnet025_v2': retinaface_mnet025_v2, 21 | 'mnet_cov2': mnet_cov2, 22 | 'centerface': centerface, 23 | 'dbface': dbface, 24 | } 25 | 26 | 27 | def prepare_backend(model_name, im_size: List[int] = None, 28 | max_batch_size: int = 1, 29 | force_fp16: bool = False, 30 | download_model: bool = True, 31 | config: Configs = None): 32 | """ 33 | Check if ONNX, MXNet and TensorRT models exist and download/create them otherwise. 34 | 35 | :param model_name: Name of required model. Must be one of keys in `models` dict. 36 | :param backend_name: Name of inference backend. (onnx, trt) 37 | :param im_size: Desired maximum size of image in W,H form. Will be overridden if model doesn't support reshaping. 38 | :param max_batch_size: Maximum batch size for inference, currently supported for ArcFace model only. 39 | :param force_fp16: Force use of FP16 precision, even if device doesn't support it. Be careful. TensorRT specific. 40 | :param download_model: Download MXNet or ONNX model if it not exist. 41 | :param config: Configs class instance 42 | :return: ONNX model serialized to string, or path to TensorRT engine 43 | """ 44 | 45 | prepare_folders([config.mxnet_models_dir, config.onnx_models_dir, config.trt_engines_dir]) 46 | 47 | in_package = config.in_official_package(model_name) 48 | reshape_allowed = config.mxnet_models[model_name].get('reshape') 49 | shape = config.get_shape(model_name) 50 | if reshape_allowed is True and im_size is not None: 51 | shape = (1, 3) + tuple(im_size)[::-1] 52 | 53 | trt_dir, trt_path = config.build_model_paths(model_name, 'plan') 54 | 55 | if reshape_allowed is True: 56 | trt_path = trt_path.replace('.plan', f'_{shape[3]}_{shape[2]}.plan') 57 | if max_batch_size > 1: 58 | trt_path = trt_path.replace('.plan', f'_batch{max_batch_size}.plan') 59 | if force_fp16 is True: 60 | trt_path = trt_path.replace('.plan', '_fp16.plan') 61 | return trt_path 62 | 63 | 64 | def get_model(model_name: str, im_size: List[int] = None, max_batch_size: int = 1, 65 | force_fp16: bool = False, 66 | root_dir: str = "/models", download_model: bool = True, **kwargs): 67 | """ 68 | Returns inference backend instance with loaded model. 69 | 70 | :param model_name: Name of required model. Must be one of keys in `models` dict. 71 | :param backend_name: Name of inference backend. (onnx, mxnet, trt) 72 | :param im_size: Desired maximum size of image in W,H form. Will be overridden if model doesn't support reshaping. 73 | :param max_batch_size: Maximum batch size for inference, currently supported for ArcFace model only. 74 | :param force_fp16: Force use of FP16 precision, even if device doesn't support it. Be careful. TensorRT specific. 75 | :param root_dir: Root directory where models will be stored. 76 | :param download_model: Download MXNet or ONNX model. Might be disabled if TRT model was already created. 77 | :param kwargs: Placeholder. 78 | :return: Inference backend with loaded model. 79 | """ 80 | 81 | config = Configs(models_dir=root_dir) 82 | model_path = prepare_backend(model_name, im_size=im_size, max_batch_size=max_batch_size, 83 | config=config, force_fp16=force_fp16, 84 | download_model=download_model) 85 | 86 | outputs = config.get_outputs_order(model_name) 87 | model = models[model_name](model_path=model_path, backend=trt_backend, outputs=outputs) 88 | return model 89 | -------------------------------------------------------------------------------- /TensorFace/modules/utils/download.py: -------------------------------------------------------------------------------- 1 | """ 2 | This code file mainly comes from https://github.com/dmlc/gluon-cv/blob/master/gluoncv/utils/download.py 3 | """ 4 | import os 5 | import hashlib 6 | import requests 7 | from tqdm import tqdm 8 | 9 | def check_sha1(filename, sha1_hash): 10 | """Check whether the sha1 hash of the file content matches the expected hash. 11 | Parameters 12 | ---------- 13 | filename : str 14 | Path to the file. 15 | sha1_hash : str 16 | Expected sha1 hash in hexadecimal digits. 17 | Returns 18 | ------- 19 | bool 20 | Whether the file content matches the expected hash. 21 | """ 22 | sha1 = hashlib.sha1() 23 | with open(filename, 'rb') as f: 24 | while True: 25 | data = f.read(1048576) 26 | if not data: 27 | break 28 | sha1.update(data) 29 | 30 | sha1_file = sha1.hexdigest() 31 | l = min(len(sha1_file), len(sha1_hash)) 32 | return sha1.hexdigest()[0:l] == sha1_hash[0:l] 33 | 34 | def download(url, path=None, overwrite=False, sha1_hash=None): 35 | """Download an given URL 36 | Parameters 37 | ---------- 38 | url : str 39 | URL to download 40 | path : str, optional 41 | Destination path to store downloaded file. By default stores to the 42 | current directory with same name as in url. 43 | overwrite : bool, optional 44 | Whether to overwrite destination file if already exists. 45 | sha1_hash : str, optional 46 | Expected sha1 hash in hexadecimal digits. Will ignore existing file when hash is specified 47 | but doesn't match. 48 | Returns 49 | ------- 50 | str 51 | The file path of the downloaded file. 52 | """ 53 | if path is None: 54 | fname = url.split('/')[-1] 55 | else: 56 | path = os.path.expanduser(path) 57 | if os.path.isdir(path): 58 | fname = os.path.join(path, url.split('/')[-1]) 59 | else: 60 | fname = path 61 | 62 | if overwrite or not os.path.exists(fname) or (sha1_hash and not check_sha1(fname, sha1_hash)): 63 | dirname = os.path.dirname(os.path.abspath(os.path.expanduser(fname))) 64 | if not os.path.exists(dirname): 65 | os.makedirs(dirname) 66 | 67 | print('Downloading %s from %s...'%(fname, url)) 68 | r = requests.get(url, stream=True) 69 | if r.status_code != 200: 70 | raise RuntimeError("Failed downloading url %s"%url) 71 | total_length = r.headers.get('content-length') 72 | with open(fname, 'wb') as f: 73 | if total_length is None: # no content length header 74 | for chunk in r.iter_content(chunk_size=1024): 75 | if chunk: # filter out keep-alive new chunks 76 | f.write(chunk) 77 | else: 78 | total_length = int(total_length) 79 | for chunk in tqdm(r.iter_content(chunk_size=1024), 80 | total=int(total_length / 1024. + 0.5), 81 | unit='KB', unit_scale=False, dynamic_ncols=True): 82 | f.write(chunk) 83 | 84 | if sha1_hash and not check_sha1(fname, sha1_hash): 85 | raise UserWarning('File {} is downloaded but the content hash does not match. ' \ 86 | 'The repo may be outdated or download may be incomplete. ' \ 87 | 'If the "repo_url" is overridden, consider switching to ' \ 88 | 'the default repo.'.format(fname)) 89 | 90 | return fname 91 | -------------------------------------------------------------------------------- /TensorFace/modules/utils/helpers.py: -------------------------------------------------------------------------------- 1 | import os 2 | from itertools import chain, islice 3 | from distutils import util 4 | 5 | def prepare_folders(paths): 6 | for path in paths: 7 | os.makedirs(path, exist_ok=True) 8 | 9 | def to_chunks(iterable, size=10): 10 | iterator = iter(iterable) 11 | for first in iterator: 12 | yield chain([first], islice(iterator, size - 1)) 13 | 14 | def tobool(input): 15 | try: 16 | return bool(util.strtobool(input)) 17 | except: 18 | return False 19 | 20 | def parse_size(size=None, def_size='640,480'): 21 | if size is None: 22 | size = def_size 23 | size_lst = list(map(int, size.split(','))) 24 | return size_lst 25 | 26 | -------------------------------------------------------------------------------- /TensorFace/modules/utils/model_store.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | This code file mainly comes from https://github.com/dmlc/gluon-cv/blob/master/gluoncv/model_zoo/model_store.py 4 | """ 5 | from __future__ import print_function 6 | 7 | __all__ = ['get_model_file'] 8 | import os 9 | import zipfile 10 | import glob 11 | 12 | from .download import download, check_sha1 13 | 14 | _model_sha1 = {name: checksum for checksum, name in [ 15 | ('95be21b58e29e9c1237f229dae534bd854009ce0', 'arcface_r100_v1'), 16 | ('', 'arcface_mfn_v1'), 17 | ('39fd1e087a2a2ed70a154ac01fecaa86c315d01b', 'retinaface_r50_v1'), 18 | ('2c9de8116d1f448fd1d4661f90308faae34c990a', 'retinaface_mnet025_v1'), 19 | ('0db1d07921d005e6c9a5b38e059452fc5645e5a4', 'retinaface_mnet025_v2'), 20 | ('7dd8111652b7aac2490c5dcddeb268e53ac643e6', 'genderage_v1'), 21 | ]} 22 | 23 | base_repo_url = 'http://insightface.ai/files/' 24 | _url_format = '{repo_url}models/{file_name}.zip' 25 | 26 | 27 | def short_hash(name): 28 | if name not in _model_sha1: 29 | raise ValueError('Pretrained model for {name} is not available.'.format(name=name)) 30 | return _model_sha1[name][:8] 31 | 32 | 33 | def find_params_file(dir_path): 34 | if not os.path.exists(dir_path): 35 | return None 36 | paths = glob.glob("%s/*.params"%dir_path) 37 | if len(paths)==0: 38 | return None 39 | paths = sorted(paths) 40 | return paths[-1] 41 | 42 | def get_model_file(name, root=os.path.join('~', '.insightface', 'models')): 43 | r"""Return location for the pretrained on local file system. 44 | 45 | This function will download from online model zoo when model cannot be found or has mismatch. 46 | The root directory will be created if it doesn't exist. 47 | 48 | Parameters 49 | ---------- 50 | name : str 51 | Name of the model. 52 | root : str, default '~/.mxnet/models' 53 | Location for keeping the model parameters. 54 | 55 | Returns 56 | ------- 57 | file_path 58 | Path to the requested pretrained model file. 59 | """ 60 | 61 | file_name = name 62 | root = os.path.expanduser(root) 63 | dir_path = os.path.join(root, name) 64 | file_path = find_params_file(dir_path) 65 | #file_path = os.path.join(root, file_name + '.params') 66 | sha1_hash = _model_sha1[name] 67 | if file_path is not None: 68 | if check_sha1(file_path, sha1_hash): 69 | return file_path 70 | else: 71 | print('Mismatch in the content of model file detected. Downloading again.') 72 | else: 73 | print('Model file is not found. Downloading.') 74 | 75 | if not os.path.exists(root): 76 | os.makedirs(root) 77 | if not os.path.exists(dir_path): 78 | os.makedirs(dir_path) 79 | 80 | zip_file_path = os.path.join(root, file_name + '.zip') 81 | repo_url = base_repo_url 82 | if repo_url[-1] != '/': 83 | repo_url = repo_url + '/' 84 | download(_url_format.format(repo_url=repo_url, file_name=file_name), 85 | path=zip_file_path, 86 | overwrite=True) 87 | with zipfile.ZipFile(zip_file_path) as zf: 88 | zf.extractall(dir_path) 89 | os.remove(zip_file_path) 90 | file_path = find_params_file(dir_path) 91 | 92 | if check_sha1(file_path, sha1_hash): 93 | return file_path 94 | else: 95 | raise ValueError('Downloaded file has different hash. Please try again.') 96 | 97 | 98 | -------------------------------------------------------------------------------- /datasets/property: -------------------------------------------------------------------------------- 1 | 57330,112,112 2 | -------------------------------------------------------------------------------- /deploy/FUNCTION.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import cv2 3 | import sys 4 | import math 5 | import numpy as np 6 | import csv 7 | import os 8 | 9 | 10 | def read_img(path_img): 11 | img = cv2.imread(path_img) 12 | # img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB) 13 | return img 14 | 15 | 16 | def get_all_path(IMAGE_DIR): 17 | image_path = [] 18 | g = os.walk(IMAGE_DIR) 19 | for path, d, filelist in g: 20 | for filename in filelist: 21 | list = [] 22 | if filename.endswith('jpg') or filename.endswith('bmp'): 23 | list.append(({"name": filename}, {"path": os.path.join(path, filename)})) 24 | image_path.append(list) 25 | return image_path 26 | 27 | 28 | def get_all_path_sort(file_dir): 29 | files = os.listdir(file_dir) # 采用listdir来读取所有文件 30 | files.sort() # 排序 31 | s = [] # 创建一个空列表 32 | for file_ in files: 33 | list = [] # 循环读取每个文件名 34 | if file_.endswith('jpg'): 35 | f_name = str(file_) 36 | list.append(({"name": f_name}, {"path": os.path.join(file_dir, f_name)})) 37 | s.append(list) 38 | return s 39 | 40 | 41 | # get top index sim 42 | def get_top(fea, feature, top=2, COLOR='bgr'): 43 | index_name = [] 44 | index_sim = [] 45 | color_index = 'fea_' + COLOR 46 | fea_index = [] 47 | for j in feature: 48 | sim = np.dot(fea, j[color_index].T) 49 | index_sim.append(sim) 50 | fea_index.append(j[color_index]) 51 | index_name.append(j['id']) 52 | index_sim = np.array(index_sim) 53 | order = index_sim.argsort()[::-1] 54 | index_name = np.array(index_name) 55 | NAME = index_name[order][:top] 56 | SIM = index_sim[order][:top] 57 | fea_index = np.array(fea_index) 58 | fea_index = fea_index[order][:top] 59 | return NAME[0], SIM[0], fea_index 60 | 61 | 62 | # get top same id 63 | import collections 64 | def bool_reranking(NAME, SIM, top_num=10): 65 | sample_name = NAME[:top_num] 66 | sample_sim = np.array(SIM[:top_num]) 67 | dic = collections.Counter(sample_name) 68 | 69 | top_nums = list(dic.values()) 70 | top_ids = list(dic.keys()) 71 | ids_index, sim_index = [], [] 72 | for i in range(len(top_ids)): 73 | score = 0.0 74 | for j in range(len(sample_name)): 75 | if top_ids[i] == sample_name[j]: 76 | score += sample_sim[j] 77 | ids_index.append(top_ids[i]) 78 | sim = score/(top_nums[i]+1) # 按照出现的次数,越多权重越大 79 | sim_index.append(sim) 80 | sim_index = np.array(sim_index) 81 | order = sim_index.argsort()[::-1] 82 | sim_index = sim_index[order] 83 | ids_index = np.array(ids_index) 84 | ids_index = ids_index[order] 85 | data = (ids_index, sim_index) 86 | return data 87 | 88 | # get score updata 89 | def ScoreAug(score, aug_threshold): 90 | k1 = (4 - 1) / (0.98 - aug_threshold) 91 | b1 = 4 - 0.98 * k1 92 | k2 = (-1 - -4) / (aug_threshold - 0) 93 | b2 = -1 - aug_threshold * k2 94 | 95 | if score > aug_threshold: 96 | return 1.0 / (1.0 + np.e ** (-(k1 * score + b1))) 97 | else: 98 | return 1.0 / (1.0 + np.e ** (-(k2 * score + b2))) 99 | -------------------------------------------------------------------------------- /deploy/RocTest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | from sklearn.metrics import roc_curve, auc ###计算roc和auc 6 | 7 | def plot_roc(y_score, y_test, titlt): 8 | ###通过decision_function()计算得到的y_score的值,用在roc_curve()函数中 9 | # y_score = [0.1, 0.5, 0.8, 0.6, 0.3] 10 | # y_test = [0, 1, 1, 0, 0] 11 | 12 | # Compute ROC curve and ROC area for each class 13 | fpr,tpr,threshold = roc_curve(y_test, y_score) ###计算真正率和假正率 14 | roc_auc = auc(fpr,tpr) ###计算auc的值 15 | 16 | plt.figure() 17 | lw = 2 18 | plt.figure(figsize=(10,10)) 19 | plt.plot(fpr, tpr, color='darkorange', 20 | lw=lw, label='ROC curve (area = %0.2f)' % roc_auc) ###假正率为横坐标,真正率为纵坐标做曲线 21 | plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--') 22 | plt.xlim([0.0, 1.0]) 23 | plt.ylim([0.5, 1.05]) 24 | plt.xlabel('False Positive Rate') 25 | plt.ylabel('True Positive Rate') 26 | plt.title(titlt) 27 | plt.legend(loc="lower right") 28 | plt.show() 29 | # plt.savefig(save_path) -------------------------------------------------------------------------------- /deploy/benchmark.py: -------------------------------------------------------------------------------- 1 | import face_embedding 2 | import argparse 3 | import cv2 4 | import numpy as np 5 | import datetime 6 | 7 | parser = argparse.ArgumentParser(description='face model test') 8 | # general 9 | parser.add_argument('--image-size', default='112,112', help='') 10 | parser.add_argument('--model', default='../models/model-r34-amf/model,0', help='path to load model.') 11 | parser.add_argument('--gpu', default=0, type=int, help='gpu id') 12 | parser.add_argument('--det', default=2, type=int, help='mtcnn option, 2 means using R+O, else using O') 13 | parser.add_argument('--flip', default=0, type=int, help='whether do lr flip aug') 14 | parser.add_argument('--threshold', default=1.24, type=float, help='ver dist threshold') 15 | args = parser.parse_args() 16 | 17 | model = face_embedding.FaceModel(args) 18 | #img = cv2.imread('/raid5data/dplearn/lfw/Jude_Law/Jude_Law_0001.jpg') 19 | img = cv2.imread('/raid5data/dplearn/megaface/facescrubr/112x112/Tom_Hanks/Tom_Hanks_54745.png') 20 | 21 | time_now = datetime.datetime.now() 22 | for i in xrange(3000): 23 | f1 = model.get_feature(img) 24 | time_now2 = datetime.datetime.now() 25 | diff = time_now2 - time_now 26 | print(diff.total_seconds()/3000) 27 | -------------------------------------------------------------------------------- /deploy/clean_others_img.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | # 筛选同文件夹下不同的人 3 | import face_model 4 | import argparse 5 | import cv2 6 | import sys 7 | import os 8 | import numpy as np 9 | 10 | import shutil 11 | 12 | def get_all_path(IMAGE_DIR): 13 | image_path = [] 14 | g = os.walk(IMAGE_DIR) 15 | for path, d, filelist in g: 16 | for filename in filelist: 17 | list = [] 18 | if filename.endswith('jpg') or filename.endswith('bmp'): 19 | list.append(({"name": filename}, {"path": os.path.join(path, filename)})) 20 | image_path.append(list) 21 | return image_path 22 | 23 | def review_img(feature, img_index): 24 | # 计算与其他img的相似度,平均相似度小于0.5删除 25 | del_index = [] 26 | for i in range(len(feature)): 27 | sim = 0. 28 | for j in range(len(feature)): 29 | if i != j: 30 | sim += np.dot(feature[i], feature[j].T) 31 | sim = sim / (len(feature) - 1) 32 | if sim < 0.25: 33 | del_index.append(i) 34 | for k in del_index: 35 | os.remove(img_index[k]) 36 | # print(img_index[k], 'is removed') 37 | 38 | def main(args): 39 | model = face_model.FaceModel(args) 40 | # 打开文件 41 | dir0 = os.listdir(args.image_path) 42 | count = len(dir0) 43 | for id in dir0: 44 | count -= 1 45 | if count%3000 == 0: 46 | print('last num:', count) 47 | name_path = os.path.join(args.image_path, id) 48 | name_files = get_all_path(name_path) 49 | if len(name_files) < 4: 50 | shutil.rmtree(name_path) 51 | # print(args.image_path + id, 'is < 1 size') 52 | continue 53 | else: 54 | feature = [] 55 | img_index = [] 56 | for index in range(len(name_files)): 57 | file_path = name_files[index][0][1]["path"] 58 | img = cv2.imread(file_path) 59 | if img.ndim<2: 60 | os.remove(file_path) 61 | continue 62 | # print(file_path) 63 | aligned = model.get_input(img) 64 | if aligned is None: 65 | os.remove(file_path) 66 | continue 67 | else: 68 | f1 = model.get_feature(aligned) 69 | feature.append(f1) 70 | img_index.append(file_path) 71 | review_img(feature, img_index) 72 | name_files = os.listdir(name_path) 73 | if len(name_files) < 2: # 清洗后的数量小于20删除该文件夹 74 | shutil.rmtree(name_path) 75 | # print(args.image_path + id, ' is < 1 size') 76 | 77 | 78 | def parse_arguments(argv): 79 | parser = argparse.ArgumentParser() 80 | parser = argparse.ArgumentParser(description='face model test') 81 | # general 82 | parser.add_argument('--image-size', default='112,112', help='') 83 | parser.add_argument('--image_path', default='/home/sai/YANG/image/Face_Recognition/GateFace/raw/50000_out/', help='') 84 | parser.add_argument('--model', default='../models/glink-best/model,1', help='path to load model.') 85 | parser.add_argument('--ga-model', default='../models/gamodel-r50/model,0', help='path to load model.') 86 | parser.add_argument('--gpu', default=0, type=int, help='gpu id') 87 | parser.add_argument('--det', default=0, type=int, help='mtcnn option, 1 means using R+O, 0 means detect from begining') 88 | parser.add_argument('--flip', default=1, type=int, help='whether do lr flip aug') 89 | parser.add_argument('--threshold', default=1.24, type=float, help='ver dist threshold') 90 | parser.add_argument('--face_detection', default=1, help='0 is mtcnn, 1 is ssh') 91 | parser.add_argument('--ssh_model', default='../SSH/model/model-zhaohang-v1.0/e2e', type=str, help='0 is mtcnn, 1 is ssh') 92 | parser.add_argument('--face_landmark', default='../face_landmark_xiaoyi/model/ssh_FAN-4_003.pth', 93 | help='load 68 landmark') 94 | # args = parser.parse_args() 95 | return parser.parse_args(argv) 96 | 97 | if __name__ == '__main__': 98 | main(parse_arguments(sys.argv[1:])) 99 | 100 | -------------------------------------------------------------------------------- /deploy/face_embedding.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | from scipy import misc 6 | import sys 7 | import os 8 | import argparse 9 | import tensorflow as tf 10 | import numpy as np 11 | import mxnet as mx 12 | import random 13 | import cv2 14 | import sklearn 15 | from sklearn.decomposition import PCA 16 | from time import sleep 17 | from easydict import EasyDict as edict 18 | from mtcnn_detector import MtcnnDetector 19 | sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src', 'common')) 20 | import face_image 21 | import face_preprocess 22 | 23 | 24 | def do_flip(data): 25 | for idx in xrange(data.shape[0]): 26 | data[idx,:,:] = np.fliplr(data[idx,:,:]) 27 | 28 | class FaceModel: 29 | def __init__(self, args): 30 | self.args = args 31 | model = edict() 32 | 33 | self.threshold = args.threshold 34 | self.det_minsize = 50 35 | self.det_threshold = [0.4,0.6,0.6] 36 | self.det_factor = 0.9 37 | _vec = args.image_size.split(',') 38 | assert len(_vec)==2 39 | image_size = (int(_vec[0]), int(_vec[1])) 40 | self.image_size = image_size 41 | _vec = args.model.split(',') 42 | assert len(_vec)==2 43 | prefix = _vec[0] 44 | epoch = int(_vec[1]) 45 | print('loading',prefix, epoch) 46 | ctx = mx.gpu(args.gpu) 47 | sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch) 48 | all_layers = sym.get_internals() 49 | sym = all_layers['fc1_output'] 50 | model = mx.mod.Module(symbol=sym, context=ctx, label_names = None) 51 | #model.bind(data_shapes=[('data', (args.batch_size, 3, image_size[0], image_size[1]))], label_shapes=[('softmax_label', (args.batch_size,))]) 52 | model.bind(data_shapes=[('data', (1, 3, image_size[0], image_size[1]))]) 53 | model.set_params(arg_params, aux_params) 54 | self.model = model 55 | mtcnn_path = os.path.join(os.path.dirname(__file__), 'mtcnn-model') 56 | detector = MtcnnDetector(model_folder=mtcnn_path, ctx=ctx, num_worker=1, accurate_landmark = True, threshold=[0.0,0.0,0.2]) 57 | self.detector = detector 58 | 59 | 60 | def get_feature(self, face_img): 61 | #face_img is bgr image 62 | ret = self.detector.detect_face_limited(face_img, det_type = self.args.det) 63 | if ret is None: 64 | return None 65 | bbox, points = ret 66 | if bbox.shape[0]==0: 67 | return None 68 | bbox = bbox[0,0:4] 69 | points = points[0,:].reshape((2,5)).T 70 | #print(bbox) 71 | #print(points) 72 | nimg = face_preprocess.preprocess(face_img, bbox, points, image_size='112,112') 73 | nimg = cv2.cvtColor(nimg, cv2.COLOR_BGR2RGB) 74 | aligned = np.transpose(nimg, (2,0,1)) 75 | #print(nimg.shape) 76 | embedding = None 77 | for flipid in [0,1]: 78 | if flipid==1: 79 | if self.args.flip==0: 80 | break 81 | do_flip(aligned) 82 | input_blob = np.expand_dims(aligned, axis=0) 83 | data = mx.nd.array(input_blob) 84 | db = mx.io.DataBatch(data=(data,)) 85 | self.model.forward(db, is_train=False) 86 | _embedding = self.model.get_outputs()[0].asnumpy() 87 | #print(_embedding.shape) 88 | if embedding is None: 89 | embedding = _embedding 90 | else: 91 | embedding += _embedding 92 | embedding = sklearn.preprocessing.normalize(embedding).flatten() 93 | return embedding 94 | 95 | -------------------------------------------------------------------------------- /deploy/face_model_prnet_mask.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | from __future__ import absolute_import 3 | from __future__ import division 4 | from __future__ import print_function 5 | 6 | from scipy import misc 7 | import sys 8 | import os 9 | import numpy as np 10 | import mxnet as mx 11 | import cv2 12 | import sklearn 13 | 14 | sys.path.append(os.path.join(os.path.dirname(__file__), '..')) 15 | # add ssh face detection 16 | from SSH.ssh_detector import SSHDetector 17 | # add 3D mask 18 | from PRNet_Mask.generate_mask import generate_mask, load_mask_model 19 | 20 | def do_flip(data): 21 | for idx in range(data.shape[0]): 22 | data[idx, :, :] = np.fliplr(data[idx, :, :]) 23 | 24 | 25 | def get_max_face(bounding_boxes): 26 | det = bounding_boxes[:, 0:4] 27 | bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1]) 28 | bindex = np.argmax(bounding_box_size) # some extra weight on the centering 29 | return bindex 30 | 31 | 32 | def get_model(ctx, image_size, model_str, layer): 33 | _vec = model_str.split(',') 34 | assert len(_vec) == 2 35 | prefix = _vec[0] 36 | epoch = int(_vec[1]) 37 | print('loading', prefix, epoch) 38 | sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch) 39 | all_layers = sym.get_internals() 40 | sym = all_layers[layer + '_output'] 41 | model = mx.mod.Module(symbol=sym, context=ctx, label_names=None) 42 | model.bind(data_shapes=[('data', (1, 3, image_size[0], image_size[1]))]) 43 | model.set_params(arg_params, aux_params) 44 | return model 45 | 46 | 47 | class FaceModel: 48 | def __init__(self, args): 49 | self.args = args 50 | ctx = mx.gpu(args.gpu) 51 | _vec = args.image_size.split(',') 52 | assert len(_vec) == 2 53 | image_size = (int(_vec[0]), int(_vec[1])) 54 | self.model = None 55 | self.ga_model = None 56 | if len(args.model) > 0: 57 | self.model = get_model(ctx, image_size, args.model, 'fc1') 58 | # if len(args.ga_model)>0: 59 | # self.ga_model = get_model(ctx, image_size, args.ga_model, 'fc1') 60 | 61 | self.det_minsize = 50 62 | self.image_size = image_size 63 | # load 68 landmark model 64 | self.landmark_net = load_mask_model(args.gpu) 65 | # 使用ssh人脸检测 66 | self.detector = SSHDetector(args.gpu, False) 67 | 68 | def get_input(self, face_img): 69 | ret = self.detector.detect(face_img, scales_index=2) 70 | if ret is None or ret.shape[0] < 1: 71 | return None 72 | bindex = get_max_face(ret) 73 | bbox = ret[bindex, :4] 74 | # 获取3D人脸mask 75 | warped = generate_mask(face_img, self.landmark_net, bbox, True) 76 | if warped is None: 77 | return None 78 | nimg = cv2.resize(warped, (112, 112), cv2.INTER_AREA) 79 | # face_score = face_quality(self.Qnet, nimg) 80 | 81 | RGB_nimg = cv2.cvtColor(nimg, cv2.COLOR_BGR2RGB) # train img is all bgr 82 | aligned_rgb = np.transpose(RGB_nimg, (2, 0, 1)) 83 | return aligned_rgb 84 | 85 | def get_feature(self, aligned): 86 | input_blob = np.expand_dims(aligned, axis=0) 87 | data = mx.nd.array(input_blob) 88 | db = mx.io.DataBatch(data=(data,)) 89 | self.model.forward(db, is_train=False) 90 | embedding = self.model.get_outputs()[0].asnumpy() 91 | embedding = sklearn.preprocessing.normalize(embedding).flatten() 92 | return embedding 93 | 94 | def get_ga(self, aligned): 95 | input_blob = np.expand_dims(aligned, axis=0) 96 | data = mx.nd.array(input_blob) 97 | db = mx.io.DataBatch(data=(data,)) 98 | self.ga_model.forward(db, is_train=False) 99 | ret = self.ga_model.get_outputs()[0].asnumpy() 100 | g = ret[:, 0:2].flatten() 101 | gender = np.argmax(g) 102 | a = ret[:, 2:202].reshape((100, 2)) 103 | a = np.argmax(a, axis=1) 104 | age = int(sum(a)) 105 | 106 | return gender, age 107 | -------------------------------------------------------------------------------- /deploy/ga_merge.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import sys 6 | import os 7 | import argparse 8 | import numpy as np 9 | import mxnet as mx 10 | 11 | parser = argparse.ArgumentParser(description='merge age and gender models') 12 | # general 13 | parser.add_argument('--age-model', default='', help='path to load age model.') 14 | parser.add_argument('--gender-model', default='', help='path to load gender model.') 15 | parser.add_argument('--prefix', default='', help='path to save model.') 16 | args = parser.parse_args() 17 | 18 | i = 0 19 | tsym = None 20 | targ = {} 21 | taux = {} 22 | for model in [args.age_model, args.gender_model]: 23 | _vec = model.split(',') 24 | assert len(_vec)==2 25 | prefix = _vec[0] 26 | epoch = int(_vec[1]) 27 | print('loading',prefix, epoch) 28 | sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch) 29 | if tsym is None: 30 | all_layers = sym.get_internals() 31 | tsym = all_layers['fc1_output'] 32 | if i==0: 33 | prefix = 'age' 34 | else: 35 | prefix = 'gender' 36 | for k,v in arg_params.iteritems(): 37 | if k.startswith(prefix): 38 | print('arg', i, k) 39 | targ[k] = v 40 | for k,v in aux_params.iteritems(): 41 | if k.startswith(prefix): 42 | print('aux', i, k) 43 | taux[k] = v 44 | i+=1 45 | dellist = [] 46 | #for k,v in arg_params.iteritems(): 47 | # if k.startswith('fc7'): 48 | # dellist.append(k) 49 | for d in dellist: 50 | del targ[d] 51 | mx.model.save_checkpoint(args.prefix, 0, tsym, targ, taux) 52 | 53 | -------------------------------------------------------------------------------- /deploy/gen_landmark_data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import face_model_video 3 | import argparse 4 | import cv2 5 | import sys 6 | import math 7 | import os 8 | import numpy as np 9 | 10 | parser = argparse.ArgumentParser(description='face model test') 11 | # general 12 | parser.add_argument('--image-size', default='112,112', help='') 13 | parser.add_argument('--model', default='../models/glink-best/model,1', help='path to load model.') 14 | # parser.add_argument('--ga-model', default='', help='path to load model.') 15 | parser.add_argument('--gpu', default=0, type=int, help='gpu id') 16 | parser.add_argument('--det', default=0, type=int, help='mtcnn option, 1 means using R+O, 0 means detect from begining') 17 | parser.add_argument('--flip', default=0, type=int, help='whether do lr flip aug') 18 | parser.add_argument('--threshold', default=1.24, type=float, help='ver dist threshold') 19 | parser.add_argument('--face_detection', default=1, help='0 is mtcnn, 1 is ssh') 20 | parser.add_argument('--ssh_model', default='../SSH/model/model-zhaohang-v1.0/e2e', type=str, help='0 is mtcnn, 1 is ssh') 21 | parser.add_argument('--face_landmark', default='../face_landmark_xiaoyi/model/ssh_FAN-4_003.pth', 22 | help='load 68 landmark') 23 | args = parser.parse_args() 24 | 25 | model = face_model_video.FaceModel(args) 26 | 27 | 28 | def get_all_path(IMAGE_DIR): 29 | image_path = [] 30 | g = os.walk(IMAGE_DIR) 31 | for path, d, filelist in g: 32 | for filename in filelist: 33 | list = [] 34 | if filename.endswith('jpg'): 35 | list.append(({"name": filename}, {"path": os.path.join(path, filename)})) 36 | image_path.append(list) 37 | return image_path 38 | # 39 | IMAGE_DIR = '/home/sai/YANG/image/Face_Recognition/landmark-data/other-src' 40 | SAVE_DIR = '/home/sai/YANG/image/Face_Recognition/landmark-data/' 41 | 42 | count = 0 43 | file_names = get_all_path(IMAGE_DIR) 44 | feature=[] 45 | for index in range(len(file_names)): 46 | name = file_names[index][0][0]["name"] 47 | file_path = file_names[index][0][1]["path"] 48 | img = cv2.imread(file_path) 49 | img_draw = img.copy() 50 | # if count%5!=0: 51 | # continue 52 | # print(file_path) 53 | aligned = model.get_input(img) 54 | if aligned is None: 55 | continue 56 | if len(aligned) != 1: 57 | continue 58 | for i in aligned: 59 | bbox = i['bbox'] 60 | # cv2.rectangle(img_draw, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])), (0, 255, 0), 1) 61 | f1 = model.get_feature(i['aligned']) 62 | f1 = list(f1) 63 | for k in i['landmark']: 64 | f1.append(k[0]) 65 | f1.append(k[1]) 66 | cv2.circle(img_draw, (int(k[0]), int(k[1])), 1, (255, 0, 255), 1) 67 | 68 | feature.append({'id': 'false', 'fea': np.array(f1)}) 69 | count += 1 70 | # cv2.imwrite(os.path.join(SAVE_DIR+'src-new', str(count)+'_new.jpg'), img) 71 | # cv2.imwrite(os.path.join(SAVE_DIR + 'other-draw', name), img_draw) 72 | 73 | np.save(SAVE_DIR+'/other_feature.npy', feature) 74 | 75 | 76 | -------------------------------------------------------------------------------- /deploy/model_slim.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import sys 6 | import os 7 | import argparse 8 | import numpy as np 9 | import mxnet as mx 10 | 11 | parser = argparse.ArgumentParser(description='face model slim') 12 | # general 13 | parser.add_argument('--model', default='../models/glink-best/model,1', help='path to load model.') 14 | args = parser.parse_args() 15 | 16 | _vec = args.model.split(',') 17 | assert len(_vec)==2 18 | prefix = _vec[0] 19 | epoch = int(_vec[1]) 20 | print('loading',prefix, epoch) 21 | sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch) 22 | all_layers = sym.get_internals() 23 | sym = all_layers['fc1_output'] 24 | dellist = [] 25 | for k,v in arg_params.items(): 26 | if k.startswith('fc7'): 27 | dellist.append(k) 28 | for d in dellist: 29 | del arg_params[d] 30 | mx.model.save_checkpoint(prefix+"s", 0, sym, arg_params, aux_params) 31 | 32 | -------------------------------------------------------------------------------- /deploy/reranking.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Jun 26 14:46:56 2017 5 | 6 | @author: luohao 7 | """ 8 | 9 | """ 10 | CVPR2017 paper:Zhong Z, Zheng L, Cao D, et al. Re-ranking Person Re-identification with k-reciprocal Encoding[J]. 2017. 11 | url:http://openaccess.thecvf.com/content_cvpr_2017/papers/Zhong_Re-Ranking_Person_Re-Identification_CVPR_2017_paper.pdf 12 | Matlab version: https://github.com/zhunzhong07/person-re-ranking 13 | """ 14 | 15 | """ 16 | API 17 | 18 | probFea: all feature vectors of the query set, shape = (image_size, feature_dim) 19 | galFea: all feature vectors of the gallery set, shape = (image_size, feature_dim) 20 | k1,k2,lambda: parameters, the original paper is (k1=20,k2=6,lambda=0.3) 21 | MemorySave: set to 'True' when using MemorySave mode 22 | Minibatch: avaliable when 'MemorySave' is 'True' 23 | 24 | Modified by lizhen 25 | """ 26 | 27 | import pdb 28 | import numpy as np 29 | from scipy.spatial.distance import cdist 30 | 31 | def re_ranking(probFea,galFea,k1=10,k2=6,k3=0.63, MemorySave = False, Minibatch = 10): 32 | 33 | query_num = probFea.shape[0] 34 | all_num = query_num + galFea.shape[0] 35 | feat = np.append(probFea,galFea,axis = 0) 36 | feat = feat.astype(np.float16) 37 | #print('computing original distance') 38 | if MemorySave: 39 | original_dist = np.zeros(shape = [all_num,all_num],dtype = np.float16) 40 | i = 0 41 | while True: 42 | it = i + Minibatch 43 | if it < np.shape(feat)[0]: 44 | original_dist[i:it,] = np.power(cdist(feat[i:it,],feat),2).astype(np.float16) 45 | else: 46 | original_dist[i:,:] = np.power(cdist(feat[i:,],feat),2).astype(np.float16) 47 | break 48 | i = it 49 | else: 50 | original_dist = cdist(feat,feat).astype(np.float16) 51 | original_dist = np.power(original_dist,2).astype(np.float16) 52 | del feat 53 | gallery_num = original_dist.shape[0] 54 | original_dist = np.transpose(original_dist/np.max(original_dist,axis = 0)) 55 | V = np.zeros_like(original_dist).astype(np.float16) 56 | initial_rank = np.argsort(original_dist).astype(np.int32) 57 | 58 | 59 | #print('starting re_ranking') 60 | for i in range(all_num): 61 | # k-reciprocal neighbors 62 | forward_k_neigh_index = initial_rank[i,:k1+1] 63 | backward_k_neigh_index = initial_rank[forward_k_neigh_index,:k1+1] 64 | fi = np.where(backward_k_neigh_index==i)[0] 65 | k_reciprocal_index = forward_k_neigh_index[fi] 66 | k_reciprocal_expansion_index = k_reciprocal_index 67 | for j in range(len(k_reciprocal_index)): 68 | candidate = k_reciprocal_index[j] 69 | candidate_forward_k_neigh_index = initial_rank[candidate,:int(np.around(k1/2))+1] 70 | candidate_backward_k_neigh_index = initial_rank[candidate_forward_k_neigh_index,:int(np.around(k1/2))+1] 71 | fi_candidate = np.where(candidate_backward_k_neigh_index == candidate)[0] 72 | candidate_k_reciprocal_index = candidate_forward_k_neigh_index[fi_candidate] 73 | if len(np.intersect1d(candidate_k_reciprocal_index,k_reciprocal_index))> 2/3*len(candidate_k_reciprocal_index): 74 | k_reciprocal_expansion_index = np.append(k_reciprocal_expansion_index,candidate_k_reciprocal_index) 75 | 76 | k_reciprocal_expansion_index = np.unique(k_reciprocal_expansion_index) 77 | weight = np.exp(-original_dist[i,k_reciprocal_expansion_index]) 78 | V[i,k_reciprocal_expansion_index] = weight/np.sum(weight) 79 | original_dist = original_dist[:query_num,] 80 | if k2 != 1: 81 | V_qe = np.zeros_like(V,dtype=np.float16) 82 | for i in range(all_num): 83 | V_qe[i,:] = np.mean(V[initial_rank[i,:k2],:],axis=0) 84 | V = V_qe 85 | del V_qe 86 | del initial_rank 87 | invIndex = [] 88 | for i in range(gallery_num): 89 | invIndex.append(np.where(V[:,i] != 0)[0]) 90 | 91 | jaccard_dist = np.zeros_like(original_dist,dtype = np.float16) 92 | 93 | 94 | for i in range(query_num): 95 | temp_min = np.zeros(shape=[1,gallery_num],dtype=np.float16) 96 | indNonZero = np.where(V[i,:] != 0)[0] 97 | indImages = [] 98 | indImages = [invIndex[ind] for ind in indNonZero] 99 | for j in range(len(indNonZero)): 100 | temp_min[0,indImages[j]] = temp_min[0,indImages[j]]+ np.minimum(V[i,indNonZero[j]],V[indImages[j],indNonZero[j]]) 101 | jaccard_dist[i] = 1-temp_min/(2-temp_min) 102 | 103 | final_dist = jaccard_dist*(1-k3) + original_dist*k3 104 | del original_dist 105 | del V 106 | del jaccard_dist 107 | final_dist = final_dist[:query_num,query_num:] 108 | return final_dist[0] 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /deploy/test_prnet_mask.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | import face_model_prnet_mask 3 | import argparse 4 | import cv2 5 | import sys 6 | import math 7 | import numpy as np 8 | import csv 9 | import os 10 | 11 | from deploy.FUNCTION import * 12 | 13 | parser = argparse.ArgumentParser(description='face model test') 14 | # general 15 | parser.add_argument('--image-size', default='112,112', help='') 16 | parser.add_argument('--model', default='../model-resnet152-quality-mask/model,1', help='path to load model.') 17 | parser.add_argument('--gpu', default=0, type=str, help='gpu id') 18 | parser.add_argument('--flip', default=1, type=int, help='whether do lr flip aug') 19 | 20 | args = parser.parse_args() 21 | 22 | model = face_model_prnet_mask.FaceModel(args) 23 | 24 | IMAGE_DIR = '../images/test_imgs/false' 25 | txt_write = open('../images/test/result.txt', 'w') 26 | feature = np.load('../images/test/all_img_resnet152_mask.npy') 27 | 28 | file_names = get_all_path(IMAGE_DIR) 29 | for index in range(len(file_names)): 30 | name = file_names[index][0][0]["name"] 31 | file_path = file_names[index][0][1]["path"] 32 | img = cv2.imread(file_path) 33 | 34 | aligned_rgb = model.get_input(img) 35 | if aligned_rgb is None: 36 | continue 37 | fea = model.get_feature(aligned_rgb) 38 | NAME, SIM, _ = get_top(fea, feature, top=1, COLOR='rgb') 39 | 40 | # print(name, NAME, SIM, face_score) 41 | txt_write.write(str(name) + ' ') 42 | txt_write.write(str(NAME[0]) + ' ') 43 | txt_write.write(str(SIM[0]) + '\n') 44 | txt_write.close() 45 | 46 | # 47 | # IMAGE_DIR = '../images/test/20190430_ids/' 48 | # feature = [] 49 | # dir0 = os.listdir(IMAGE_DIR) 50 | # count = len(dir0) 51 | # for i in dir0: 52 | # count -= 1 53 | # if count%2000 == 0: 54 | # print(count) 55 | # 56 | # file_path = os.path.join(IMAGE_DIR+i) 57 | # img = cv2.imread(file_path) 58 | # if img is None: 59 | # continue 60 | # aligned_rgb = model.get_input(img) 61 | # if aligned_rgb is None: 62 | # continue 63 | # 64 | # f_rgb = model.get_feature(aligned_rgb) 65 | # feature.append({'id':i.strip('.jpg'), 'fea_rgb':f_rgb}) 66 | # np.save('../images/test/all_img_resnet152_mask.npy', feature) -------------------------------------------------------------------------------- /faceQuality/FaceQNet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from keras.models import load_model 3 | import numpy as np 4 | import os 5 | import cv2 6 | 7 | def load_Qnet_model(): 8 | # os.environ['CUDA_VISIBLE_DEVICES']='0' 9 | base_path = os.path.dirname(__file__) 10 | #Loading the pretrained model 11 | model = load_model(base_path+'/FaceQnet.h5') 12 | return model 13 | 14 | def face_quality(model, img): 15 | img = cv2.resize(img, (224, 224)) 16 | test_data = [] 17 | test_data.append(img) 18 | test_data = np.array(test_data, copy=False, dtype=np.float32) 19 | #Extract quality scores for the samples 20 | score = model.predict(test_data, batch_size=1, verbose=1) 21 | return score 22 | -------------------------------------------------------------------------------- /faceQuality/README.md: -------------------------------------------------------------------------------- 1 | # FaceQnet 2 | FaceQnet: Quality Assessment for Face Recognition based on Deep Learning 3 | 4 | **`2020.07.02`**: [**更新最新的人脸质量评价模型**](https://github.com/uam-biometrics/FaceQnet) 5 | 6 | This repository contains the DNN FaceQnet presented in the paper: "FaceQnet: Quality Assessment for Face Recognition based on Deep Learning". 7 | 8 | FaceQnet is a No-Reference, end-to-end Quality Assessment (QA) system for face recognition based on deep learning. 9 | The system consists of a Convolutional Neural Network that is able to predict the suitability of a specific input image for face recognition purposes. 10 | The training of FaceQnet is done using the VGGFace2 database. 11 | 12 | -- Configuring environment in Windows: 13 | 14 | 1) Installing Conda: https://conda.io/projects/conda/en/latest/user-guide/install/windows.html 15 | 16 | Update Conda in the default environment: 17 | 18 | conda update conda 19 | conda upgrade --all 20 | 21 | Create a new environment: 22 | 23 | conda create -n [env-name] 24 | 25 | Activate the environment: 26 | 27 | conda activate [env-name] 28 | 29 | 2) Installing dependencies in your environment: 30 | 31 | Install Tensorflow and all its dependencies: 32 | 33 | pip install tensorflow 34 | 35 | Install Keras: 36 | 37 | pip install keras 38 | 39 | Install OpenCV: 40 | 41 | conda install -c conda-forge opencv 42 | 43 | 3) If you want to use a CUDA compatible GPU for faster predictions: 44 | 45 | You will need CUDA and the Nvidia drivers installed in your computer: https://docs.nvidia.com/deeplearning/sdk/cudnn-install/ 46 | 47 | Then, install the GPU version of Tensorflow: 48 | 49 | pip install tensorflow-gpu 50 | 51 | -- Using FaceQnet for predicting scores: 52 | 2) Due to the size of the video example, please download the FaceQnet pretrained model here (.h5 file) and place it in the /src folder. 53 | -------------------------------------------------------------------------------- /faceQuality/get_quality.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from keras.models import load_model 3 | import numpy as np 4 | import os 5 | import cv2 6 | from FaceQNet import load_Qnet_model, face_quality 7 | 8 | # Loading the pretrained model 9 | model = load_Qnet_model() 10 | 11 | IMG_PATH = '/home/sai/YANG/image/video/nanning/haha' 12 | dir = os.listdir(IMG_PATH) 13 | count = len(dir) 14 | print('count:', count) 15 | for i in dir: 16 | count -= 1 17 | if count%1000==0: 18 | print('count:', count) 19 | dir_path = os.path.join(IMG_PATH, i) 20 | imgs_dir = os.listdir(dir_path) 21 | for j in imgs_dir: 22 | img_path = os.path.join(dir_path, j) 23 | img = cv2.imread(img_path) 24 | score = face_quality(model, img) 25 | # img = [cv2.resize(cv2.imread(img_path, cv2.IMREAD_COLOR), (224, 224))] 26 | # test_data = np.array(img, copy=False, dtype=np.float32) 27 | # score = model.predict(test_data, batch_size=1, verbose=1) 28 | path1 = str(score[0][0]) + '@' 29 | rename = path1 + j 30 | os.rename(img_path, os.path.join(dir_path, rename)) 31 | -------------------------------------------------------------------------------- /faceQuality/get_quality_clean.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import numpy as np 3 | import os 4 | import cv2 5 | import shutil 6 | 7 | IMG_PATH = '/data1t/glint-gate-retina-crop' 8 | High_PATH = '/data1t/glint_datasets/glint-aligned-v4-quality' 9 | dir = os.listdir(IMG_PATH) 10 | count = len(dir) 11 | print('count:', count) 12 | for i in dir: 13 | count -= 1 14 | if count%1000==0: 15 | print('count:', count) 16 | dir_path = os.path.join(IMG_PATH, i) 17 | imgs_dir = os.listdir(dir_path) 18 | 19 | save_path = os.path.join(High_PATH, i) 20 | if not os.path.exists(save_path): 21 | os.makedirs(save_path) 22 | for j in imgs_dir: 23 | img_path = os.path.join(dir_path, j) 24 | if not os.path.exists(img_path): 25 | continue 26 | path_index = j.index('@') 27 | score = float(j[:path_index]) 28 | if score > 0.45: 29 | shutil.copy(img_path, save_path) 30 | -------------------------------------------------------------------------------- /images/Abner_Martinez_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/images/Abner_Martinez_0001.jpg -------------------------------------------------------------------------------- /images/Akbar_Al_Baker_0001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/images/Akbar_Al_Baker_0001.jpg -------------------------------------------------------------------------------- /images/mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/images/mask.png -------------------------------------------------------------------------------- /images/src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/images/src.png -------------------------------------------------------------------------------- /make_rec/README.md: -------------------------------------------------------------------------------- 1 | insightface制作自己的数据及其训练 2 | # 1.生成,*.lst,property 3 | 运行:sh im2rec_my_lst.sh生成*.lst (加上--train-ratio 0.9可以按比例划分train和val) 4 | property是属性文件,里面内容是类别数和图像大小,例如 5 | 1000,112,112 其中1000代表人脸的类别数目,图片格式为112x112(一直都不知道怎么自动生成这个,我是自己写的) 6 | 7 | # 2.生成.rec,.idx 8 | 运行:sh im2rec_my.sh 9 | 10 | 11 | # 3.生成测试文件.bin 12 | ## 3.1.用gen_valdatasets.py 13 | 直接修改里面的几个参数就ok(推荐) 14 | 15 | ## 3.2.使用sh文件 16 | 首先需要制作一个test.txt文件,格式如下: 17 | 路径/img_1.jpg,路径/img_2.jpg, 1 18 | 路径/img_3.jpg,路径/img_4.jpg, 0 19 | [图片1,图片2,空格,标签]:如果相同,标签=1,不相同=0 20 | -------------------------------------------------------------------------------- /make_rec/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/make_rec/common/__init__.py -------------------------------------------------------------------------------- /make_rec/common/face_preprocess.py: -------------------------------------------------------------------------------- 1 | 2 | import cv2 3 | import numpy as np 4 | from skimage import transform as trans 5 | 6 | def parse_lst_line(line): 7 | vec = line.strip().split("\t") 8 | assert len(vec)>=3 9 | aligned = int(vec[0]) 10 | image_path = vec[1] 11 | label = int(vec[2]) 12 | bbox = None 13 | landmark = None 14 | #print(vec) 15 | if len(vec)>3: 16 | bbox = np.zeros( (4,), dtype=np.int32) 17 | for i in xrange(3,7): 18 | bbox[i-3] = int(vec[i]) 19 | landmark = None 20 | if len(vec)>7: 21 | _l = [] 22 | for i in xrange(7,17): 23 | _l.append(float(vec[i])) 24 | landmark = np.array(_l).reshape( (2,5) ).T 25 | #print(aligned) 26 | return image_path, label, bbox, landmark, aligned 27 | 28 | 29 | 30 | 31 | def read_image(img_path, **kwargs): 32 | mode = kwargs.get('mode', 'rgb') 33 | layout = kwargs.get('layout', 'HWC') 34 | if mode=='gray': 35 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_GRAYSCALE) 36 | else: 37 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_COLOR) 38 | if mode=='rgb': 39 | #print('to rgb') 40 | img = img[...,::-1] 41 | if layout=='CHW': 42 | img = np.transpose(img, (2,0,1)) 43 | return img 44 | 45 | 46 | def preprocess(img, bbox=None, landmark=None, **kwargs): 47 | if isinstance(img, str): 48 | img = read_image(img, **kwargs) 49 | M = None 50 | image_size = [] 51 | str_image_size = kwargs.get('image_size', '') 52 | if len(str_image_size)>0: 53 | image_size = [int(x) for x in str_image_size.split(',')] 54 | if len(image_size)==1: 55 | image_size = [image_size[0], image_size[0]] 56 | assert len(image_size)==2 57 | assert image_size[0]==112 58 | assert image_size[0]==112 or image_size[1]==96 59 | if landmark is not None: 60 | assert len(image_size)==2 61 | src = np.array([ 62 | [30.2946, 51.6963], 63 | [65.5318, 51.5014], 64 | [48.0252, 71.7366], 65 | [33.5493, 92.3655], 66 | [62.7299, 92.2041] ], dtype=np.float32 ) 67 | if image_size[1]==112: 68 | src[:,0] += 8.0 69 | dst = landmark.astype(np.float32) 70 | 71 | tform = trans.SimilarityTransform() 72 | tform.estimate(dst, src) 73 | M = tform.params[0:2,:] 74 | #M = cv2.estimateRigidTransform( dst.reshape(1,5,2), src.reshape(1,5,2), False) 75 | 76 | if M is None: 77 | if bbox is None: #use center crop 78 | det = np.zeros(4, dtype=np.int32) 79 | det[0] = int(img.shape[1]*0.0625) 80 | det[1] = int(img.shape[0]*0.0625) 81 | det[2] = img.shape[1] - det[0] 82 | det[3] = img.shape[0] - det[1] 83 | else: 84 | det = bbox 85 | margin = kwargs.get('margin', 44) 86 | bb = np.zeros(4, dtype=np.int32) 87 | bb[0] = np.maximum(det[0]-margin/2, 0) 88 | bb[1] = np.maximum(det[1]-margin/2, 0) 89 | bb[2] = np.minimum(det[2]+margin/2, img.shape[1]) 90 | bb[3] = np.minimum(det[3]+margin/2, img.shape[0]) 91 | ret = img[bb[1]:bb[3],bb[0]:bb[2],:] 92 | if len(image_size)>0: 93 | ret = cv2.resize(ret, (image_size[1], image_size[0])) 94 | return ret 95 | else: #do align using landmark 96 | assert len(image_size)==2 97 | 98 | #src = src[0:3,:] 99 | #dst = dst[0:3,:] 100 | 101 | 102 | #print(src.shape, dst.shape) 103 | #print(src) 104 | #print(dst) 105 | #print(M) 106 | #warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), borderValue = 0.0) 107 | warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT) 108 | 109 | #warped = cv2.resize(img,(image_size[1],image_size[0])) 110 | 111 | #tform3 = trans.ProjectiveTransform() 112 | #tform3.estimate(src, dst) 113 | #warped = trans.warp(img, tform3, output_shape=_shape) 114 | return warped 115 | 116 | 117 | -------------------------------------------------------------------------------- /make_rec/common/noise_sgd.py: -------------------------------------------------------------------------------- 1 | import mxnet.optimizer as optimizer 2 | from mxnet import ndarray as nd 3 | 4 | class NoiseSGD(optimizer.SGD): 5 | """Noise SGD. 6 | 7 | 8 | This optimizer accepts the same arguments as :class:`.SGD`. 9 | """ 10 | def __init__(self, scale, **kwargs): 11 | super(NoiseSGD, self).__init__(**kwargs) 12 | print('init noise sgd with', scale) 13 | self.scale = scale 14 | 15 | def update(self, index, weight, grad, state): 16 | assert(isinstance(weight, NDArray)) 17 | assert(isinstance(grad, NDArray)) 18 | self._update_count(index) 19 | lr = self._get_lr(index) 20 | wd = self._get_wd(index) 21 | 22 | grad = grad * self.rescale_grad 23 | if self.clip_gradient is not None: 24 | grad = clip(grad, -self.clip_gradient, self.clip_gradient) 25 | noise = nd.random.normal(scale = self.scale, shape = grad.shape, dtype=grad.dtype, ctx = grad.context) 26 | grad += noise 27 | 28 | if state is not None: 29 | mom = state 30 | mom[:] *= self.momentum 31 | grad += wd * weight 32 | mom[:] += grad 33 | grad[:] += self.momentum * mom 34 | weight[:] += -lr * grad 35 | else: 36 | assert self.momentum == 0.0 37 | weight[:] += -lr * (grad + wd * weight) 38 | 39 | -------------------------------------------------------------------------------- /make_rec/gen_datasets_lst.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | from __future__ import absolute_import 3 | from __future__ import division 4 | from __future__ import print_function 5 | 6 | import sys 7 | import os 8 | import argparse 9 | import numpy as np 10 | import random 11 | from time import sleep 12 | 13 | sys.path.append(os.path.join(os.path.dirname(__file__), 'common')) 14 | from common import face_image 15 | import cv2 16 | import time 17 | 18 | 19 | def to_rgb(img): 20 | w, h = img.shape 21 | ret = np.empty((w, h, 3), dtype=np.uint8) 22 | ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img 23 | return ret 24 | 25 | 26 | def main(args): 27 | # facenet.store_revision_info(src_path, output_dir, ' '.join(sys.argv)) 28 | dataset = face_image.get_dataset('lfw', args.input_dir) 29 | print('dataset size', 'lfw', len(dataset)) 30 | 31 | output_filename = os.path.join(args.output_dir, 'train.lst') 32 | 33 | with open(output_filename, "w") as text_file: 34 | nrof_images_total = 0 35 | nrof = np.zeros((5,), dtype=np.int32) 36 | for fimage in dataset: 37 | if nrof_images_total % 50000 == 0: 38 | print("Processing %d, (%s)" % (nrof_images_total, nrof)) 39 | nrof_images_total += 1 40 | 41 | _paths = fimage.image_path.split('/') 42 | a, b = _paths[-2], _paths[-1] 43 | target_dir = os.path.join(args.input_dir, a) 44 | # if not os.path.exists(target_dir): 45 | # os.makedirs(target_dir) 46 | target_file = os.path.join(target_dir, b) 47 | oline = '%d\t%s\t%d\n' % (1, target_file, int(fimage.classname)) 48 | text_file.write(oline) 49 | 50 | 51 | def parse_arguments(argv): 52 | parser = argparse.ArgumentParser() 53 | 54 | parser.add_argument('--input-dir', type=str, help='Directory with unaligned images.', 55 | default='/data1t/mask/glint-mask') 56 | parser.add_argument('--output-dir', type=str, help='Directory with aligned face thumbnails.', 57 | default='/data1t/mask/mask-output') 58 | 59 | return parser.parse_args(argv) 60 | 61 | 62 | if __name__ == '__main__': 63 | main(parse_arguments(sys.argv[1:])) 64 | -------------------------------------------------------------------------------- /make_rec/gen_val_bin.sh: -------------------------------------------------------------------------------- 1 | #前者表示lst,后者表示图像所在文件夹 2 | python2 gen_valdatasets.py --total-num 5000 --base-path ../images/train/aug_datasets/train --out-name ../images/train/aug_output/crop_ours_xiaoyi.bin 3 | -------------------------------------------------------------------------------- /make_rec/gen_valdatasets.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Jul 13 17:02:01 2018 4 | 5 | @author: wxy 6 | """ 7 | import os 8 | import numpy as np 9 | import cv2 10 | import pickle,itertools 11 | import random 12 | import argparse 13 | 14 | root_path = '/home/sai/YANG/image/Face_Recognition/Test_datasets/add_blake/' 15 | parser = argparse.ArgumentParser(description='face model test') 16 | # general 17 | parser.add_argument('--total-num', default=80000, type=int, help='numbers of paris') 18 | parser.add_argument('--same-path', default=root_path+'black_crop', type=str, help='img root') 19 | parser.add_argument('--out-name', default=root_path+'black_crop.bin', type=str, help='putput name') 20 | args = parser.parse_args() 21 | 22 | 23 | 24 | def do_flip(data): 25 | for idx in range(data.shape[0]): 26 | data[idx,:,:] = np.fliplr(data[idx,:,:]) 27 | 28 | def glob_format(path,fmt_list = ('.jpg','.png','.bmp')): 29 | fs = [] 30 | if not os.path.exists(path):return fs 31 | for root, dirs, files in os.walk(path): 32 | for file in files: 33 | item = os.path.join(root, file) 34 | fmt = os.path.splitext(item)[-1] 35 | if fmt not in fmt_list: continue 36 | fs.append(item) 37 | return fs 38 | 39 | 40 | def procese_pair(pair): 41 | a1 =[] #np.zeros((2,112,112,3)) 42 | #a1_flip=np.zeros((2,112,112,3)) 43 | for i in range(2): 44 | img = cv2.imread(pair[0]) 45 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 46 | #aligned = np.transpose(img, (2,0,1)) 47 | # imgg = cv2.imencode('.png', img) 48 | data_encode = np.array( cv2.imencode('.jpg', img)[1]).tostring() 49 | a1[i] = data_encode 50 | #img_flip=do_flip(img.copy()) 51 | #data_encode = np.array( cv2.imencode('.jpg', img_flip)[1]).tostring() 52 | #a1_flip[i]= data_encode 53 | return a1 54 | # return a1, a1_flip 55 | #boshi original 56 | def gen_pairlist(base_path): 57 | img_list = glob_format(base_path) 58 | random.shuffle(img_list) 59 | pair_list_True=[] 60 | pair_list_False =[] 61 | 62 | gentor = itertools.combinations( img_list, 2) 63 | for pair in gentor: 64 | if len(pair_list_True) >=total_num and len(pair_list_False) >=total_num : 65 | break 66 | if pair[0].split("/")[-2] == pair[1].split("/")[-2]: 67 | pair_list_True.append(pair) 68 | else: 69 | pair_list_False.append(pair) 70 | 71 | num = min(len(pair_list_False),len(pair_list_True)) 72 | 73 | print('num1:', num) 74 | pair_list_True = random.sample(pair_list_True, num) 75 | pair_list_False = random.sample(pair_list_False, num) #1:3 true:false 76 | pair_list = pair_list_True + pair_list_False 77 | label_list =[True]*len(pair_list_True) +[False]*len(pair_list_False) 78 | return pair_list, label_list 79 | 80 | def main(base_path, out_name): 81 | pair_list, label_list = gen_pairlist(base_path) 82 | img1_list =[] #np.zeros((num*2,112,112,3),dtype=np.uint8) 83 | #img2_list =[] #np.zeros((num*2,112,112,3),dtype=np.uint8) 84 | index = list(range(len(pair_list))) 85 | random.shuffle(index) 86 | label_out=[] 87 | for i in index: 88 | pair =pair_list[i] 89 | img1_list.append(open(pair[0],"rb").read()) 90 | img1_list.append(open(pair[1],"rb").read()) 91 | label_out.append(label_list[i]) 92 | 93 | #a1, a1_flip = procese_pair(pair) 94 | 95 | #img1_list+=a1 96 | #img2_list+=a1_flip 97 | #for k in range(2): 98 | # img1_list.append(a1[k]) 99 | # img2_list.append(a1_flip[k]) 100 | #img1_list[i*2+k] =a1[k] 101 | #img2_list[i*2+k] =a1_flip[k] 102 | out = (img1_list,label_out) 103 | 104 | with open(out_name,'wb') as f: 105 | pickle.dump(out,f) 106 | f.close() 107 | print ('done') 108 | 109 | # import csv 110 | # with open('../images/test/pairs_std.csv', 'w') as csvFile: 111 | # csvwriter = csv.writer(csvFile) 112 | # for cs in pair_list: 113 | # csvwriter.writerow(cs) 114 | 115 | if __name__ == "__main__": 116 | total_num =args.total_num 117 | base_path = args.same_path 118 | out_name = args.out_name 119 | main(base_path, out_name) 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /make_rec/generate_lst.sh: -------------------------------------------------------------------------------- 1 | #insigtface自带的lst,--input-dir是输入图片的路径,--output-dir输出图片的路径 2 | python3 gen_datasets_lst.py --input-dir /data1t/glint-gate-retina-crop --output-dir /data1t/glint-gate-retina-output 3 | #前者表示要生成的.lst文件名,后者表示图像所在文件夹 4 | #python im2rec_my.py --list --recursive /data1t/glink-gate/glink_gate_datasets/train /data1t/glink-gate/glink-gate-aligned/ 5 | -------------------------------------------------------------------------------- /make_rec/generate_rec.sh: -------------------------------------------------------------------------------- 1 | #insigtface自带的rec,路径表示为save的地址 2 | python3 face2rec2.py /data1t/glint-gate-retina-output 3 | #mxnet原始版本生成rec, 前者表示lst,后者表示图像所在文件夹 4 | #python im2rec_my.py /data1t/glink-gate/glink_gate_datasets/train /data1t/glink-gate/glink-gate-aligned/ 5 | -------------------------------------------------------------------------------- /remove_lowshot.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -* 2 | # clean unuseful imgs in datasets(one id imgs low 10) 3 | import os, shutil 4 | import argparse 5 | 6 | 7 | if __name__ == '__main__': 8 | parser = argparse.ArgumentParser(description = 'remove low-shot classes') 9 | parser.add_argument("-root", "--root", help = "specify your dir",default = '/data1t/GateID/gate_aligned_retina_crop', type = str) 10 | parser.add_argument("-min_num", "--min_num", help = "remove the classes with less than min_num samples", default = 3, type = int) 11 | args = parser.parse_args() 12 | 13 | root = args.root # specify your dir 14 | min_num = args.min_num # remove the classes with less than min_num samples 15 | 16 | cwd = os.getcwd() # delete '.DS_Store' existed in the source_root 17 | os.chdir(root) 18 | os.system("find . -name '*.DS_Store' -type f -delete") 19 | os.chdir(cwd) 20 | import re 21 | for subfolder in os.listdir(root): 22 | if re.search('.jpg', subfolder): 23 | os.remove(os.path.join(root, subfolder)) 24 | continue 25 | file_num = len(os.listdir(os.path.join(root, subfolder))) 26 | if file_num <= min_num: 27 | print("Class {} has less than {} samples, removed!".format(subfolder, min_num)) 28 | shutil.rmtree(os.path.join(root, subfolder)) -------------------------------------------------------------------------------- /src/--target: -------------------------------------------------------------------------------- 1 | /usr/local/lib/python2.7/dist-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`. 2 | from ._conv import register_converters as _register_converters 3 | usage: train_softmax.py [-h] [--data-dir DATA_DIR] [--prefix PREFIX] 4 | [--pretrained PRETRAINED] [--retrain] [--ckpt CKPT] 5 | [--network NETWORK] [--version-se VERSION_SE] 6 | [--version-input VERSION_INPUT] 7 | [--version-output VERSION_OUTPUT] 8 | [--version-unit VERSION_UNIT] [--end-epoch END_EPOCH] 9 | [--lr LR] [--wd WD] [--mom MOM] [--emb-size EMB_SIZE] 10 | [--per-batch-size PER_BATCH_SIZE] 11 | [--margin-m MARGIN_M] [--margin-s MARGIN_S] 12 | [--easy-margin EASY_MARGIN] 13 | [--margin-verbose MARGIN_VERBOSE] [--margin MARGIN] 14 | [--beta BETA] [--beta-min BETA_MIN] 15 | [--beta-freeze BETA_FREEZE] [--gamma GAMMA] 16 | [--power POWER] [--scale SCALE] 17 | [--center-alpha CENTER_ALPHA] 18 | [--center-scale CENTER_SCALE] 19 | [--images-per-identity IMAGES_PER_IDENTITY] 20 | [--triplet-bag-size TRIPLET_BAG_SIZE] 21 | [--triplet-alpha TRIPLET_ALPHA] 22 | [--triplet-max-ap TRIPLET_MAX_AP] [--verbose VERBOSE] 23 | [--loss-type LOSS_TYPE] [--incay INCAY] 24 | [--use-deformable USE_DEFORMABLE] 25 | [--rand-mirror RAND_MIRROR] [--patch PATCH] 26 | [--lr-steps LR_STEPS] [--max-steps MAX_STEPS] 27 | [--target TARGET] [--memonger] 28 | train_softmax.py: error: unrecognized arguments: crop_lfw ../models/model-r100-crop/log 29 | [19:40:25] src/engine/engine.cc:55: MXNet start using engine: ThreadedEnginePerDevice 30 | -------------------------------------------------------------------------------- /src/align/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/src/align/__init__.py -------------------------------------------------------------------------------- /src/align/det1.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/src/align/det1.npy -------------------------------------------------------------------------------- /src/align/det2.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/src/align/det2.npy -------------------------------------------------------------------------------- /src/align/det3.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/src/align/det3.npy -------------------------------------------------------------------------------- /src/api/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | import face_model 3 | import argparse 4 | import json 5 | import base64 6 | #import requests 7 | import numpy as np 8 | import urllib 9 | import cv2 10 | from flask import Flask, render_template, request, jsonify 11 | 12 | 13 | parser = argparse.ArgumentParser(description='do verification') 14 | # general 15 | parser.add_argument('--image-size', default='112,112', help='') 16 | parser.add_argument('--model', default='../model/softmax,50', help='path to load model.') 17 | parser.add_argument('--gpu', default=0, type=int, help='gpu id') 18 | parser.add_argument('--threshold', default=1.24, type=float, help='ver dist threshold') 19 | args = parser.parse_args() 20 | 21 | model = face_model.FaceModel(args) 22 | 23 | app = Flask(__name__) 24 | 25 | @app.route('/') 26 | def hello_world(): 27 | return 'Hello, This is InsightFace!' 28 | 29 | def image_resize(image): 30 | m = min(image.shape[0], image.shape[1]) 31 | f = 640.0/m 32 | if f<1.0: 33 | image = cv2.resize(image, (int(image.shape[1]*f), int(image.shape[0]*f))) 34 | return image 35 | 36 | def get_image(data): 37 | image = None 38 | if 'url' in data: 39 | url = data['url'] 40 | if url.startswith('http'): 41 | resp = urllib.urlopen(url) 42 | image = np.asarray(bytearray(resp.read()), dtype="uint8") 43 | image = cv2.imdecode(image, cv2.IMREAD_COLOR) 44 | else: 45 | image = cv2.imread(url, cv2.IMREAD_COLOR) 46 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 47 | image = image_resize(image) 48 | elif 'data' in data: 49 | _bin = data['data'] 50 | if _bin is not None: 51 | if not isinstance(_bin, list): 52 | _bin = base64.b64decode(_bin) 53 | _bin = np.fromstring(_bin, np.uint8) 54 | image = cv2.imdecode(_bin, cv2.IMREAD_COLOR) 55 | image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) 56 | image = image_resize(image) 57 | else: 58 | image = [] 59 | for __bin in _bin: 60 | __bin = base64.b64decode(__bin) 61 | __bin = np.fromstring(__bin, np.uint8) 62 | _image = cv2.imdecode(__bin, cv2.IMREAD_COLOR) 63 | _image = cv2.cvtColor(_image, cv2.COLOR_BGR2RGB) 64 | _image = image_resize(_image) 65 | image.append(_image) 66 | 67 | return image 68 | 69 | @app.route('/ver', methods=['POST']) 70 | def ver(): 71 | try: 72 | data = request.data 73 | values = json.loads(data) 74 | source_image = get_image(values['source']) 75 | if source_image is None: 76 | print('source image is None') 77 | return '-1' 78 | assert not isinstance(source_image, list) 79 | print(source_image.shape) 80 | target_image = get_image(values['target']) 81 | if target_image is None: 82 | print('target image is None') 83 | return '-1' 84 | #print(target_image.shape) 85 | if not isinstance(target_image, list): 86 | target_image = [target_image] 87 | #print('before call') 88 | #ret = model.is_same_id(source_image, target_image) 89 | ret = model.sim(source_image, target_image) 90 | except Exception as ex: 91 | print(ex) 92 | return '-1' 93 | 94 | #return str(int(ret)) 95 | print('sim', ret) 96 | return "%1.3f"%ret 97 | 98 | if __name__ == '__main__': 99 | app.run('0.0.0.0', port=18080, debug=False) 100 | -------------------------------------------------------------------------------- /src/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bleakie/MaskInsightface/94511404eaa7912945fa087e6445a3608c46aaea/src/common/__init__.py -------------------------------------------------------------------------------- /src/common/face_preprocess.py: -------------------------------------------------------------------------------- 1 | 2 | import cv2 3 | import numpy as np 4 | from skimage import transform as trans 5 | 6 | def parse_lst_line(line): 7 | vec = line.strip().split("\t") 8 | assert len(vec)>=3 9 | aligned = int(vec[0]) 10 | image_path = vec[1] 11 | label = int(vec[2]) 12 | bbox = None 13 | landmark = None 14 | #print(vec) 15 | if len(vec)>3: 16 | bbox = np.zeros( (4,), dtype=np.int32) 17 | for i in xrange(3,7): 18 | bbox[i-3] = int(vec[i]) 19 | landmark = None 20 | if len(vec)>7: 21 | _l = [] 22 | for i in xrange(7,17): 23 | _l.append(float(vec[i])) 24 | landmark = np.array(_l).reshape( (2,5) ).T 25 | #print(aligned) 26 | return image_path, label, bbox, landmark, aligned 27 | 28 | 29 | 30 | 31 | def read_image(img_path, **kwargs): 32 | mode = kwargs.get('mode', 'rgb') 33 | layout = kwargs.get('layout', 'HWC') 34 | if mode=='gray': 35 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_GRAYSCALE) 36 | else: 37 | img = cv2.imread(img_path, cv2.CV_LOAD_IMAGE_COLOR) 38 | if mode=='rgb': 39 | #print('to rgb') 40 | img = img[...,::-1] 41 | if layout=='CHW': 42 | img = np.transpose(img, (2,0,1)) 43 | return img 44 | 45 | 46 | def preprocess(img, bbox=None, landmark=None, **kwargs): 47 | if isinstance(img, str): 48 | img = read_image(img, **kwargs) 49 | M = None 50 | image_size = [] 51 | str_image_size = kwargs.get('image_size', '') 52 | if len(str_image_size)>0: 53 | image_size = [int(x) for x in str_image_size.split(',')] 54 | if len(image_size)==1: 55 | image_size = [image_size[0], image_size[0]] 56 | assert len(image_size)==2 57 | assert image_size[0]==112 58 | assert image_size[0]==112 or image_size[1]==96 59 | if landmark is not None: 60 | assert len(image_size)==2 61 | src = np.array([ 62 | [30.2946, 51.6963], 63 | [65.5318, 51.5014], 64 | [48.0252, 71.7366], 65 | [33.5493, 92.3655], 66 | [62.7299, 92.2041] ], dtype=np.float32 ) 67 | if image_size[1]==112: 68 | src[:,0] += 8.0 69 | dst = landmark.astype(np.float32) 70 | 71 | tform = trans.SimilarityTransform() 72 | tform.estimate(dst, src) 73 | M = tform.params[0:2,:] 74 | #M = cv2.estimateRigidTransform( dst.reshape(1,5,2), src.reshape(1,5,2), False) 75 | 76 | if M is None: 77 | if bbox is None: #use center crop 78 | det = np.zeros(4, dtype=np.int32) 79 | det[0] = int(img.shape[1]*0.0625) 80 | det[1] = int(img.shape[0]*0.0625) 81 | det[2] = img.shape[1] - det[0] 82 | det[3] = img.shape[0] - det[1] 83 | else: 84 | det = bbox 85 | margin = kwargs.get('margin', 44) 86 | bb = np.zeros(4, dtype=np.int32) 87 | bb[0] = np.maximum(det[0]-margin/2, 0) 88 | bb[1] = np.maximum(det[1]-margin/2, 0) 89 | bb[2] = np.minimum(det[2]+margin/2, img.shape[1]) 90 | bb[3] = np.minimum(det[3]+margin/2, img.shape[0]) 91 | ret = img[bb[1]:bb[3],bb[0]:bb[2],:] 92 | if len(image_size)>0: 93 | ret = cv2.resize(ret, (image_size[1], image_size[0])) 94 | return ret 95 | else: #do align using landmark 96 | assert len(image_size)==2 97 | 98 | #src = src[0:3,:] 99 | #dst = dst[0:3,:] 100 | 101 | 102 | #print(src.shape, dst.shape) 103 | #print(src) 104 | #print(dst) 105 | #print(M) 106 | #warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), borderValue = 0.0) 107 | warped = cv2.warpAffine(img,M,(image_size[1],image_size[0]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT) 108 | 109 | #warped = cv2.resize(img,(image_size[1],image_size[0])) 110 | 111 | #tform3 = trans.ProjectiveTransform() 112 | #tform3.estimate(src, dst) 113 | #warped = trans.warp(img, tform3, output_shape=_shape) 114 | return warped 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/common/noise_sgd.py: -------------------------------------------------------------------------------- 1 | import mxnet.optimizer as optimizer 2 | from mxnet import ndarray as nd 3 | 4 | class NoiseSGD(optimizer.SGD): 5 | """Noise SGD. 6 | 7 | 8 | This optimizer accepts the same arguments as :class:`.SGD`. 9 | """ 10 | def __init__(self, scale, **kwargs): 11 | super(NoiseSGD, self).__init__(**kwargs) 12 | print('init noise sgd with', scale) 13 | self.scale = scale 14 | 15 | def update(self, index, weight, grad, state): 16 | assert(isinstance(weight, NDArray)) 17 | assert(isinstance(grad, NDArray)) 18 | self._update_count(index) 19 | lr = self._get_lr(index) 20 | wd = self._get_wd(index) 21 | 22 | grad = grad * self.rescale_grad 23 | if self.clip_gradient is not None: 24 | grad = clip(grad, -self.clip_gradient, self.clip_gradient) 25 | noise = nd.random.normal(scale = self.scale, shape = grad.shape, dtype=grad.dtype, ctx = grad.context) 26 | grad += noise 27 | 28 | if state is not None: 29 | mom = state 30 | mom[:] *= self.momentum 31 | grad += wd * weight 32 | mom[:] += grad 33 | grad[:] += self.momentum * mom 34 | weight[:] += -lr * grad 35 | else: 36 | assert self.momentum == 0.0 37 | weight[:] += -lr * (grad + wd * weight) 38 | 39 | -------------------------------------------------------------------------------- /src/data/agedb2pack2.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | #import mxnet as mx 5 | #from mxnet import ndarray as nd 6 | import argparse 7 | import cv2 8 | import pickle 9 | import numpy as np 10 | import sys 11 | from scipy import misc 12 | import os 13 | import tensorflow as tf 14 | from scipy.io import loadmat 15 | sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'align')) 16 | #sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) 17 | import detect_face 18 | import face_image 19 | import face_preprocess 20 | #import lfw 21 | 22 | def to_rgb(img): 23 | w, h = img.shape 24 | ret = np.empty((w, h, 3), dtype=np.uint8) 25 | ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img 26 | return ret 27 | 28 | 29 | def IOU(Reframe,GTframe): 30 | x1 = Reframe[0]; 31 | y1 = Reframe[1]; 32 | width1 = Reframe[2]-Reframe[0]; 33 | height1 = Reframe[3]-Reframe[1]; 34 | 35 | x2 = GTframe[0] 36 | y2 = GTframe[1] 37 | width2 = GTframe[2]-GTframe[0] 38 | height2 = GTframe[3]-GTframe[1] 39 | 40 | endx = max(x1+width1,x2+width2) 41 | startx = min(x1,x2) 42 | width = width1+width2-(endx-startx) 43 | 44 | endy = max(y1+height1,y2+height2) 45 | starty = min(y1,y2) 46 | height = height1+height2-(endy-starty) 47 | 48 | if width <=0 or height <= 0: 49 | ratio = 0 50 | else: 51 | Area = width*height 52 | Area1 = width1*height1 53 | Area2 = width2*height2 54 | ratio = Area*1./(Area1+Area2-Area) 55 | return ratio 56 | 57 | parser = argparse.ArgumentParser(description='Package AgeDB images') 58 | # general 59 | parser.add_argument('--data-dir', default='', help='') 60 | parser.add_argument('--image-size', type=str, default='112,96', help='') 61 | parser.add_argument('--output', default='./', help='path to save.') 62 | args = parser.parse_args() 63 | 64 | 65 | for part in [ ('04_FINAL_protocol_30_years.mat', 'agedb_30') ]: 66 | mat_file = os.path.join(args.data_dir, part[0]) 67 | mat_data = loadmat(mat_file) 68 | print(mat_data.__class__) 69 | data = mat_data['splits'] 70 | 71 | bins = [] 72 | issame_list = [] 73 | nrof = [0, 0, 0] 74 | print('processing', part[1]) 75 | pp = 0 76 | for i in xrange(data.shape[0]): 77 | split = data[i][0][0][0][0] 78 | print(split.shape) 79 | for c in xrange(split.shape[1]): 80 | last_name = '' 81 | for r in xrange(split.shape[0]): 82 | pp+=1 83 | if pp%10==0: 84 | print('processing', pp, nrof) 85 | item = split[r][c][0][0] 86 | path = str(item[0][0]) 87 | vec = path.split('_') 88 | assert len(vec)>=5 89 | name = vec[0] 90 | if r==1: 91 | issame = False 92 | if name==last_name: 93 | issame = True 94 | #print(issame) 95 | issame_list.append(issame) 96 | last_name = name 97 | age = int(item[1]) 98 | #print(path, age) 99 | #sys.exit(0) 100 | img_path = os.path.join(args.data_dir, '03_Protocol_Images', path+".jpg") 101 | #print(img_path) 102 | img = misc.imread(img_path) 103 | if img.ndim == 2: 104 | img = to_rgb(img) 105 | assert img.ndim==3 106 | assert img.shape[2]==3 107 | #img = img[:,:,0:3] 108 | all_landmark = np.zeros( (68,2), dtype=np.float32) 109 | pts_file = img_path[0:-3]+"pts" 110 | pp=0 111 | 112 | for line in open(pts_file, 'r'): 113 | pp+=1 114 | pointid = pp-3 115 | if pointid<1 or pointid>68: 116 | continue 117 | point = [float(x) for x in line.strip().split()] 118 | assert len(point)==2 119 | point = np.array(point).reshape( (1,2) ) 120 | #print(pointid) 121 | all_landmark[pointid-1,:] = point 122 | 123 | 124 | _landmark = np.zeros( (5,2), dtype=np.float32) 125 | _landmark[0,:] = (all_landmark[36,:]+all_landmark[39,:])/2 126 | _landmark[1,:] = (all_landmark[42,:]+all_landmark[45,:])/2 127 | _landmark[2,:] = all_landmark[33,:] 128 | _landmark[3,:] = all_landmark[48,:] 129 | _landmark[4,:] = all_landmark[54,:] 130 | _bbox = None 131 | warped = face_preprocess.preprocess(img, bbox=_bbox, landmark = _landmark, image_size=args.image_size) 132 | warped = warped[...,::-1] #to bgr 133 | _, s = cv2.imencode('.jpg', warped) 134 | bins.append(s) 135 | print(nrof) 136 | outname = os.path.join(args.output, part[1]+'.bin') 137 | with open(outname, 'wb') as f: 138 | pickle.dump((bins, issame_list), f, protocol=pickle.HIGHEST_PROTOCOL) 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/data/dataset_info.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import mxnet as mx 7 | from mxnet import ndarray as nd 8 | import random 9 | import argparse 10 | import cv2 11 | import time 12 | import sklearn 13 | from sklearn.decomposition import PCA 14 | from easydict import EasyDict as edict 15 | from sklearn.cluster import DBSCAN 16 | import numpy as np 17 | 18 | sys.path.append(os.path.join(os.path.dirname(__file__),'..', 'common')) 19 | import face_image 20 | 21 | 22 | def main(args): 23 | path_imgrec = os.path.join(args.input, 'train.rec') 24 | path_imgidx = os.path.join(args.input, 'train.idx') 25 | imgrec = mx.recordio.MXIndexedRecordIO(path_imgidx, path_imgrec, 'r') # pylint: disable=redefined-variable-type 26 | s = imgrec.read_idx(0) 27 | header, _ = mx.recordio.unpack(s) 28 | assert header.flag>0 29 | print('header0 label', header.label) 30 | header0 = (int(header.label[0]), int(header.label[1])) 31 | print('identities', header0[1]-header0[0]) 32 | print('images', header0[0]) 33 | 34 | if __name__ == '__main__': 35 | parser = argparse.ArgumentParser(description='') 36 | # general 37 | parser.add_argument('--input', default='', type=str, help='') 38 | args = parser.parse_args() 39 | main(args) 40 | 41 | -------------------------------------------------------------------------------- /src/data/dataset_relabel.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import mxnet as mx 7 | from mxnet import ndarray as nd 8 | import random 9 | import argparse 10 | import cv2 11 | import time 12 | import sklearn 13 | from sklearn.decomposition import PCA 14 | from easydict import EasyDict as edict 15 | from sklearn.cluster import DBSCAN 16 | import numpy as np 17 | 18 | sys.path.append(os.path.join(os.path.dirname(__file__),'..', 'common')) 19 | import face_image 20 | 21 | def main(args): 22 | include_datasets = args.include.split(',') 23 | rec_list = [] 24 | for ds in include_datasets: 25 | path_imgrec = os.path.join(ds, 'train.rec') 26 | path_imgidx = os.path.join(ds, 'train.idx') 27 | imgrec = mx.recordio.MXIndexedRecordIO(path_imgidx, path_imgrec, 'r') # pylint: disable=redefined-variable-type 28 | rec_list.append(imgrec) 29 | if not os.path.exists(args.output): 30 | os.makedirs(args.output) 31 | writer = mx.recordio.MXIndexedRecordIO(os.path.join(args.output, 'train.idx'), os.path.join(args.output, 'train.rec'), 'w') 32 | for ds_id in xrange(len(rec_list)): 33 | id_list = [] 34 | imgrec = rec_list[ds_id] 35 | s = imgrec.read_idx(0) 36 | writer.write_idx(0, s) 37 | header, _ = mx.recordio.unpack(s) 38 | assert header.flag>0 39 | print('header0 label', header.label) 40 | header0 = (int(header.label[0]), int(header.label[1])) 41 | seq_identity = range(int(header.label[0]), int(header.label[1])) 42 | pp=0 43 | nlabel = -1 44 | for identity in seq_identity: 45 | pp+=1 46 | if pp%10==0: 47 | print('processing id', pp) 48 | s = imgrec.read_idx(identity) 49 | writer.write_idx(identity, s) 50 | header, _ = mx.recordio.unpack(s) 51 | nlabel+=1 52 | for _idx in xrange(int(header.label[0]), int(header.label[1])): 53 | s = imgrec.read_idx(_idx) 54 | _header, _content = mx.recordio.unpack(s) 55 | nheader = mx.recordio.IRHeader(0, nlabel, _idx, 0) 56 | s = mx.recordio.pack(nheader, _content) 57 | writer.write_idx(_idx, s) 58 | 59 | print('max label', nlabel) 60 | 61 | 62 | 63 | if __name__ == '__main__': 64 | parser = argparse.ArgumentParser(description='do dataset merge') 65 | # general 66 | parser.add_argument('--include', default='', type=str, help='') 67 | parser.add_argument('--output', default='', type=str, help='') 68 | args = parser.parse_args() 69 | main(args) 70 | 71 | -------------------------------------------------------------------------------- /src/data/lfw2pack.py: -------------------------------------------------------------------------------- 1 | import mxnet as mx 2 | from mxnet import ndarray as nd 3 | import argparse 4 | import pickle 5 | import sys 6 | import os 7 | sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'eval')) 8 | import lfw 9 | 10 | parser = argparse.ArgumentParser(description='Package LFW images') 11 | # general 12 | parser.add_argument('--data-dir', default='', help='') 13 | parser.add_argument('--image-size', type=str, default='112,96', help='') 14 | parser.add_argument('--output', default='', help='path to save.') 15 | args = parser.parse_args() 16 | lfw_dir = args.data_dir 17 | image_size = [int(x) for x in args.image_size.split(',')] 18 | lfw_pairs = lfw.read_pairs(os.path.join(lfw_dir, 'pairs.txt')) 19 | lfw_paths, issame_list = lfw.get_paths(lfw_dir, lfw_pairs, 'jpg') 20 | lfw_bins = [] 21 | #lfw_data = nd.empty((len(lfw_paths), 3, image_size[0], image_size[1])) 22 | i = 0 23 | for path in lfw_paths: 24 | with open(path, 'rb') as fin: 25 | _bin = fin.read() 26 | lfw_bins.append(_bin) 27 | #img = mx.image.imdecode(_bin) 28 | #img = nd.transpose(img, axes=(2, 0, 1)) 29 | #lfw_data[i][:] = img 30 | i+=1 31 | if i%1000==0: 32 | print('loading lfw', i) 33 | 34 | with open(args.output, 'wb') as f: 35 | pickle.dump((lfw_bins, issame_list), f, protocol=pickle.HIGHEST_PROTOCOL) 36 | -------------------------------------------------------------------------------- /src/eval/do_ver.sh: -------------------------------------------------------------------------------- 1 | 2 | #python -u verification.py --gpu 0 --data-dir /opt/jiaguo/faces_vgg_112x112 --image-size 112,112 --model '../../model/softmax1010d3-r101-p0_0_96_112_0,21|22|32' --target agedb_30 3 | python -u verification.py --gpu 0 --data-dir /opt/jiaguo/faces_normed --image-size 112,96 --model '../../model31/sphere-m51-p0_0_96_112_0,90' --target agedb_30 --batch-size 128 4 | -------------------------------------------------------------------------------- /src/eval/ytf_badcases.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import sys 6 | import os 7 | import numpy as np 8 | import cv2 9 | 10 | pairs_file = '/raid5data/dplearn/YTF/splits2.txt' 11 | stat = [0,0] 12 | for line in open(pairs_file, 'r'): 13 | line = line.strip() 14 | if line.startswith('split'): 15 | continue 16 | vec = line.split(',') 17 | issame = int(vec[-1]) 18 | if issame: 19 | stat[0]+=1 20 | else: 21 | stat[1]+=1 22 | print('stat', stat) 23 | 24 | image_dir = '/raid5data/dplearn/YTF/images' 25 | 26 | def get_img(name, vid): 27 | input_dir = os.path.join(image_dir, name, str(vid)) 28 | paths = [] 29 | for img in os.listdir(input_dir): 30 | path = os.path.join(input_dir, img) 31 | paths.append(path) 32 | paths = sorted(paths) 33 | parts = 8 34 | assert len(paths)>=parts 35 | gap = len(paths)//parts 36 | img = None 37 | for i in xrange(parts): 38 | idx = gap*i 39 | path = paths[idx] 40 | _img = cv2.imread(path) 41 | #print(_img.shape) 42 | if img is None: 43 | img = _img 44 | else: 45 | img = np.concatenate( (img, _img), axis=1) 46 | return img 47 | 48 | 49 | text_color = (153,255,51) 50 | for input in ['ytf_false_positive', 'ytf_false_negative']: 51 | all_img = None 52 | pp = 0 53 | for line in open(input+".log", 'r'): 54 | if line.startswith("\t"): 55 | break 56 | vec = line.strip().split(',') 57 | img1 = get_img(vec[0], int(vec[1])) 58 | img2 = get_img(vec[2], int(vec[3])) 59 | img = np.concatenate( (img1, img2), axis=0) 60 | if all_img is None: 61 | all_img = img 62 | else: 63 | all_img = np.concatenate( (all_img, img), axis=0) 64 | blank_img = np.zeros( (20, 112*8,3), dtype=np.uint8) 65 | blank_img[:,:,:] = 255 66 | font = cv2.FONT_HERSHEY_SIMPLEX 67 | k = "centre-distance:%.3f"%(float(vec[4])) 68 | #print(k) 69 | cv2.putText(blank_img,k,(350,blank_img.shape[0]-4), font, 0.6, text_color, 2) 70 | all_img = np.concatenate( (all_img, blank_img), axis=0) 71 | pp+=1 72 | 73 | filename = os.path.join('badcases', input+".png") 74 | cv2.imwrite(filename, all_img) 75 | 76 | -------------------------------------------------------------------------------- /src/losses/center_loss.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # MXNET_CPU_WORKER_NTHREADS must be greater than 1 for custom op to work on CPU 4 | #os.environ['MXNET_CPU_WORKER_NTHREADS'] = '2' 5 | import mxnet as mx 6 | 7 | 8 | # define metric of accuracy 9 | class Accuracy(mx.metric.EvalMetric): 10 | def __init__(self, num=None): 11 | super(Accuracy, self).__init__('accuracy', num) 12 | 13 | def update(self, labels, preds): 14 | mx.metric.check_label_shapes(labels, preds) 15 | 16 | if self.num is not None: 17 | assert len(labels) == self.num 18 | 19 | pred_label = mx.nd.argmax_channel(preds[0]).asnumpy().astype('int32') 20 | label = labels[0].asnumpy().astype('int32') 21 | 22 | mx.metric.check_label_shapes(label, pred_label) 23 | 24 | self.sum_metric += (pred_label.flat == label.flat).sum() 25 | self.num_inst += len(pred_label.flat) 26 | 27 | 28 | # define some metric of center_loss 29 | class CenterLossMetric(mx.metric.EvalMetric): 30 | def __init__(self): 31 | super(CenterLossMetric, self).__init__('center_loss') 32 | 33 | def update(self, labels, preds): 34 | self.sum_metric += preds[1].asnumpy()[0] 35 | self.num_inst += 1 36 | 37 | 38 | # see details: 39 | # 40 | class CenterLoss(mx.operator.CustomOp): 41 | def __init__(self, ctx, shapes, dtypes, num_class, alpha, scale=1.0): 42 | if not len(shapes[0]) == 2: 43 | raise ValueError('dim for input_data shoudl be 2 for CenterLoss') 44 | 45 | self.alpha = alpha 46 | self.batch_size = shapes[0][0] 47 | self.num_class = num_class 48 | self.scale = scale 49 | 50 | def forward(self, is_train, req, in_data, out_data, aux): 51 | labels = in_data[1].asnumpy() 52 | diff = aux[0] 53 | center = aux[1] 54 | 55 | # store x_i - c_yi 56 | for i in range(self.batch_size): 57 | diff[i] = in_data[0][i] - center[int(labels[i])] 58 | 59 | loss = mx.nd.sum(mx.nd.square(diff)) / self.batch_size / 2 60 | self.assign(out_data[0], req[0], loss) 61 | 62 | def backward(self, req, out_grad, in_data, out_data, in_grad, aux): 63 | diff = aux[0] 64 | center = aux[1] 65 | sum_ = aux[2] 66 | 67 | # back grad is just scale * ( x_i - c_yi) 68 | grad_scale = float(self.scale/self.batch_size) 69 | self.assign(in_grad[0], req[0], diff * grad_scale) 70 | 71 | # update the center 72 | labels = in_data[1].asnumpy() 73 | label_occur = dict() 74 | for i, label in enumerate(labels): 75 | label_occur.setdefault(int(label), []).append(i) 76 | 77 | for label, sample_index in label_occur.items(): 78 | sum_[:] = 0 79 | for i in sample_index: 80 | sum_ = sum_ + diff[i] 81 | delta_c = sum_ / (1 + len(sample_index)) 82 | center[label] += self.alpha * delta_c 83 | 84 | 85 | @mx.operator.register("centerloss") 86 | class CenterLossProp(mx.operator.CustomOpProp): 87 | def __init__(self, num_class, alpha, scale=1.0, batchsize=64): 88 | super(CenterLossProp, self).__init__(need_top_grad=False) 89 | 90 | # convert it to numbers 91 | self.num_class = int(num_class) 92 | self.alpha = float(alpha) 93 | self.scale = float(scale) 94 | self.batchsize = int(batchsize) 95 | 96 | def list_arguments(self): 97 | return ['data', 'label'] 98 | 99 | def list_outputs(self): 100 | return ['output'] 101 | 102 | def list_auxiliary_states(self): 103 | # call them 'bias' for zero initialization 104 | return ['diff_bias', 'center_bias', 'sum_bias'] 105 | 106 | def infer_shape(self, in_shape): 107 | data_shape = in_shape[0] 108 | label_shape = (in_shape[0][0],) 109 | 110 | # store diff , same shape as input batch 111 | diff_shape = [self.batchsize, data_shape[1]] 112 | 113 | # store the center of each class , should be ( num_class, d ) 114 | center_shape = [self.num_class, diff_shape[1]] 115 | 116 | # computation buf 117 | sum_shape = [diff_shape[1],] 118 | 119 | output_shape = [1, ] 120 | return [data_shape, label_shape], [output_shape], [diff_shape, center_shape, sum_shape] 121 | 122 | def create_operator(self, ctx, shapes, dtypes): 123 | return CenterLoss(ctx, shapes, dtypes, self.num_class, self.alpha, self.scale) 124 | -------------------------------------------------------------------------------- /src/megaface/README.md: -------------------------------------------------------------------------------- 1 | Please strictly follow these rules if you want to use our MegaFace noises list. 2 | 3 | * Please cite our paper and git repo if you want to use this list in your paper. 4 | * Please include the information like `We used the noises list proposed by InsightFace, at https://github.com/deepinsight/insightface/tree/master/src/megaface` if you want to submit the result to MegaFace challenge. 5 | * To be fair, if you want to submit MegaFace result, please ensure there's no training set overlaps with FaceScrub identities. You can do this by removing identities from your training set whose cosine similarity is larger than 0.4 with any FaceScrub identity by comparing their centre feature vectors. 6 | * If you find more overlaps noise, please open an issue at InsightFace. 7 | -------------------------------------------------------------------------------- /src/symbols/fmobilenetv2.py: -------------------------------------------------------------------------------- 1 | import mxnet as mx 2 | import mxnet.ndarray as nd 3 | import mxnet.gluon as gluon 4 | import mxnet.gluon.nn as nn 5 | import mxnet.autograd as ag 6 | import symbol_utils 7 | 8 | def ConvBlock(channels, kernel_size, strides): 9 | out = nn.HybridSequential() 10 | out.add( 11 | nn.Conv2D(channels, kernel_size, strides=strides, padding=1, use_bias=False), 12 | nn.BatchNorm(scale=True), 13 | nn.Activation('relu') 14 | ) 15 | return out 16 | 17 | def Conv1x1(channels, is_linear=False): 18 | out = nn.HybridSequential() 19 | out.add( 20 | nn.Conv2D(channels, 1, padding=0, use_bias=False), 21 | nn.BatchNorm(scale=True) 22 | ) 23 | if not is_linear: 24 | out.add(nn.Activation('relu')) 25 | return out 26 | 27 | def DWise(channels, stride): 28 | out = nn.HybridSequential() 29 | out.add( 30 | nn.Conv2D(channels, 3, strides=stride, padding=1, groups=channels, use_bias=False), 31 | nn.BatchNorm(scale=True), 32 | nn.Activation('relu') 33 | ) 34 | return out 35 | 36 | class InvertedResidual(nn.HybridBlock): 37 | def __init__(self, t, e, c, s, same_shape=True, **kwargs): 38 | super(InvertedResidual, self).__init__(**kwargs) 39 | self.same_shape = same_shape 40 | self.stride = s 41 | with self.name_scope(): 42 | self.bottleneck = nn.HybridSequential() 43 | self.bottleneck.add( 44 | Conv1x1(e*t), 45 | DWise(e*t, self.stride), 46 | Conv1x1(c, is_linear=True) 47 | ) 48 | if self.stride == 1 and not self.same_shape: 49 | self.conv_res = Conv1x1(c) 50 | def hybrid_forward(self, F, x): 51 | out = self.bottleneck(x) 52 | #if self.stride == 1 and self.same_shape: 53 | # out = F.elemwise_add(out, x) 54 | if self.stride == 1: 55 | if not self.same_shape: 56 | x = self.conv_res(x) 57 | out = F.elemwise_add(out, x) 58 | return out 59 | 60 | class MobilenetV2(nn.HybridBlock): 61 | def __init__(self, num_classes=1000, width_mult=1.0, **kwargs): 62 | super(MobilenetV2, self).__init__(**kwargs) 63 | 64 | self.w = width_mult 65 | 66 | self.cn = [int(x*self.w) for x in [32, 16, 24, 32, 64, 96, 160, 320]] 67 | 68 | def InvertedResidualSequence(t, cn_id, n, s): 69 | seq = nn.HybridSequential() 70 | seq.add(InvertedResidual(t, self.cn[cn_id-1], self.cn[cn_id], s, same_shape=False)) 71 | for _ in range(n-1): 72 | seq.add(InvertedResidual(t, self.cn[cn_id-1], self.cn[cn_id], 1)) 73 | return seq 74 | 75 | self.b0 = ConvBlock(self.cn[0], 3, 1) 76 | self.b1 = InvertedResidualSequence(1, 1, 1, 1) 77 | self.b2 = InvertedResidualSequence(6, 2, 2, 2) 78 | self.b3 = InvertedResidualSequence(6, 3, 3, 2) 79 | self.b4 = InvertedResidualSequence(6, 4, 4, 1) 80 | self.b5 = InvertedResidualSequence(6, 5, 3, 2) 81 | self.b6 = InvertedResidualSequence(6, 6, 3, 2) 82 | self.b7 = InvertedResidualSequence(6, 7, 1, 1) 83 | 84 | self.last_channels = int(1280*self.w) if self.w > 1.0 else 1280 85 | with self.name_scope(): 86 | self.features = nn.HybridSequential() 87 | with self.features.name_scope(): 88 | self.features.add(self.b0, self.b1, self.b2, self.b3, self.b4, self.b5, self.b6, self.b7) 89 | self.features.add(Conv1x1(self.last_channels)) 90 | #self.features.add(nn.GlobalAvgPool2D()) 91 | #self.features.add(nn.Flatten()) 92 | #self.output = nn.Dense(num_classes) 93 | def hybrid_forward(self, F, x): 94 | x = self.features(x) 95 | #x = self.output(x) 96 | return x 97 | 98 | def get_symbol(num_classes): 99 | net = MobilenetV2(num_classes, 1) 100 | data = mx.sym.Variable(name='data') 101 | data = data-127.5 102 | data = data*0.0078125 103 | body = net(data) 104 | fc1 = symbol_utils.get_fc1(body, num_classes, 'E') 105 | return fc1 106 | 107 | -------------------------------------------------------------------------------- /src/symbols/spherenet.py: -------------------------------------------------------------------------------- 1 | import mxnet as mx 2 | import numpy as np 3 | import math 4 | from mxnet.base import _Null 5 | 6 | def conv_main(data, units, filters, workspace): 7 | body = data 8 | for i in xrange(len(units)): 9 | f = filters[i] 10 | _weight = mx.symbol.Variable("conv%d_%d_weight"%(i+1, 1), lr_mult=1.0) 11 | _bias = mx.symbol.Variable("conv%d_%d_bias"%(i+1, 1), lr_mult=2.0, wd_mult=0.0) 12 | body = mx.sym.Convolution(data=body, weight = _weight, bias = _bias, num_filter=f, kernel=(3, 3), stride=(2,2), pad=(1, 1), 13 | name= "conv%d_%d"%(i+1, 1), workspace=workspace) 14 | 15 | body = mx.sym.LeakyReLU(data = body, act_type='prelu', name = "relu%d_%d" % (i+1, 1)) 16 | idx = 2 17 | for j in xrange(units[i]): 18 | _body = mx.sym.Convolution(data=body, no_bias=True, num_filter=f, kernel=(3, 3), stride=(1,1), pad=(1, 1), 19 | name= "conv%d_%d"%(i+1, idx), workspace=workspace) 20 | 21 | _body = mx.sym.LeakyReLU(data = _body, act_type='prelu', name = "relu%d_%d" % (i+1, idx)) 22 | idx+=1 23 | _body = mx.sym.Convolution(data=_body, no_bias=True, num_filter=f, kernel=(3, 3), stride=(1,1), pad=(1, 1), 24 | name= "conv%d_%d"%(i+1, idx), workspace=workspace) 25 | _body = mx.sym.LeakyReLU(data = _body, act_type='prelu', name = "relu%d_%d" % (i+1, idx)) 26 | idx+=1 27 | body = body+_body 28 | 29 | return body 30 | 31 | def get_symbol(num_classes, num_layers, conv_workspace=256, **kwargs): 32 | if num_layers==64: 33 | units = [3,8,16,3] 34 | filters = [64,128,256,512] 35 | elif num_layers==20: 36 | units = [1,2,4,1] 37 | filters = [64,128,256,512] 38 | #filters = [64, 256, 512, 1024] 39 | elif num_layers==36: 40 | units = [2,4,8,2] 41 | filters = [64,128,256,512] 42 | #filters = [64, 256, 512, 1024] 43 | elif num_layers==60: 44 | units = [3,8,14,3] 45 | filters = [64,128,256,512] 46 | elif num_layers==104: 47 | units = [3,8,36,3] 48 | filters = [64,128,256,512] 49 | #filters = [64, 256, 512, 1024] 50 | data = mx.symbol.Variable('data') 51 | data = data-127.5 52 | data = data*0.0078125 53 | body = conv_main(data = data, units = units, filters = filters, workspace = conv_workspace) 54 | 55 | _weight = mx.symbol.Variable("fc1_weight", lr_mult=1.0) 56 | _bias = mx.symbol.Variable("fc1_bias", lr_mult=2.0, wd_mult=0.0) 57 | fc1 = mx.sym.FullyConnected(data=body, weight=_weight, bias=_bias, num_hidden=num_classes, name='fc1') 58 | return fc1 59 | 60 | def init_weights(sym, data_shape_dict, num_layers): 61 | arg_name = sym.list_arguments() 62 | aux_name = sym.list_auxiliary_states() 63 | arg_shape, aaa, aux_shape = sym.infer_shape(**data_shape_dict) 64 | #print(data_shape_dict) 65 | #print(arg_name) 66 | #print(arg_shape) 67 | arg_params = {} 68 | aux_params = None 69 | #print(aaa) 70 | #print(aux_shape) 71 | arg_shape_dict = dict(zip(arg_name, arg_shape)) 72 | aux_shape_dict = dict(zip(aux_name, aux_shape)) 73 | #print(aux_shape) 74 | #print(aux_params) 75 | #print(arg_shape_dict) 76 | for k,v in arg_shape_dict.iteritems(): 77 | if k.startswith('conv') and k.endswith('_weight'): 78 | if not k.find('_1_')>=0: 79 | if num_layers<100: 80 | arg_params[k] = mx.random.normal(0, 0.01, shape=v) 81 | print('init', k) 82 | if k.endswith('_bias'): 83 | arg_params[k] = mx.nd.zeros(shape=v) 84 | print('init', k) 85 | return arg_params, aux_params 86 | 87 | -------------------------------------------------------------------------------- /src/train_myself.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source /etc/profile 3 | CUDA_VISIBLE_DEVICES='0' python3 -u train.py --pretrained ../models/glink-best/model,1 --network r100 --loss-type 4 --margin-m 0.5 --data-dir ../datasets/glink_aug_datasets_fan/ --prefix ../models/model-aug/model --target 'crop_ours_xiaoyi' 2>&1 > ../models/model-aug/aug.log & 4 | 5 | -------------------------------------------------------------------------------- /src/utils/benchmark.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | import os 5 | import sys 6 | import datetime 7 | import mxnet as mx 8 | from mxnet import ndarray as nd 9 | import random 10 | import argparse 11 | import cv2 12 | import time 13 | import sklearn 14 | from sklearn.decomposition import PCA 15 | from easydict import EasyDict as edict 16 | from sklearn.cluster import DBSCAN 17 | import numpy as np 18 | sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'common')) 19 | import face_image 20 | 21 | def ch_dev(arg_params, aux_params, ctx): 22 | new_args = dict() 23 | new_auxs = dict() 24 | for k, v in arg_params.items(): 25 | new_args[k] = v.as_in_context(ctx) 26 | for k, v in aux_params.items(): 27 | new_auxs[k] = v.as_in_context(ctx) 28 | return new_args, new_auxs 29 | 30 | 31 | def main(args): 32 | ctx = mx.gpu(args.gpu) 33 | args.ctx_num = 1 34 | prop = face_image.load_property(args.data) 35 | image_size = prop.image_size 36 | print('image_size', image_size) 37 | vec = args.model.split(',') 38 | prefix = vec[0] 39 | epoch = int(vec[1]) 40 | print('loading',prefix, epoch) 41 | sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch) 42 | arg_params, aux_params = ch_dev(arg_params, aux_params, ctx) 43 | all_layers = sym.get_internals() 44 | sym = all_layers['fc1_output'] 45 | #model = mx.mod.Module.load(prefix, epoch, context = ctx) 46 | model = mx.mod.Module(symbol=sym, context=ctx, label_names = None) 47 | #model.bind(data_shapes=[('data', (args.batch_size, 3, image_size[0], image_size[1]))], label_shapes=[('softmax_label', (args.batch_size,))]) 48 | model.bind(data_shapes=[('data', (args.batch_size, 3, image_size[0], image_size[1]))]) 49 | model.set_params(arg_params, aux_params) 50 | path_imgrec = os.path.join(args.data, 'train.rec') 51 | path_imgidx = os.path.join(args.data, 'train.idx') 52 | imgrec = mx.recordio.MXIndexedRecordIO(path_imgidx, path_imgrec, 'r') # pylint: disable=redefined-variable-type 53 | s = imgrec.read_idx(0) 54 | header, _ = mx.recordio.unpack(s) 55 | assert header.flag>0 56 | print('header0 label', header.label) 57 | header0 = (int(header.label[0]), int(header.label[1])) 58 | #assert(header.flag==1) 59 | imgidx = range(1, int(header.label[0])) 60 | stat = [] 61 | count = 0 62 | data = nd.zeros( (1 ,3, image_size[0], image_size[1]) ) 63 | label = nd.zeros( (1,) ) 64 | for idx in imgidx: 65 | if len(stat)%100==0: 66 | print('processing', len(stat)) 67 | s = imgrec.read_idx(idx) 68 | header, img = mx.recordio.unpack(s) 69 | img = mx.image.imdecode(img) 70 | img = nd.transpose(img, axes=(2, 0, 1)) 71 | data[0][:] = img 72 | #input_blob = np.expand_dims(img.asnumpy(), axis=0) 73 | #arg_params["data"] = mx.nd.array(input_blob, ctx) 74 | #arg_params["softmax_label"] = mx.nd.empty((1,), ctx) 75 | time_now = datetime.datetime.now() 76 | #exe = sym.bind(ctx, arg_params ,args_grad=None, grad_req="null", aux_states=aux_params) 77 | #exe.forward(is_train=False) 78 | #_embedding = exe.outputs[0].asnumpy().flatten() 79 | #db = mx.io.DataBatch(data=(data,), label=(label,)) 80 | db = mx.io.DataBatch(data=(data,)) 81 | model.forward(db, is_train=False) 82 | net_out = model.get_outputs()[0].asnumpy() 83 | time_now2 = datetime.datetime.now() 84 | diff = time_now2 - time_now 85 | stat.append(diff.total_seconds()) 86 | if len(stat)==args.param1: 87 | break 88 | stat = stat[10:] 89 | print('avg infer time', np.mean(stat)) 90 | 91 | if __name__ == '__main__': 92 | parser = argparse.ArgumentParser(description='do network benchmark') 93 | # general 94 | parser.add_argument('--gpu', default=0, type=int, help='') 95 | parser.add_argument('--data', default='', type=str, help='') 96 | parser.add_argument('--model', default='../model/softmax,50', help='path to load model.') 97 | parser.add_argument('--batch-size', default=1, type=int, help='') 98 | parser.add_argument('--param1', default=1010, type=int, help='') 99 | args = parser.parse_args() 100 | main(args) 101 | 102 | -------------------------------------------------------------------------------- /verification.sh: -------------------------------------------------------------------------------- 1 | python3 -u ./src/eval/verification.py --gpu 0 --model "./models/glint-gate-resnet152-crop_v4-quality-add_black/model,1" --data-dir './datasets' --target 'quality_crop','ours_orign' 2 | --------------------------------------------------------------------------------