Spaces:
Sleeping
Sleeping
init app
Browse files- .gitignore +2 -0
- README.md +1 -1
- app.py +79 -0
- requirements.txt +5 -0
- utils.py +50 -0
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
.idea/
|
2 |
+
__pycache__/
|
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: 👁
|
4 |
colorFrom: blue
|
5 |
colorTo: green
|
|
|
1 |
---
|
2 |
+
title: Face Parser
|
3 |
emoji: 👁
|
4 |
colorFrom: blue
|
5 |
colorTo: green
|
app.py
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
import numpy as np
|
5 |
+
import torch
|
6 |
+
from PIL import Image
|
7 |
+
from bisnet import BiSeNet
|
8 |
+
from huggingface_hub import snapshot_download
|
9 |
+
|
10 |
+
from utils import vis_parsing_maps, decode_segmentation_masks, image_to_tensor
|
11 |
+
|
12 |
+
os.system("pip freeze")
|
13 |
+
|
14 |
+
REPO_ID = "leonelhs/faceparser"
|
15 |
+
MODEL_NAME = "79999_iter.pth"
|
16 |
+
|
17 |
+
model = BiSeNet(n_classes=19)
|
18 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
19 |
+
snapshot_folder = snapshot_download(repo_id=REPO_ID)
|
20 |
+
model_path = os.path.join(snapshot_folder, MODEL_NAME)
|
21 |
+
model.load_state_dict(torch.load(model_path, map_location=device))
|
22 |
+
model.eval()
|
23 |
+
|
24 |
+
|
25 |
+
def makeOverlay(image, mask):
|
26 |
+
prediction_mask = np.asarray(mask)
|
27 |
+
image = image.resize((512, 512), Image.BILINEAR)
|
28 |
+
dark_map, overlay = vis_parsing_maps(image, prediction_mask)
|
29 |
+
colormap = decode_segmentation_masks(dark_map)
|
30 |
+
return overlay, colormap
|
31 |
+
|
32 |
+
|
33 |
+
def predict(image):
|
34 |
+
with torch.no_grad():
|
35 |
+
image = image.resize((512, 512), Image.BILINEAR)
|
36 |
+
input_tensor = image_to_tensor(image)
|
37 |
+
input_tensor = torch.unsqueeze(input_tensor, 0)
|
38 |
+
if torch.cuda.is_available():
|
39 |
+
input_tensor = input_tensor.cuda()
|
40 |
+
output = model(input_tensor)[0]
|
41 |
+
return output.squeeze(0).cpu().numpy().argmax(0)
|
42 |
+
|
43 |
+
|
44 |
+
def inference(image):
|
45 |
+
mask = predict(image)
|
46 |
+
overlay, colormap = makeOverlay(image, mask)
|
47 |
+
return overlay
|
48 |
+
|
49 |
+
|
50 |
+
title = "Face Parser"
|
51 |
+
description = r"""
|
52 |
+
## Image face parser for research
|
53 |
+
|
54 |
+
This is an implementation of <a href='https://github.com/zllrunning/face-parsing.PyTorch' target='_blank'>face-parsing.PyTorch</a>.
|
55 |
+
It has no any particular purpose than start research on AI models.
|
56 |
+
|
57 |
+
"""
|
58 |
+
|
59 |
+
article = r"""
|
60 |
+
Questions, doubts, comments, please email 📧 `leonelhs@gmail.com`
|
61 |
+
|
62 |
+
This demo is running on a CPU, if you like this project please make us a donation to run on a GPU or just give us a <a href='https://github.com/leonelhs/zeroscratches/' target='_blank'>Github ⭐</a>
|
63 |
+
|
64 |
+
<a href="https://www.buymeacoffee.com/leonelhs"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=leonelhs&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
|
65 |
+
|
66 |
+
<center><img src='https://visitor-badge.glitch.me/badge?page_id=zeroscratches.visitor-badge' alt='visitor badge'></center>
|
67 |
+
"""
|
68 |
+
|
69 |
+
demo = gr.Interface(
|
70 |
+
inference, [
|
71 |
+
gr.Image(type="pil", label="Input"),
|
72 |
+
], [
|
73 |
+
gr.Image(type="numpy", label="Image face parsed")
|
74 |
+
],
|
75 |
+
title=title,
|
76 |
+
description=description,
|
77 |
+
article=article)
|
78 |
+
|
79 |
+
demo.queue().launch()
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
torch>=2.0.1
|
2 |
+
torchvision~=0.15.2
|
3 |
+
pillow~=9.5.0
|
4 |
+
bisnet~=1.0.1
|
5 |
+
opencv-python
|
utils.py
ADDED
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import numpy as np
|
3 |
+
import torchvision.transforms as transforms
|
4 |
+
|
5 |
+
# Colors for all 20 parts
|
6 |
+
part_colors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 0, 85], [255, 0, 170],
|
7 |
+
[0, 255, 0], [85, 255, 0], [170, 255, 0], [0, 255, 85], [0, 255, 170],
|
8 |
+
[0, 0, 255], [85, 0, 255], [170, 0, 255], [0, 85, 255], [0, 170, 255],
|
9 |
+
[255, 255, 0], [255, 255, 85], [255, 255, 170], [255, 0, 255], [255, 85, 255],
|
10 |
+
[255, 170, 255], [0, 255, 255], [85, 255, 255], [170, 255, 255]]
|
11 |
+
|
12 |
+
colormap = np.array(part_colors, dtype=np.uint8)
|
13 |
+
|
14 |
+
|
15 |
+
def image_to_tensor(image):
|
16 |
+
return transforms.Compose([
|
17 |
+
transforms.ToTensor(),
|
18 |
+
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
|
19 |
+
])(image)
|
20 |
+
|
21 |
+
|
22 |
+
def decode_segmentation_masks(mask, n_classes=20):
|
23 |
+
red = np.zeros_like(mask).astype(np.uint8)
|
24 |
+
green = np.zeros_like(mask).astype(np.uint8)
|
25 |
+
blue = np.zeros_like(mask).astype(np.uint8)
|
26 |
+
for chanel in range(0, n_classes):
|
27 |
+
idx = mask == chanel
|
28 |
+
red[idx] = colormap[chanel, 0]
|
29 |
+
green[idx] = colormap[chanel, 1]
|
30 |
+
blue[idx] = colormap[chanel, 2]
|
31 |
+
return np.stack([red, green, blue], axis=2)
|
32 |
+
|
33 |
+
|
34 |
+
def vis_parsing_maps(image: np.array, parsing_anno, stride=1):
|
35 |
+
image = np.array(image)
|
36 |
+
vis_im = image.copy().astype(np.uint8)
|
37 |
+
vis_parsing_anno = parsing_anno.copy().astype(np.uint8)
|
38 |
+
vis_parsing_anno = cv2.resize(vis_parsing_anno, None, fx=stride, fy=stride, interpolation=cv2.INTER_NEAREST)
|
39 |
+
vis_parsing_anno_color = np.zeros((vis_parsing_anno.shape[0], vis_parsing_anno.shape[1], 3)) + 255
|
40 |
+
|
41 |
+
num_of_class = np.max(vis_parsing_anno)
|
42 |
+
|
43 |
+
for pi in range(1, num_of_class + 1):
|
44 |
+
index = np.where(vis_parsing_anno == pi)
|
45 |
+
vis_parsing_anno_color[index[0], index[1], :] = part_colors[pi]
|
46 |
+
|
47 |
+
vis_parsing_anno_color = vis_parsing_anno_color.astype(np.uint8)
|
48 |
+
vis_im = cv2.addWeighted(cv2.cvtColor(vis_im, cv2.COLOR_RGB2BGR), 0.4, vis_parsing_anno_color, 0.6, 0)
|
49 |
+
|
50 |
+
return vis_parsing_anno, vis_im
|