Spaces:
Sleeping
Sleeping
vitor.fran commited on
Commit ·
f127edd
1
Parent(s): f9fd7e4
Improve faceless lineart detail for Space
Browse files- app.py +26 -3
- faceless_processing.py +20 -15
app.py
CHANGED
|
@@ -15,6 +15,30 @@ def process_faceless(input_image, prompt="", negative_prompt="", is_cartoon=Fals
|
|
| 15 |
# Configuração base
|
| 16 |
cfg = LineartConfig()
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
if is_cartoon:
|
| 19 |
cfg.is_cartoon = True
|
| 20 |
# Afrouxa as regras para não apagar detalhes do desenho, mas com limites seguros para bordar
|
|
@@ -59,8 +83,7 @@ def process_faceless(input_image, prompt="", negative_prompt="", is_cartoon=Fals
|
|
| 59 |
cfg.face_min_size = (9999, 9999)
|
| 60 |
|
| 61 |
# Mantém grossinho para bordar!
|
| 62 |
-
cfg.
|
| 63 |
-
cfg.interior_line_thickness = 4
|
| 64 |
|
| 65 |
# NÃO REDIMENSIONAMOS A IMAGEM – a função interna ( embroidery_processing.py) já lida com tamanhos variados.
|
| 66 |
# Gera lineart e cutout usando a função otimizada
|
|
@@ -97,4 +120,4 @@ demo = gr.Interface(
|
|
| 97 |
)
|
| 98 |
|
| 99 |
if __name__ == "__main__":
|
| 100 |
-
demo.launch()
|
|
|
|
| 15 |
# Configuração base
|
| 16 |
cfg = LineartConfig()
|
| 17 |
|
| 18 |
+
# The detail preset applies to portraits too. Previously it only affected
|
| 19 |
+
# cartoon mode, which made the public controls misleading.
|
| 20 |
+
if detail == "detailed":
|
| 21 |
+
cfg.lineart_threshold = 72
|
| 22 |
+
cfg.lineart_min_perimeter = 20.0
|
| 23 |
+
cfg.lineart_min_area = 5.0
|
| 24 |
+
cfg.min_line_distance = 4
|
| 25 |
+
cfg.silhouette_line_thickness = 5
|
| 26 |
+
cfg.interior_line_thickness = 4
|
| 27 |
+
elif detail == "soft":
|
| 28 |
+
cfg.lineart_threshold = 100
|
| 29 |
+
cfg.lineart_min_perimeter = 36.0
|
| 30 |
+
cfg.lineart_min_area = 10.0
|
| 31 |
+
cfg.min_line_distance = 7
|
| 32 |
+
cfg.silhouette_line_thickness = 4
|
| 33 |
+
cfg.interior_line_thickness = 3
|
| 34 |
+
else:
|
| 35 |
+
cfg.lineart_threshold = 88
|
| 36 |
+
cfg.lineart_min_perimeter = 28.0
|
| 37 |
+
cfg.lineart_min_area = 8.0
|
| 38 |
+
cfg.min_line_distance = 5
|
| 39 |
+
cfg.silhouette_line_thickness = 5
|
| 40 |
+
cfg.interior_line_thickness = 4
|
| 41 |
+
|
| 42 |
if is_cartoon:
|
| 43 |
cfg.is_cartoon = True
|
| 44 |
# Afrouxa as regras para não apagar detalhes do desenho, mas com limites seguros para bordar
|
|
|
|
| 83 |
cfg.face_min_size = (9999, 9999)
|
| 84 |
|
| 85 |
# Mantém grossinho para bordar!
|
| 86 |
+
cfg.stroke_dilate_iterations = 0
|
|
|
|
| 87 |
|
| 88 |
# NÃO REDIMENSIONAMOS A IMAGEM – a função interna ( embroidery_processing.py) já lida com tamanhos variados.
|
| 89 |
# Gera lineart e cutout usando a função otimizada
|
|
|
|
| 120 |
)
|
| 121 |
|
| 122 |
if __name__ == "__main__":
|
| 123 |
+
demo.launch()
|
faceless_processing.py
CHANGED
|
@@ -4,6 +4,7 @@ from PIL import Image, ImageFilter
|
|
| 4 |
from dataclasses import dataclass
|
| 5 |
from typing import Tuple, Optional
|
| 6 |
import io
|
|
|
|
| 7 |
import base64
|
| 8 |
import os
|
| 9 |
import urllib.request
|
|
@@ -144,16 +145,21 @@ class LineartConfig:
|
|
| 144 |
lineart_coarse: bool = True
|
| 145 |
|
| 146 |
# AUMENTADO: Força bruta para ignorar detalhes fracos
|
| 147 |
-
|
|
|
|
|
|
|
| 148 |
|
| 149 |
# REDUZIDO: Permite traços de corpos menores (crianças em grupos)
|
| 150 |
-
lineart_min_perimeter: float =
|
| 151 |
-
lineart_min_area: float =
|
| 152 |
-
lineart_morph_open: bool =
|
| 153 |
force_canny: bool = False
|
| 154 |
|
| 155 |
interior_erode_size: int = 1
|
| 156 |
-
interior_line_thickness: int =
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
# ---- Canny fallback parametros ----
|
| 159 |
canny_low: int = 50
|
|
@@ -688,8 +694,10 @@ def build_interior_edges(rgb: np.ndarray, subject_mask: np.ndarray, cfg: Lineart
|
|
| 688 |
min_area=min_area
|
| 689 |
)
|
| 690 |
|
| 691 |
-
|
| 692 |
-
|
|
|
|
|
|
|
| 693 |
filtered = cv2.GaussianBlur(filtered, (3, 3), 0)
|
| 694 |
|
| 695 |
_, filtered = cv2.threshold(filtered, 127, 255, cv2.THRESH_BINARY)
|
|
@@ -821,8 +829,10 @@ def _build_interior_edges_canny(rgb: np.ndarray, subject_mask: np.ndarray, cfg:
|
|
| 821 |
shape=edges.shape
|
| 822 |
)
|
| 823 |
|
| 824 |
-
|
| 825 |
-
|
|
|
|
|
|
|
| 826 |
return filtered
|
| 827 |
|
| 828 |
|
|
@@ -1144,11 +1154,6 @@ def remove_background_subject(img: Image.Image) -> Image.Image:
|
|
| 1144 |
def make_faceless_cutout(img: Image.Image) -> Image.Image:
|
| 1145 |
return remove_background_subject(img)
|
| 1146 |
|
| 1147 |
-
|
| 1148 |
-
|
| 1149 |
-
|
| 1150 |
-
|
| 1151 |
-
|
| 1152 |
def build_faceless_embroidery_assets(img: Image.Image, cfg: Optional[LineartConfig] = None, **kwargs) -> Tuple[Image.Image, Image.Image]:
|
| 1153 |
if cfg is None:
|
| 1154 |
cfg = LineartConfig()
|
|
@@ -1158,4 +1163,4 @@ def build_faceless_embroidery_assets(img: Image.Image, cfg: Optional[LineartConf
|
|
| 1158 |
cfg.negative_prompt = kwargs["negative_prompt"]
|
| 1159 |
lineart = make_faceless_lineart(img, cfg)
|
| 1160 |
cutout = make_faceless_cutout(img)
|
| 1161 |
-
return lineart, cutout
|
|
|
|
| 4 |
from dataclasses import dataclass
|
| 5 |
from typing import Tuple, Optional
|
| 6 |
import io
|
| 7 |
+
|
| 8 |
import base64
|
| 9 |
import os
|
| 10 |
import urllib.request
|
|
|
|
| 145 |
lineart_coarse: bool = True
|
| 146 |
|
| 147 |
# AUMENTADO: Força bruta para ignorar detalhes fracos
|
| 148 |
+
# Lower threshold keeps subtle clothing/hair contours that were previously
|
| 149 |
+
# discarded before they could be converted into embroidery lines.
|
| 150 |
+
lineart_threshold: int = 88
|
| 151 |
|
| 152 |
# REDUZIDO: Permite traços de corpos menores (crianças em grupos)
|
| 153 |
+
lineart_min_perimeter: float = 28.0
|
| 154 |
+
lineart_min_area: float = 8.0
|
| 155 |
+
lineart_morph_open: bool = False
|
| 156 |
force_canny: bool = False
|
| 157 |
|
| 158 |
interior_erode_size: int = 1
|
| 159 |
+
interior_line_thickness: int = 4
|
| 160 |
+
# Extra dilation is deliberately opt-in. The old unconditional dilation
|
| 161 |
+
# made independent contours merge into thick blobs at embroidery scale.
|
| 162 |
+
stroke_dilate_iterations: int = 0
|
| 163 |
|
| 164 |
# ---- Canny fallback parametros ----
|
| 165 |
canny_low: int = 50
|
|
|
|
| 694 |
min_area=min_area
|
| 695 |
)
|
| 696 |
|
| 697 |
+
dilate_iterations = max(0, int(getattr(cfg, 'stroke_dilate_iterations', 0)))
|
| 698 |
+
if dilate_iterations:
|
| 699 |
+
kernel_dilate = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
|
| 700 |
+
filtered = cv2.dilate(filtered, kernel_dilate, iterations=dilate_iterations)
|
| 701 |
filtered = cv2.GaussianBlur(filtered, (3, 3), 0)
|
| 702 |
|
| 703 |
_, filtered = cv2.threshold(filtered, 127, 255, cv2.THRESH_BINARY)
|
|
|
|
| 829 |
shape=edges.shape
|
| 830 |
)
|
| 831 |
|
| 832 |
+
dilate_iterations = max(0, int(getattr(cfg, 'stroke_dilate_iterations', 0)))
|
| 833 |
+
if dilate_iterations:
|
| 834 |
+
kernel_dilate = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
|
| 835 |
+
filtered = cv2.dilate(filtered, kernel_dilate, iterations=dilate_iterations)
|
| 836 |
return filtered
|
| 837 |
|
| 838 |
|
|
|
|
| 1154 |
def make_faceless_cutout(img: Image.Image) -> Image.Image:
|
| 1155 |
return remove_background_subject(img)
|
| 1156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1157 |
def build_faceless_embroidery_assets(img: Image.Image, cfg: Optional[LineartConfig] = None, **kwargs) -> Tuple[Image.Image, Image.Image]:
|
| 1158 |
if cfg is None:
|
| 1159 |
cfg = LineartConfig()
|
|
|
|
| 1163 |
cfg.negative_prompt = kwargs["negative_prompt"]
|
| 1164 |
lineart = make_faceless_lineart(img, cfg)
|
| 1165 |
cutout = make_faceless_cutout(img)
|
| 1166 |
+
return lineart, cutout
|