├── .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 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/PRNet_Mask/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/PRNet_Mask/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SSH/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SSH/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TensorFace/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TensorFace/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
--------------------------------------------------------------------------------