Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +9 -0
- README.md +110 -3
- config.json +0 -0
- gallery_imgs/kobe.jpg +0 -0
- gallery_imgs/wade.jpg +0 -0
- insightface/__init__.py +21 -0
- insightface/__pycache__/__init__.cpython-310.pyc +0 -0
- insightface/__pycache__/__init__.cpython-311.pyc +0 -0
- insightface/__pycache__/__init__.cpython-313.pyc +0 -0
- insightface/app/__init__.py +2 -0
- insightface/app/__pycache__/__init__.cpython-310.pyc +0 -0
- insightface/app/__pycache__/__init__.cpython-311.pyc +0 -0
- insightface/app/__pycache__/__init__.cpython-313.pyc +0 -0
- insightface/app/__pycache__/common.cpython-310.pyc +0 -0
- insightface/app/__pycache__/common.cpython-311.pyc +0 -0
- insightface/app/__pycache__/common.cpython-313.pyc +0 -0
- insightface/app/__pycache__/face_analysis.cpython-310.pyc +0 -0
- insightface/app/__pycache__/face_analysis.cpython-311.pyc +0 -0
- insightface/app/__pycache__/face_analysis.cpython-313.pyc +0 -0
- insightface/app/__pycache__/mask_renderer.cpython-311.pyc +0 -0
- insightface/app/common.py +49 -0
- insightface/app/face_analysis.py +108 -0
- insightface/app/mask_renderer.py +232 -0
- insightface/commands/__init__.py +13 -0
- insightface/commands/insightface_cli.py +29 -0
- insightface/commands/model_download.py +36 -0
- insightface/commands/rec_add_mask_param.py +94 -0
- insightface/data/__init__.py +2 -0
- insightface/data/__pycache__/__init__.cpython-310.pyc +0 -0
- insightface/data/__pycache__/__init__.cpython-311.pyc +0 -0
- insightface/data/__pycache__/__init__.cpython-313.pyc +0 -0
- insightface/data/__pycache__/image.cpython-310.pyc +0 -0
- insightface/data/__pycache__/image.cpython-311.pyc +0 -0
- insightface/data/__pycache__/image.cpython-313.pyc +0 -0
- insightface/data/__pycache__/pickle_object.cpython-310.pyc +0 -0
- insightface/data/__pycache__/pickle_object.cpython-311.pyc +0 -0
- insightface/data/__pycache__/pickle_object.cpython-313.pyc +0 -0
- insightface/data/image.py +28 -0
- insightface/data/images/Tom_Hanks_54745.png +0 -0
- insightface/data/images/mask_black.jpg +0 -0
- insightface/data/images/mask_blue.jpg +0 -0
- insightface/data/images/mask_green.jpg +0 -0
- insightface/data/images/mask_white.jpg +0 -0
- insightface/data/images/t1.jpg +3 -0
- insightface/data/objects/meanshape_68.pkl +3 -0
- insightface/data/pickle_object.py +27 -0
- insightface/data/rec_builder.py +71 -0
- insightface/model_zoo/__init__.py +6 -0
- insightface/model_zoo/__pycache__/__init__.cpython-310.pyc +0 -0
- insightface/model_zoo/__pycache__/__init__.cpython-311.pyc +0 -0
.gitattributes
CHANGED
|
@@ -34,3 +34,12 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
*models/buffalo_l/det_10g.axmodel filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
*models/buffalo_l/det_10g.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
insightface/data/images/t1.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
models/buffalo_l/1k3d68.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
models/buffalo_l/2d106det.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
models/buffalo_l/genderage.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
models/buffalo_l/w600k_r50.axmodel filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
output/kobe0.jpg filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
output/ssd_horse.jpg filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
query/ssd_horse.jpg filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
query/wade2.jpg filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,3 +1,110 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Insightface
|
| 2 |
+
基于Insightface的人脸识别Pipeline,使用其buffalo_l系列模型中的人脸检测+定点模型,人脸属性模型,人脸特征提取模型实现人脸识别,支持650N系列平台的1v1人脸比对和1vN人脸识别。
|
| 3 |
+
|
| 4 |
+
支持芯片:
|
| 5 |
+
- AX650N
|
| 6 |
+
|
| 7 |
+
支持硬件
|
| 8 |
+
|
| 9 |
+
- [M4N-Dock(爱芯派Pro)](https://wiki.sipeed.com/hardware/zh/maixIV/m4ndock/m4ndock.html)
|
| 10 |
+
- [M.2 Accelerator card](https://axcl-docs.readthedocs.io/zh-cn/latest/doc_guide_hardware.html)
|
| 11 |
+
|
| 12 |
+
原始模型请参考
|
| 13 |
+
- [Insightface Github](https://github.com/deepinsight/insightface)
|
| 14 |
+
|
| 15 |
+
## 性能对比
|
| 16 |
+
|
| 17 |
+
| Models |input size | Latency (ms) | CMM Usage (MB) |
|
| 18 |
+
| --------------|------- | ---------------------- | -------------- |
|
| 19 |
+
| det_10g |640x640 |6.947 | 14.0 |
|
| 20 |
+
| genderage |96x96 |0.295 | 0.62 |
|
| 21 |
+
| w600k_r50 |112x112|3.993 | 44.0 |
|
| 22 |
+
|
| 23 |
+
## 模型转换
|
| 24 |
+
- 模型转换工具链[Pulsar2](https://huggingface.co/AXERA-TECH/Pulsar2)
|
| 25 |
+
- 转换文档[TODO]
|
| 26 |
+
|
| 27 |
+
## 环境准备
|
| 28 |
+
- NPU Python API: [pyaxengine](https://github.com/AXERA-TECH/pyaxengine)
|
| 29 |
+
|
| 30 |
+
安装需要的python库
|
| 31 |
+
```pip install -r requirements.txt```
|
| 32 |
+
|
| 33 |
+
## 运行(算力卡版本)
|
| 34 |
+
|
| 35 |
+
```bash
|
| 36 |
+
(insightface) axera@dell:~/insightface/ax$ python insightface_pipeline.py -h
|
| 37 |
+
[INFO] Available providers: ['AXCLRTExecutionProvider']
|
| 38 |
+
usage: insightface_pipeline.py [-h] [--model_path MODEL_PATH] [--type TYPE] [--gallery_path GALLERY_PATH] [--query_path QUERY_PATH] [--draw]
|
| 39 |
+
|
| 40 |
+
Face Recognition Pipeline Example
|
| 41 |
+
|
| 42 |
+
options:
|
| 43 |
+
-h, --help show this help message and exit
|
| 44 |
+
--model_path, -m MODEL_PATH
|
| 45 |
+
Path to the model directory
|
| 46 |
+
--type, -t TYPE Type of operation: 1: 1v1 compare, 2: 1vN recognize
|
| 47 |
+
--gallery_path, -g GALLERY_PATH
|
| 48 |
+
Path to the gallery image for image file
|
| 49 |
+
--query_path, -q QUERY_PATH
|
| 50 |
+
Path to the query image
|
| 51 |
+
--draw, -d Whether to draw results on the image
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
(insightface) axera@dell:~/insightface/ax$ python insightface_pipeline.py -g ./gallery_imgs/ -d -t 1
|
| 55 |
+
[INFO] Available providers: ['AXCLRTExecutionProvider']
|
| 56 |
+
ModelRouter ./models/buffalo_l/1k3d68.axmodel
|
| 57 |
+
[INFO] Using provider: AXCLRTExecutionProvider
|
| 58 |
+
[INFO] SOC Name: AX650N
|
| 59 |
+
[INFO] VNPU type: VNPUType.DISABLED
|
| 60 |
+
[INFO] Compiler version: 5.0-patch1-dirty 5cf5ab99-dirty
|
| 61 |
+
Applied providers: AXCLRTExecutionProvider, with options: None
|
| 62 |
+
model not recognized: ./models/buffalo_l/1k3d68.axmodel
|
| 63 |
+
ModelRouter ./models/buffalo_l/2d106det.axmodel
|
| 64 |
+
[INFO] Using provider: AXCLRTExecutionProvider
|
| 65 |
+
[INFO] SOC Name: AX650N
|
| 66 |
+
[INFO] VNPU type: VNPUType.DISABLED
|
| 67 |
+
[INFO] Compiler version: 5.0-patch1-dirty 5cf5ab99-dirty
|
| 68 |
+
Applied providers: AXCLRTExecutionProvider, with options: None
|
| 69 |
+
model not recognized: ./models/buffalo_l/2d106det.axmodel
|
| 70 |
+
ModelRouter ./models/buffalo_l/det_10g.axmodel
|
| 71 |
+
[INFO] Using provider: AXCLRTExecutionProvider
|
| 72 |
+
[INFO] SOC Name: AX650N
|
| 73 |
+
[INFO] VNPU type: VNPUType.DISABLED
|
| 74 |
+
[INFO] Compiler version: 5.0-patch1-dirty 5cf5ab99-dirty
|
| 75 |
+
Applied providers: AXCLRTExecutionProvider, with options: None
|
| 76 |
+
find model: ./models/buffalo_l/det_10g.axmodel detection [1, 640, 640, 3] 0.0 1.0
|
| 77 |
+
ModelRouter ./models/buffalo_l/genderage.axmodel
|
| 78 |
+
[INFO] Using provider: AXCLRTExecutionProvider
|
| 79 |
+
[INFO] SOC Name: AX650N
|
| 80 |
+
[INFO] VNPU type: VNPUType.DISABLED
|
| 81 |
+
[INFO] Compiler version: 5.0-patch1-dirty 5cf5ab99-dirty
|
| 82 |
+
Applied providers: AXCLRTExecutionProvider, with options: None
|
| 83 |
+
find model: ./models/buffalo_l/genderage.axmodel genderage [1, 96, 96, 3] 0.0 1.0
|
| 84 |
+
ModelRouter ./models/buffalo_l/w600k_r50.axmodel
|
| 85 |
+
[INFO] Using provider: AXCLRTExecutionProvider
|
| 86 |
+
[INFO] SOC Name: AX650N
|
| 87 |
+
[INFO] VNPU type: VNPUType.DISABLED
|
| 88 |
+
[INFO] Compiler version: 5.0-patch1-dirty 5cf5ab99-dirty
|
| 89 |
+
Applied providers: AXCLRTExecutionProvider, with options: None
|
| 90 |
+
find model: ./models/buffalo_l/w600k_r50.axmodel recognition [1, 112, 112, 3] 0.0 1.0
|
| 91 |
+
set det-size: (640, 640)
|
| 92 |
+
warning: det_size is already set in detection model, ignore
|
| 93 |
+
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:00<00:00, 12.49it/s]
|
| 94 |
+
特征库构建完成,包含以下人员: ['wade', 'kobe']
|
| 95 |
+
请输入查询图像路径 (输入 'exit' 退出):
|
| 96 |
+
./query/wade2.jpg
|
| 97 |
+
识别结果: wade, 相似度(0-1): 0.5860
|
| 98 |
+
结果已保存到 ./output/wade2.jpg
|
| 99 |
+
请输入查询图像路径 (输入 'exit' 退出):
|
| 100 |
+
./query/ssd_horse.jpg
|
| 101 |
+
识别结果: Unknown, 相似度(0-1): 0.0135
|
| 102 |
+
结果已保存到 ./output/ssd_horse.jpg
|
| 103 |
+
请输入查询图像路径 (输入 'exit' 退出):
|
| 104 |
+
exit
|
| 105 |
+
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
保存结果在 `./output` 目录下:
|
| 109 |
+

|
| 110 |
+

|
config.json
ADDED
|
File without changes
|
gallery_imgs/kobe.jpg
ADDED
|
gallery_imgs/wade.jpg
ADDED
|
insightface/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding: utf-8
|
| 2 |
+
# pylint: disable=wrong-import-position
|
| 3 |
+
"""InsightFace: A Face Analysis Toolkit."""
|
| 4 |
+
from __future__ import absolute_import
|
| 5 |
+
|
| 6 |
+
# try:
|
| 7 |
+
# #import mxnet as mx
|
| 8 |
+
# import onnxruntime
|
| 9 |
+
# except ImportError:
|
| 10 |
+
# raise ImportError(
|
| 11 |
+
# "Unable to import dependency onnxruntime. "
|
| 12 |
+
# )
|
| 13 |
+
|
| 14 |
+
__version__ = '0.7.3'
|
| 15 |
+
|
| 16 |
+
from . import model_zoo
|
| 17 |
+
from . import utils
|
| 18 |
+
from . import app
|
| 19 |
+
from . import data
|
| 20 |
+
from . import thirdparty
|
| 21 |
+
|
insightface/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (424 Bytes). View file
|
|
|
insightface/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (756 Bytes). View file
|
|
|
insightface/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (441 Bytes). View file
|
|
|
insightface/app/__init__.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .face_analysis import *
|
| 2 |
+
# from .mask_renderer import *
|
insightface/app/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (175 Bytes). View file
|
|
|
insightface/app/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (211 Bytes). View file
|
|
|
insightface/app/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (181 Bytes). View file
|
|
|
insightface/app/__pycache__/common.cpython-310.pyc
ADDED
|
Binary file (1.78 kB). View file
|
|
|
insightface/app/__pycache__/common.cpython-311.pyc
ADDED
|
Binary file (2.99 kB). View file
|
|
|
insightface/app/__pycache__/common.cpython-313.pyc
ADDED
|
Binary file (2.54 kB). View file
|
|
|
insightface/app/__pycache__/face_analysis.cpython-310.pyc
ADDED
|
Binary file (2.95 kB). View file
|
|
|
insightface/app/__pycache__/face_analysis.cpython-311.pyc
ADDED
|
Binary file (5.56 kB). View file
|
|
|
insightface/app/__pycache__/face_analysis.cpython-313.pyc
ADDED
|
Binary file (5.09 kB). View file
|
|
|
insightface/app/__pycache__/mask_renderer.cpython-311.pyc
ADDED
|
Binary file (14.3 kB). View file
|
|
|
insightface/app/common.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
from numpy.linalg import norm as l2norm
|
| 3 |
+
#from easydict import EasyDict
|
| 4 |
+
|
| 5 |
+
class Face(dict):
|
| 6 |
+
|
| 7 |
+
def __init__(self, d=None, **kwargs):
|
| 8 |
+
if d is None:
|
| 9 |
+
d = {}
|
| 10 |
+
if kwargs:
|
| 11 |
+
d.update(**kwargs)
|
| 12 |
+
for k, v in d.items():
|
| 13 |
+
setattr(self, k, v)
|
| 14 |
+
# Class attributes
|
| 15 |
+
#for k in self.__class__.__dict__.keys():
|
| 16 |
+
# if not (k.startswith('__') and k.endswith('__')) and not k in ('update', 'pop'):
|
| 17 |
+
# setattr(self, k, getattr(self, k))
|
| 18 |
+
|
| 19 |
+
def __setattr__(self, name, value):
|
| 20 |
+
if isinstance(value, (list, tuple)):
|
| 21 |
+
value = [self.__class__(x)
|
| 22 |
+
if isinstance(x, dict) else x for x in value]
|
| 23 |
+
elif isinstance(value, dict) and not isinstance(value, self.__class__):
|
| 24 |
+
value = self.__class__(value)
|
| 25 |
+
super(Face, self).__setattr__(name, value)
|
| 26 |
+
super(Face, self).__setitem__(name, value)
|
| 27 |
+
|
| 28 |
+
__setitem__ = __setattr__
|
| 29 |
+
|
| 30 |
+
def __getattr__(self, name):
|
| 31 |
+
return None
|
| 32 |
+
|
| 33 |
+
@property
|
| 34 |
+
def embedding_norm(self):
|
| 35 |
+
if self.embedding is None:
|
| 36 |
+
return None
|
| 37 |
+
return l2norm(self.embedding)
|
| 38 |
+
|
| 39 |
+
@property
|
| 40 |
+
def normed_embedding(self):
|
| 41 |
+
if self.embedding is None:
|
| 42 |
+
return None
|
| 43 |
+
return self.embedding / self.embedding_norm
|
| 44 |
+
|
| 45 |
+
@property
|
| 46 |
+
def sex(self):
|
| 47 |
+
if self.gender is None:
|
| 48 |
+
return None
|
| 49 |
+
return 'M' if self.gender==1 else 'F'
|
insightface/app/face_analysis.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
# @Organization : insightface.ai
|
| 3 |
+
# @Author : Jia Guo
|
| 4 |
+
# @Time : 2021-05-04
|
| 5 |
+
# @Function :
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
from __future__ import division
|
| 9 |
+
|
| 10 |
+
import glob
|
| 11 |
+
import os.path as osp
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
from numpy.linalg import norm
|
| 15 |
+
|
| 16 |
+
from ..model_zoo import model_zoo
|
| 17 |
+
from ..utils import DEFAULT_MP_NAME, ensure_available
|
| 18 |
+
from .common import Face
|
| 19 |
+
|
| 20 |
+
__all__ = ['FaceAnalysis']
|
| 21 |
+
|
| 22 |
+
class FaceAnalysis:
|
| 23 |
+
def __init__(self, name=DEFAULT_MP_NAME, root='./models/axmodel', allowed_modules=None, **kwargs):
|
| 24 |
+
|
| 25 |
+
self.models = {}
|
| 26 |
+
self.model_dir = root
|
| 27 |
+
onnx_files = glob.glob(osp.join(self.model_dir, '*.axmodel'))
|
| 28 |
+
onnx_files = sorted(onnx_files)
|
| 29 |
+
for onnx_file in onnx_files:
|
| 30 |
+
model = model_zoo.get_model(onnx_file, **kwargs)
|
| 31 |
+
if model is None:
|
| 32 |
+
print('model not recognized:', onnx_file)
|
| 33 |
+
elif allowed_modules is not None and model.taskname not in allowed_modules:
|
| 34 |
+
print('model ignore:', onnx_file, model.taskname)
|
| 35 |
+
del model
|
| 36 |
+
elif model.taskname not in self.models and (allowed_modules is None or model.taskname in allowed_modules):
|
| 37 |
+
print('find model:', onnx_file, model.taskname, model.input_shape, model.input_mean, model.input_std)
|
| 38 |
+
self.models[model.taskname] = model
|
| 39 |
+
else:
|
| 40 |
+
print('duplicated model task type, ignore:', onnx_file, model.taskname)
|
| 41 |
+
del model
|
| 42 |
+
assert 'detection' in self.models
|
| 43 |
+
self.det_model = self.models['detection']
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def prepare(self, ctx_id, det_thresh=0.5, det_size=(640, 640)):
|
| 47 |
+
self.det_thresh = det_thresh
|
| 48 |
+
assert det_size is not None
|
| 49 |
+
print('set det-size:', det_size)
|
| 50 |
+
self.det_size = det_size
|
| 51 |
+
for taskname, model in self.models.items():
|
| 52 |
+
if taskname=='detection':
|
| 53 |
+
model.prepare(ctx_id, input_size=det_size, det_thresh=det_thresh)
|
| 54 |
+
else:
|
| 55 |
+
model.prepare(ctx_id)
|
| 56 |
+
|
| 57 |
+
def get(self, img, max_num=0, det_metric='default'):
|
| 58 |
+
bboxes, kpss = self.det_model.detect(img,
|
| 59 |
+
max_num=max_num,
|
| 60 |
+
metric=det_metric)
|
| 61 |
+
if bboxes.shape[0] == 0:
|
| 62 |
+
return []
|
| 63 |
+
ret = []
|
| 64 |
+
for i in range(bboxes.shape[0]):
|
| 65 |
+
bbox = bboxes[i, 0:4]
|
| 66 |
+
det_score = bboxes[i, 4]
|
| 67 |
+
kps = None
|
| 68 |
+
if kpss is not None:
|
| 69 |
+
kps = kpss[i]
|
| 70 |
+
face = Face(bbox=bbox, kps=kps, det_score=det_score)
|
| 71 |
+
for taskname, model in self.models.items():
|
| 72 |
+
if taskname=='detection':
|
| 73 |
+
continue
|
| 74 |
+
model.get(img, face)
|
| 75 |
+
ret.append(face)
|
| 76 |
+
return ret
|
| 77 |
+
|
| 78 |
+
def draw_on(self, img, faces):
|
| 79 |
+
import cv2
|
| 80 |
+
dimg = img.copy()
|
| 81 |
+
for i in range(len(faces)):
|
| 82 |
+
face = faces[i]
|
| 83 |
+
box = face.bbox.astype(int)
|
| 84 |
+
color = (0, 0, 255)
|
| 85 |
+
cv2.rectangle(dimg, (box[0], box[1]), (box[2], box[3]), color, 2)
|
| 86 |
+
if face.kps is not None:
|
| 87 |
+
kps = face.kps.astype(int)
|
| 88 |
+
#print(landmark.shape)
|
| 89 |
+
for l in range(kps.shape[0]):
|
| 90 |
+
color = (0, 0, 255)
|
| 91 |
+
if l == 0 or l == 3:
|
| 92 |
+
color = (0, 255, 0)
|
| 93 |
+
cv2.circle(dimg, (kps[l][0], kps[l][1]), 1, color,
|
| 94 |
+
2)
|
| 95 |
+
if face.gender is not None and face.age is not None:
|
| 96 |
+
cv2.putText(dimg,'%s,%d'%(face.sex,face.age), (box[0]-1, box[1]-4),cv2.FONT_HERSHEY_COMPLEX,0.7,(0,255,0),1)
|
| 97 |
+
|
| 98 |
+
#for key, value in face.items():
|
| 99 |
+
# if key.startswith('landmark_3d'):
|
| 100 |
+
# print(key, value.shape)
|
| 101 |
+
# print(value[0:10,:])
|
| 102 |
+
# lmk = np.round(value).astype(int)
|
| 103 |
+
# for l in range(lmk.shape[0]):
|
| 104 |
+
# color = (255, 0, 0)
|
| 105 |
+
# cv2.circle(dimg, (lmk[l][0], lmk[l][1]), 1, color,
|
| 106 |
+
# 2)
|
| 107 |
+
return dimg
|
| 108 |
+
|
insightface/app/mask_renderer.py
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, sys, datetime
|
| 2 |
+
import numpy as np
|
| 3 |
+
import os.path as osp
|
| 4 |
+
import albumentations as A
|
| 5 |
+
from albumentations.core.transforms_interface import ImageOnlyTransform
|
| 6 |
+
from .face_analysis import FaceAnalysis
|
| 7 |
+
from ..utils import get_model_dir
|
| 8 |
+
from ..thirdparty import face3d
|
| 9 |
+
from ..data import get_image as ins_get_image
|
| 10 |
+
from ..utils import DEFAULT_MP_NAME
|
| 11 |
+
import cv2
|
| 12 |
+
|
| 13 |
+
class MaskRenderer:
|
| 14 |
+
def __init__(self, name=DEFAULT_MP_NAME, root='~/.insightface', insfa=None):
|
| 15 |
+
#if insfa is None, enter render_only mode
|
| 16 |
+
self.mp_name = name
|
| 17 |
+
self.root = root
|
| 18 |
+
self.insfa = insfa
|
| 19 |
+
model_dir = get_model_dir(name, root)
|
| 20 |
+
bfm_file = osp.join(model_dir, 'BFM.mat')
|
| 21 |
+
assert osp.exists(bfm_file), 'should contains BFM.mat in your model directory'
|
| 22 |
+
self.bfm = face3d.morphable_model.MorphabelModel(bfm_file)
|
| 23 |
+
self.index_ind = self.bfm.kpt_ind
|
| 24 |
+
bfm_uv_file = osp.join(model_dir, 'BFM_UV.mat')
|
| 25 |
+
assert osp.exists(bfm_uv_file), 'should contains BFM_UV.mat in your model directory'
|
| 26 |
+
uv_coords = face3d.morphable_model.load.load_uv_coords(bfm_uv_file)
|
| 27 |
+
self.uv_size = (224,224)
|
| 28 |
+
self.mask_stxr = 0.1
|
| 29 |
+
self.mask_styr = 0.33
|
| 30 |
+
self.mask_etxr = 0.9
|
| 31 |
+
self.mask_etyr = 0.7
|
| 32 |
+
self.tex_h , self.tex_w, self.tex_c = self.uv_size[1] , self.uv_size[0],3
|
| 33 |
+
texcoord = np.zeros_like(uv_coords)
|
| 34 |
+
texcoord[:, 0] = uv_coords[:, 0] * (self.tex_h - 1)
|
| 35 |
+
texcoord[:, 1] = uv_coords[:, 1] * (self.tex_w - 1)
|
| 36 |
+
texcoord[:, 1] = self.tex_w - texcoord[:, 1] - 1
|
| 37 |
+
self.texcoord = np.hstack((texcoord, np.zeros((texcoord.shape[0], 1))))
|
| 38 |
+
self.X_ind = self.bfm.kpt_ind
|
| 39 |
+
self.mask_image_names = ['mask_white', 'mask_blue', 'mask_black', 'mask_green']
|
| 40 |
+
self.mask_aug_probs = [0.4, 0.4, 0.1, 0.1]
|
| 41 |
+
#self.mask_images = []
|
| 42 |
+
#self.mask_images_rgb = []
|
| 43 |
+
#for image_name in mask_image_names:
|
| 44 |
+
# mask_image = ins_get_image(image_name)
|
| 45 |
+
# self.mask_images.append(mask_image)
|
| 46 |
+
# mask_image_rgb = mask_image[:,:,::-1]
|
| 47 |
+
# self.mask_images_rgb.append(mask_image_rgb)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def prepare(self, ctx_id=0, det_thresh=0.5, det_size=(128, 128)):
|
| 51 |
+
self.pre_ctx_id = ctx_id
|
| 52 |
+
self.pre_det_thresh = det_thresh
|
| 53 |
+
self.pre_det_size = det_size
|
| 54 |
+
|
| 55 |
+
def transform(self, shape3D, R):
|
| 56 |
+
s = 1.0
|
| 57 |
+
shape3D[:2, :] = shape3D[:2, :]
|
| 58 |
+
shape3D = s * np.dot(R, shape3D)
|
| 59 |
+
return shape3D
|
| 60 |
+
|
| 61 |
+
def preprocess(self, vertices, w, h):
|
| 62 |
+
R1 = face3d.mesh.transform.angle2matrix([0, 180, 180])
|
| 63 |
+
t = np.array([-w // 2, -h // 2, 0])
|
| 64 |
+
vertices = vertices.T
|
| 65 |
+
vertices += t
|
| 66 |
+
vertices = self.transform(vertices.T, R1).T
|
| 67 |
+
return vertices
|
| 68 |
+
|
| 69 |
+
def project_to_2d(self,vertices,s,angles,t):
|
| 70 |
+
transformed_vertices = self.bfm.transform(vertices, s, angles, t)
|
| 71 |
+
projected_vertices = transformed_vertices.copy() # using stantard camera & orth projection
|
| 72 |
+
return projected_vertices[self.bfm.kpt_ind, :2]
|
| 73 |
+
|
| 74 |
+
def params_to_vertices(self,params , H , W):
|
| 75 |
+
fitted_sp, fitted_ep, fitted_s, fitted_angles, fitted_t = params
|
| 76 |
+
fitted_vertices = self.bfm.generate_vertices(fitted_sp, fitted_ep)
|
| 77 |
+
transformed_vertices = self.bfm.transform(fitted_vertices, fitted_s, fitted_angles,
|
| 78 |
+
fitted_t)
|
| 79 |
+
transformed_vertices = self.preprocess(transformed_vertices.T, W, H)
|
| 80 |
+
image_vertices = face3d.mesh.transform.to_image(transformed_vertices, H, W)
|
| 81 |
+
return image_vertices
|
| 82 |
+
|
| 83 |
+
def draw_lmk(self, face_image):
|
| 84 |
+
faces = self.insfa.get(face_image, max_num=1)
|
| 85 |
+
if len(faces)==0:
|
| 86 |
+
return face_image
|
| 87 |
+
return self.insfa.draw_on(face_image, faces)
|
| 88 |
+
|
| 89 |
+
def build_params(self, face_image):
|
| 90 |
+
#landmark = self.if3d68_handler.get(face_image)
|
| 91 |
+
#if landmark is None:
|
| 92 |
+
# return None #face not found
|
| 93 |
+
if self.insfa is None:
|
| 94 |
+
self.insfa = FaceAnalysis(name=self.mp_name, root=self.root, allowed_modules=['detection', 'landmark_3d_68'])
|
| 95 |
+
self.insfa.prepare(ctx_id=self.pre_ctx_id, det_thresh=self.pre_det_thresh, det_size=self.pre_det_size)
|
| 96 |
+
|
| 97 |
+
faces = self.insfa.get(face_image, max_num=1)
|
| 98 |
+
if len(faces)==0:
|
| 99 |
+
return None
|
| 100 |
+
landmark = faces[0].landmark_3d_68[:,:2]
|
| 101 |
+
fitted_sp, fitted_ep, fitted_s, fitted_angles, fitted_t = self.bfm.fit(landmark, self.X_ind, max_iter = 3)
|
| 102 |
+
return [fitted_sp, fitted_ep, fitted_s, fitted_angles, fitted_t]
|
| 103 |
+
|
| 104 |
+
def generate_mask_uv(self,mask, positions):
|
| 105 |
+
uv_size = (self.uv_size[1], self.uv_size[0], 3)
|
| 106 |
+
h, w, c = uv_size
|
| 107 |
+
uv = np.zeros(shape=(self.uv_size[1],self.uv_size[0], 3), dtype=np.uint8)
|
| 108 |
+
stxr, styr = positions[0], positions[1]
|
| 109 |
+
etxr, etyr = positions[2], positions[3]
|
| 110 |
+
stx, sty = int(w * stxr), int(h * styr)
|
| 111 |
+
etx, ety = int(w * etxr), int(h * etyr)
|
| 112 |
+
height = ety - sty
|
| 113 |
+
width = etx - stx
|
| 114 |
+
mask = cv2.resize(mask, (width, height))
|
| 115 |
+
uv[sty:ety, stx:etx] = mask
|
| 116 |
+
return uv
|
| 117 |
+
|
| 118 |
+
def render_mask(self,face_image, mask_image, params, input_is_rgb=False, auto_blend = True, positions=[0.1, 0.33, 0.9, 0.7]):
|
| 119 |
+
if isinstance(mask_image, str):
|
| 120 |
+
to_rgb = True if input_is_rgb else False
|
| 121 |
+
mask_image = ins_get_image(mask_image, to_rgb=to_rgb)
|
| 122 |
+
uv_mask_image = self.generate_mask_uv(mask_image, positions)
|
| 123 |
+
h,w,c = face_image.shape
|
| 124 |
+
image_vertices = self.params_to_vertices(params ,h,w)
|
| 125 |
+
output = (1-face3d.mesh.render.render_texture(image_vertices, self.bfm.full_triangles , uv_mask_image, self.texcoord, self.bfm.full_triangles, h , w ))*255
|
| 126 |
+
output = output.astype(np.uint8)
|
| 127 |
+
if auto_blend:
|
| 128 |
+
mask_bd = (output==255).astype(np.uint8)
|
| 129 |
+
final = face_image*mask_bd + (1-mask_bd)*output
|
| 130 |
+
return final
|
| 131 |
+
return output
|
| 132 |
+
|
| 133 |
+
#def mask_augmentation(self, face_image, label, input_is_rgb=False, p=0.1):
|
| 134 |
+
# if np.random.random()<p:
|
| 135 |
+
# assert isinstance(label, (list, np.ndarray)), 'make sure the rec dataset includes mask params'
|
| 136 |
+
# assert len(label)==237 or len(lable)==235, 'make sure the rec dataset includes mask params'
|
| 137 |
+
# if len(label)==237:
|
| 138 |
+
# if label[1]<0.0: #invalid label for mask aug
|
| 139 |
+
# return face_image
|
| 140 |
+
# label = label[2:]
|
| 141 |
+
# params = self.decode_params(label)
|
| 142 |
+
# mask_image_name = np.random.choice(self.mask_image_names, p=self.mask_aug_probs)
|
| 143 |
+
# pos = np.random.uniform(0.33, 0.5)
|
| 144 |
+
# face_image = self.render_mask(face_image, mask_image_name, params, input_is_rgb=input_is_rgb, positions=[0.1, pos, 0.9, 0.7])
|
| 145 |
+
# return face_image
|
| 146 |
+
|
| 147 |
+
@staticmethod
|
| 148 |
+
def encode_params(params):
|
| 149 |
+
p0 = list(params[0])
|
| 150 |
+
p1 = list(params[1])
|
| 151 |
+
p2 = [float(params[2])]
|
| 152 |
+
p3 = list(params[3])
|
| 153 |
+
p4 = list(params[4])
|
| 154 |
+
return p0+p1+p2+p3+p4
|
| 155 |
+
|
| 156 |
+
@staticmethod
|
| 157 |
+
def decode_params(params):
|
| 158 |
+
p0 = params[0:199]
|
| 159 |
+
p0 = np.array(p0, dtype=np.float32).reshape( (-1, 1))
|
| 160 |
+
p1 = params[199:228]
|
| 161 |
+
p1 = np.array(p1, dtype=np.float32).reshape( (-1, 1))
|
| 162 |
+
p2 = params[228]
|
| 163 |
+
p3 = tuple(params[229:232])
|
| 164 |
+
p4 = params[232:235]
|
| 165 |
+
p4 = np.array(p4, dtype=np.float32).reshape( (-1, 1))
|
| 166 |
+
return p0, p1, p2, p3, p4
|
| 167 |
+
|
| 168 |
+
class MaskAugmentation(ImageOnlyTransform):
|
| 169 |
+
|
| 170 |
+
def __init__(
|
| 171 |
+
self,
|
| 172 |
+
mask_names=['mask_white', 'mask_blue', 'mask_black', 'mask_green'],
|
| 173 |
+
mask_probs=[0.4,0.4,0.1,0.1],
|
| 174 |
+
h_low = 0.33,
|
| 175 |
+
h_high = 0.35,
|
| 176 |
+
always_apply=False,
|
| 177 |
+
p=1.0,
|
| 178 |
+
):
|
| 179 |
+
super(MaskAugmentation, self).__init__(always_apply, p)
|
| 180 |
+
self.renderer = MaskRenderer()
|
| 181 |
+
assert len(mask_names)>0
|
| 182 |
+
assert len(mask_names)==len(mask_probs)
|
| 183 |
+
self.mask_names = mask_names
|
| 184 |
+
self.mask_probs = mask_probs
|
| 185 |
+
self.h_low = h_low
|
| 186 |
+
self.h_high = h_high
|
| 187 |
+
#self.hlabel = None
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def apply(self, image, hlabel, mask_name, h_pos, **params):
|
| 191 |
+
#print(params.keys())
|
| 192 |
+
#hlabel = params.get('hlabel')
|
| 193 |
+
assert len(hlabel)==237 or len(hlabel)==235, 'make sure the rec dataset includes mask params'
|
| 194 |
+
if len(hlabel)==237:
|
| 195 |
+
if hlabel[1]<0.0:
|
| 196 |
+
return image
|
| 197 |
+
hlabel = hlabel[2:]
|
| 198 |
+
#print(len(hlabel))
|
| 199 |
+
mask_params = self.renderer.decode_params(hlabel)
|
| 200 |
+
image = self.renderer.render_mask(image, mask_name, mask_params, input_is_rgb=True, positions=[0.1, h_pos, 0.9, 0.7])
|
| 201 |
+
return image
|
| 202 |
+
|
| 203 |
+
@property
|
| 204 |
+
def targets_as_params(self):
|
| 205 |
+
return ["image", "hlabel"]
|
| 206 |
+
|
| 207 |
+
def get_params_dependent_on_targets(self, params):
|
| 208 |
+
hlabel = params['hlabel']
|
| 209 |
+
mask_name = np.random.choice(self.mask_names, p=self.mask_probs)
|
| 210 |
+
h_pos = np.random.uniform(self.h_low, self.h_high)
|
| 211 |
+
return {'hlabel': hlabel, 'mask_name': mask_name, 'h_pos': h_pos}
|
| 212 |
+
|
| 213 |
+
def get_transform_init_args_names(self):
|
| 214 |
+
#return ("hlabel", 'mask_names', 'mask_probs', 'h_low', 'h_high')
|
| 215 |
+
return ('mask_names', 'mask_probs', 'h_low', 'h_high')
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
if __name__ == "__main__":
|
| 219 |
+
tool = MaskRenderer('antelope')
|
| 220 |
+
tool.prepare(det_size=(128,128))
|
| 221 |
+
image = cv2.imread("Tom_Hanks_54745.png")
|
| 222 |
+
params = tool.build_params(image)
|
| 223 |
+
#out = tool.draw_lmk(image)
|
| 224 |
+
#cv2.imwrite('output_lmk.jpg', out)
|
| 225 |
+
#mask_image = cv2.imread("masks/mask1.jpg")
|
| 226 |
+
#mask_image = cv2.imread("masks/black-mask.png")
|
| 227 |
+
#mask_image = cv2.imread("masks/mask2.jpg")
|
| 228 |
+
mask_out = tool.render_mask(image, 'mask_blue', params)# use single thread to test the time cost
|
| 229 |
+
|
| 230 |
+
cv2.imwrite('output_mask.jpg', mask_out)
|
| 231 |
+
|
| 232 |
+
|
insightface/commands/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from abc import ABC, abstractmethod
|
| 2 |
+
from argparse import ArgumentParser
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class BaseInsightFaceCLICommand(ABC):
|
| 6 |
+
@staticmethod
|
| 7 |
+
@abstractmethod
|
| 8 |
+
def register_subcommand(parser: ArgumentParser):
|
| 9 |
+
raise NotImplementedError()
|
| 10 |
+
|
| 11 |
+
@abstractmethod
|
| 12 |
+
def run(self):
|
| 13 |
+
raise NotImplementedError()
|
insightface/commands/insightface_cli.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python
|
| 2 |
+
|
| 3 |
+
from argparse import ArgumentParser
|
| 4 |
+
|
| 5 |
+
from .model_download import ModelDownloadCommand
|
| 6 |
+
from .rec_add_mask_param import RecAddMaskParamCommand
|
| 7 |
+
|
| 8 |
+
def main():
|
| 9 |
+
parser = ArgumentParser("InsightFace CLI tool", usage="insightface-cli <command> [<args>]")
|
| 10 |
+
commands_parser = parser.add_subparsers(help="insightface-cli command-line helpers")
|
| 11 |
+
|
| 12 |
+
# Register commands
|
| 13 |
+
ModelDownloadCommand.register_subcommand(commands_parser)
|
| 14 |
+
RecAddMaskParamCommand.register_subcommand(commands_parser)
|
| 15 |
+
|
| 16 |
+
args = parser.parse_args()
|
| 17 |
+
|
| 18 |
+
if not hasattr(args, "func"):
|
| 19 |
+
parser.print_help()
|
| 20 |
+
exit(1)
|
| 21 |
+
|
| 22 |
+
# Run
|
| 23 |
+
service = args.func(args)
|
| 24 |
+
service.run()
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
if __name__ == "__main__":
|
| 28 |
+
main()
|
| 29 |
+
|
insightface/commands/model_download.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from argparse import ArgumentParser
|
| 2 |
+
|
| 3 |
+
from . import BaseInsightFaceCLICommand
|
| 4 |
+
import os
|
| 5 |
+
import os.path as osp
|
| 6 |
+
import zipfile
|
| 7 |
+
import glob
|
| 8 |
+
from ..utils import download
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def model_download_command_factory(args):
|
| 12 |
+
return ModelDownloadCommand(args.model, args.root, args.force)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class ModelDownloadCommand(BaseInsightFaceCLICommand):
|
| 16 |
+
#_url_format = '{repo_url}models/{file_name}.zip'
|
| 17 |
+
@staticmethod
|
| 18 |
+
def register_subcommand(parser: ArgumentParser):
|
| 19 |
+
download_parser = parser.add_parser("model.download")
|
| 20 |
+
download_parser.add_argument(
|
| 21 |
+
"--root", type=str, default='~/.insightface', help="Path to location to store the models"
|
| 22 |
+
)
|
| 23 |
+
download_parser.add_argument(
|
| 24 |
+
"--force", action="store_true", help="Force the model to be download even if already in root-dir"
|
| 25 |
+
)
|
| 26 |
+
download_parser.add_argument("model", type=str, help="Name of the model to download")
|
| 27 |
+
download_parser.set_defaults(func=model_download_command_factory)
|
| 28 |
+
|
| 29 |
+
def __init__(self, model: str, root: str, force: bool):
|
| 30 |
+
self._model = model
|
| 31 |
+
self._root = root
|
| 32 |
+
self._force = force
|
| 33 |
+
|
| 34 |
+
def run(self):
|
| 35 |
+
download('models', self._model, force=self._force, root=self._root)
|
| 36 |
+
|
insightface/commands/rec_add_mask_param.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import numbers
|
| 3 |
+
import os
|
| 4 |
+
from argparse import ArgumentParser, Namespace
|
| 5 |
+
|
| 6 |
+
import mxnet as mx
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
from ..app import MaskRenderer
|
| 10 |
+
from ..data.rec_builder import RecBuilder
|
| 11 |
+
from . import BaseInsightFaceCLICommand
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def rec_add_mask_param_command_factory(args: Namespace):
|
| 15 |
+
|
| 16 |
+
return RecAddMaskParamCommand(
|
| 17 |
+
args.input, args.output
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class RecAddMaskParamCommand(BaseInsightFaceCLICommand):
|
| 22 |
+
@staticmethod
|
| 23 |
+
def register_subcommand(parser: ArgumentParser):
|
| 24 |
+
_parser = parser.add_parser("rec.addmaskparam")
|
| 25 |
+
_parser.add_argument("input", type=str, help="input rec")
|
| 26 |
+
_parser.add_argument("output", type=str, help="output rec, with mask param")
|
| 27 |
+
_parser.set_defaults(func=rec_add_mask_param_command_factory)
|
| 28 |
+
|
| 29 |
+
def __init__(
|
| 30 |
+
self,
|
| 31 |
+
input: str,
|
| 32 |
+
output: str,
|
| 33 |
+
):
|
| 34 |
+
self._input = input
|
| 35 |
+
self._output = output
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def run(self):
|
| 39 |
+
tool = MaskRenderer()
|
| 40 |
+
tool.prepare(ctx_id=0, det_size=(128,128))
|
| 41 |
+
root_dir = self._input
|
| 42 |
+
path_imgrec = os.path.join(root_dir, 'train.rec')
|
| 43 |
+
path_imgidx = os.path.join(root_dir, 'train.idx')
|
| 44 |
+
imgrec = mx.recordio.MXIndexedRecordIO(path_imgidx, path_imgrec, 'r')
|
| 45 |
+
save_path = self._output
|
| 46 |
+
wrec=RecBuilder(path=save_path)
|
| 47 |
+
s = imgrec.read_idx(0)
|
| 48 |
+
header, _ = mx.recordio.unpack(s)
|
| 49 |
+
if header.flag > 0:
|
| 50 |
+
if len(header.label)==2:
|
| 51 |
+
imgidx = np.array(range(1, int(header.label[0])))
|
| 52 |
+
else:
|
| 53 |
+
imgidx = np.array(list(self.imgrec.keys))
|
| 54 |
+
else:
|
| 55 |
+
imgidx = np.array(list(self.imgrec.keys))
|
| 56 |
+
stat = [0, 0]
|
| 57 |
+
print('total:', len(imgidx))
|
| 58 |
+
for iid, idx in enumerate(imgidx):
|
| 59 |
+
#if iid==500000:
|
| 60 |
+
# break
|
| 61 |
+
if iid%1000==0:
|
| 62 |
+
print('processing:', iid)
|
| 63 |
+
s = imgrec.read_idx(idx)
|
| 64 |
+
header, img = mx.recordio.unpack(s)
|
| 65 |
+
label = header.label
|
| 66 |
+
if not isinstance(label, numbers.Number):
|
| 67 |
+
label = label[0]
|
| 68 |
+
sample = mx.image.imdecode(img).asnumpy()
|
| 69 |
+
bgr = sample[:,:,::-1]
|
| 70 |
+
params = tool.build_params(bgr)
|
| 71 |
+
#if iid<10:
|
| 72 |
+
# mask_out = tool.render_mask(bgr, 'mask_blue', params)
|
| 73 |
+
# cv2.imwrite('maskout_%d.jpg'%iid, mask_out)
|
| 74 |
+
stat[1] += 1
|
| 75 |
+
if params is None:
|
| 76 |
+
wlabel = [label] + [-1.0]*236
|
| 77 |
+
stat[0] += 1
|
| 78 |
+
else:
|
| 79 |
+
#print(0, params[0].shape, params[0].dtype)
|
| 80 |
+
#print(1, params[1].shape, params[1].dtype)
|
| 81 |
+
#print(2, params[2])
|
| 82 |
+
#print(3, len(params[3]), params[3][0].__class__)
|
| 83 |
+
#print(4, params[4].shape, params[4].dtype)
|
| 84 |
+
mask_label = tool.encode_params(params)
|
| 85 |
+
wlabel = [label, 0.0]+mask_label # 237 including idlabel, total mask params size is 235
|
| 86 |
+
if iid==0:
|
| 87 |
+
print('param size:', len(mask_label), len(wlabel), label)
|
| 88 |
+
assert len(wlabel)==237
|
| 89 |
+
wrec.add_image(img, wlabel)
|
| 90 |
+
#print(len(params))
|
| 91 |
+
|
| 92 |
+
wrec.close()
|
| 93 |
+
print('finished on', self._output, ', failed:', stat[0])
|
| 94 |
+
|
insightface/data/__init__.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .image import get_image
|
| 2 |
+
from .pickle_object import get_object
|
insightface/data/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (233 Bytes). View file
|
|
|
insightface/data/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (291 Bytes). View file
|
|
|
insightface/data/__pycache__/__init__.cpython-313.pyc
ADDED
|
Binary file (238 Bytes). View file
|
|
|
insightface/data/__pycache__/image.cpython-310.pyc
ADDED
|
Binary file (961 Bytes). View file
|
|
|
insightface/data/__pycache__/image.cpython-311.pyc
ADDED
|
Binary file (1.63 kB). View file
|
|
|
insightface/data/__pycache__/image.cpython-313.pyc
ADDED
|
Binary file (1.56 kB). View file
|
|
|
insightface/data/__pycache__/pickle_object.cpython-310.pyc
ADDED
|
Binary file (766 Bytes). View file
|
|
|
insightface/data/__pycache__/pickle_object.cpython-311.pyc
ADDED
|
Binary file (1.47 kB). View file
|
|
|
insightface/data/__pycache__/pickle_object.cpython-313.pyc
ADDED
|
Binary file (1.3 kB). View file
|
|
|
insightface/data/image.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cv2
|
| 2 |
+
import os
|
| 3 |
+
import os.path as osp
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
class ImageCache:
|
| 7 |
+
data = {}
|
| 8 |
+
|
| 9 |
+
def get_image(name, to_rgb=False, use_cache=True):
|
| 10 |
+
key = (name, to_rgb)
|
| 11 |
+
if key in ImageCache.data:
|
| 12 |
+
return ImageCache.data[key]
|
| 13 |
+
images_dir = osp.join(Path(__file__).parent.absolute(), 'images')
|
| 14 |
+
ext_names = ['.jpg', '.png', '.jpeg']
|
| 15 |
+
image_file = None
|
| 16 |
+
for ext_name in ext_names:
|
| 17 |
+
_image_file = osp.join(images_dir, "%s%s"%(name, ext_name))
|
| 18 |
+
if osp.exists(_image_file):
|
| 19 |
+
image_file = _image_file
|
| 20 |
+
break
|
| 21 |
+
assert image_file is not None, '%s not found'%name
|
| 22 |
+
img = cv2.imread(image_file)
|
| 23 |
+
if to_rgb:
|
| 24 |
+
img = img[:,:,::-1]
|
| 25 |
+
if use_cache:
|
| 26 |
+
ImageCache.data[key] = img
|
| 27 |
+
return img
|
| 28 |
+
|
insightface/data/images/Tom_Hanks_54745.png
ADDED
|
insightface/data/images/mask_black.jpg
ADDED
|
insightface/data/images/mask_blue.jpg
ADDED
|
insightface/data/images/mask_green.jpg
ADDED
|
insightface/data/images/mask_white.jpg
ADDED
|
insightface/data/images/t1.jpg
ADDED
|
Git LFS Details
|
insightface/data/objects/meanshape_68.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:39ffecf84ba73f0d0d7e49380833ba88713c9fcdec51df4f7ac45a48b8f4cc51
|
| 3 |
+
size 974
|
insightface/data/pickle_object.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import os
|
| 3 |
+
import os.path as osp
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import pickle
|
| 6 |
+
|
| 7 |
+
def get_object(name):
|
| 8 |
+
if getattr(sys, 'frozen', False):
|
| 9 |
+
base_dir = sys._MEIPASS
|
| 10 |
+
else:
|
| 11 |
+
base_dir = Path(__file__).parent.absolute()
|
| 12 |
+
|
| 13 |
+
objects_dir = osp.join(base_dir, 'objects')
|
| 14 |
+
|
| 15 |
+
if not name.endswith('.pkl'):
|
| 16 |
+
name = name + ".pkl"
|
| 17 |
+
|
| 18 |
+
filepath = osp.join(objects_dir, name)
|
| 19 |
+
|
| 20 |
+
if not osp.exists(filepath):
|
| 21 |
+
print(f"[Error] File not found: {filepath}")
|
| 22 |
+
return None
|
| 23 |
+
|
| 24 |
+
with open(filepath, 'rb') as f:
|
| 25 |
+
obj = pickle.load(f)
|
| 26 |
+
|
| 27 |
+
return obj
|
insightface/data/rec_builder.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pickle
|
| 2 |
+
import numpy as np
|
| 3 |
+
import os
|
| 4 |
+
import os.path as osp
|
| 5 |
+
import sys
|
| 6 |
+
import mxnet as mx
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class RecBuilder():
|
| 10 |
+
def __init__(self, path, image_size=(112, 112)):
|
| 11 |
+
self.path = path
|
| 12 |
+
self.image_size = image_size
|
| 13 |
+
self.widx = 0
|
| 14 |
+
self.wlabel = 0
|
| 15 |
+
self.max_label = -1
|
| 16 |
+
assert not osp.exists(path), '%s exists' % path
|
| 17 |
+
os.makedirs(path)
|
| 18 |
+
self.writer = mx.recordio.MXIndexedRecordIO(os.path.join(path, 'train.idx'),
|
| 19 |
+
os.path.join(path, 'train.rec'),
|
| 20 |
+
'w')
|
| 21 |
+
self.meta = []
|
| 22 |
+
|
| 23 |
+
def add(self, imgs):
|
| 24 |
+
#!!! img should be BGR!!!!
|
| 25 |
+
#assert label >= 0
|
| 26 |
+
#assert label > self.last_label
|
| 27 |
+
assert len(imgs) > 0
|
| 28 |
+
label = self.wlabel
|
| 29 |
+
for img in imgs:
|
| 30 |
+
idx = self.widx
|
| 31 |
+
image_meta = {'image_index': idx, 'image_classes': [label]}
|
| 32 |
+
header = mx.recordio.IRHeader(0, label, idx, 0)
|
| 33 |
+
if isinstance(img, np.ndarray):
|
| 34 |
+
s = mx.recordio.pack_img(header,img,quality=95,img_fmt='.jpg')
|
| 35 |
+
else:
|
| 36 |
+
s = mx.recordio.pack(header, img)
|
| 37 |
+
self.writer.write_idx(idx, s)
|
| 38 |
+
self.meta.append(image_meta)
|
| 39 |
+
self.widx += 1
|
| 40 |
+
self.max_label = label
|
| 41 |
+
self.wlabel += 1
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def add_image(self, img, label):
|
| 45 |
+
#!!! img should be BGR!!!!
|
| 46 |
+
#assert label >= 0
|
| 47 |
+
#assert label > self.last_label
|
| 48 |
+
idx = self.widx
|
| 49 |
+
header = mx.recordio.IRHeader(0, label, idx, 0)
|
| 50 |
+
if isinstance(label, list):
|
| 51 |
+
idlabel = label[0]
|
| 52 |
+
else:
|
| 53 |
+
idlabel = label
|
| 54 |
+
image_meta = {'image_index': idx, 'image_classes': [idlabel]}
|
| 55 |
+
if isinstance(img, np.ndarray):
|
| 56 |
+
s = mx.recordio.pack_img(header,img,quality=95,img_fmt='.jpg')
|
| 57 |
+
else:
|
| 58 |
+
s = mx.recordio.pack(header, img)
|
| 59 |
+
self.writer.write_idx(idx, s)
|
| 60 |
+
self.meta.append(image_meta)
|
| 61 |
+
self.widx += 1
|
| 62 |
+
self.max_label = max(self.max_label, idlabel)
|
| 63 |
+
|
| 64 |
+
def close(self):
|
| 65 |
+
with open(osp.join(self.path, 'train.meta'), 'wb') as pfile:
|
| 66 |
+
pickle.dump(self.meta, pfile, protocol=pickle.HIGHEST_PROTOCOL)
|
| 67 |
+
print('stat:', self.widx, self.wlabel)
|
| 68 |
+
with open(os.path.join(self.path, 'property'), 'w') as f:
|
| 69 |
+
f.write("%d,%d,%d\n" % (self.max_label+1, self.image_size[0], self.image_size[1]))
|
| 70 |
+
f.write("%d\n" % (self.widx))
|
| 71 |
+
|
insightface/model_zoo/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .model_zoo import get_model
|
| 2 |
+
from .arcface_onnx import ArcFaceONNX
|
| 3 |
+
from .retinaface import RetinaFace
|
| 4 |
+
# from .scrfd import SCRFD
|
| 5 |
+
from .landmark import Landmark
|
| 6 |
+
from .attribute import Attribute
|
insightface/model_zoo/__pycache__/__init__.cpython-310.pyc
ADDED
|
Binary file (371 Bytes). View file
|
|
|
insightface/model_zoo/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (528 Bytes). View file
|
|
|