vitordigitizing commited on
Commit
46a624c
·
verified ·
1 Parent(s): 90893d3

Update faceless_processing.py

Browse files
Files changed (1) hide show
  1. faceless_processing.py +67 -7
faceless_processing.py CHANGED
@@ -124,6 +124,7 @@ class LineartConfig:
124
  rembg_model: str = ""
125
  transparency_threshold: float = 0.03
126
  detect_eyebrows: bool = True
 
127
 
128
  # Subject mask
129
  white_bg_threshold: int = 245
@@ -131,19 +132,19 @@ class LineartConfig:
131
  mask_open_iterations: int = 1
132
  mask_smooth_ksize: int = 5
133
  mask_smooth_threshold: int = 128
134
- # Área mínima de silhueta. Valor menor preserva crianças e figuras pequenas.
135
- min_silhouette_area: float = 80.0
136
-
137
  # Silhouette outline
138
  silhouette_line_thickness: int = 4
139
 
 
 
 
140
  # --- Neural line-art parameters ---
141
  lineart_detect_resolution: int = 1024
142
  lineart_image_resolution: int = 1024
143
  lineart_coarse: bool = True
144
 
145
- # Reduzido: Permite traços de corpos menores (crianças em grupos)
146
- lineart_threshold: int = 120
147
 
148
  # REDUZIDO: Permite traços de corpos menores (crianças em grupos)
149
  lineart_min_perimeter: float = 80.0
@@ -215,6 +216,7 @@ class LineartConfig:
215
 
216
 
217
 
 
218
  def _nms_faces(faces: list, iou_thresh: float) -> list:
219
  if not faces:
220
  return []
@@ -468,7 +470,7 @@ def build_silhouette(subject_mask: np.ndarray, cfg: LineartConfig) -> np.ndarray
468
  cv2.drawContours(silhouette, [approx], -1, 255,
469
  cfg.silhouette_line_thickness, lineType=cv2.LINE_AA)
470
  return silhouette
471
-
472
 
473
  def build_face_erase_mask(rgb: np.ndarray, faces: list, cfg: LineartConfig) -> np.ndarray:
474
  h, w = rgb.shape[:2]
@@ -699,11 +701,64 @@ def build_interior_edges(rgb: np.ndarray, subject_mask: np.ndarray, cfg: Lineart
699
  return _build_interior_edges_canny(rgb, subject_mask, cfg)
700
 
701
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702
  def _build_interior_edges_canny(rgb: np.ndarray, subject_mask: np.ndarray, cfg: LineartConfig) -> np.ndarray:
703
  gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
704
  blurred = cv2.bilateralFilter(gray, cfg.bilateral_d, cfg.bilateral_sigma_color, cfg.bilateral_sigma_space)
705
  blurred = cv2.GaussianBlur(blurred, (cfg.gaussian_ksize, cfg.gaussian_ksize), 0)
706
- edges = cv2.Canny(blurred, cfg.canny_low, cfg.canny_high)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
707
 
708
  erode_size = max(5, cfg.silhouette_line_thickness * 2 + 3)
709
  if erode_size % 2 == 0:
@@ -740,6 +795,7 @@ def _build_interior_edges_canny(rgb: np.ndarray, subject_mask: np.ndarray, cfg:
740
  return filtered
741
 
742
 
 
743
  _LANDMARKER_LOCK = threading.Lock()
744
  _LANDMARKER_CACHE = None
745
  _LANDMARKER_NUM_FACES = None
@@ -902,6 +958,7 @@ def draw_eyebrows(rgb: np.ndarray, cfg: LineartConfig, faces: Optional[list] = N
902
  return eyebrows_layer
903
 
904
 
 
905
  def make_faceless_lineart(img: Image.Image, cfg: LineartConfig = None) -> Image.Image:
906
  cfg = cfg or LineartConfig()
907
 
@@ -1058,6 +1115,9 @@ def make_faceless_cutout(img: Image.Image) -> Image.Image:
1058
 
1059
 
1060
 
 
 
 
1061
  def build_faceless_embroidery_assets(img: Image.Image, cfg: Optional[LineartConfig] = None, **kwargs) -> Tuple[Image.Image, Image.Image]:
1062
  if cfg is None:
1063
  cfg = LineartConfig()
 
124
  rembg_model: str = ""
125
  transparency_threshold: float = 0.03
126
  detect_eyebrows: bool = True
127
+ is_cartoon: bool = False
128
 
129
  # Subject mask
130
  white_bg_threshold: int = 245
 
132
  mask_open_iterations: int = 1
133
  mask_smooth_ksize: int = 5
134
  mask_smooth_threshold: int = 128
 
 
 
135
  # Silhouette outline
136
  silhouette_line_thickness: int = 4
137
 
138
+ # Área mínima de silhueta. Valor menor preserva crianças e figuras pequenas.
139
+ min_silhouette_area: float = 90.0
140
+
141
  # --- Neural line-art parameters ---
142
  lineart_detect_resolution: int = 1024
143
  lineart_image_resolution: int = 1024
144
  lineart_coarse: bool = True
145
 
146
+ # AUMENTADO: Força bruta para ignorar detalhes fracos
147
+ lineart_threshold: int = 115
148
 
149
  # REDUZIDO: Permite traços de corpos menores (crianças em grupos)
150
  lineart_min_perimeter: float = 80.0
 
216
 
217
 
218
 
219
+
220
  def _nms_faces(faces: list, iou_thresh: float) -> list:
221
  if not faces:
222
  return []
 
470
  cv2.drawContours(silhouette, [approx], -1, 255,
471
  cfg.silhouette_line_thickness, lineType=cv2.LINE_AA)
472
  return silhouette
473
+
474
 
475
  def build_face_erase_mask(rgb: np.ndarray, faces: list, cfg: LineartConfig) -> np.ndarray:
476
  h, w = rgb.shape[:2]
 
701
  return _build_interior_edges_canny(rgb, subject_mask, cfg)
702
 
703
 
704
+ def _skeletonize(img: np.ndarray) -> np.ndarray:
705
+ """
706
+ Applies morphological skeletonization to reduce binary lines to 1-pixel wide centerlines.
707
+ """
708
+ size = np.size(img)
709
+ skel = np.zeros(img.shape, np.uint8)
710
+ element = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
711
+ img_copy = img.copy()
712
+
713
+ for _ in range(120): # safety limit
714
+ eroded = cv2.erode(img_copy, element)
715
+ temp = cv2.dilate(eroded, element)
716
+ temp = cv2.subtract(img_copy, temp)
717
+ skel = cv2.bitwise_or(skel, temp)
718
+ img_copy = eroded
719
+ if cv2.countNonZero(img_copy) == 0:
720
+ break
721
+
722
+ return skel
723
+
724
+
725
  def _build_interior_edges_canny(rgb: np.ndarray, subject_mask: np.ndarray, cfg: LineartConfig) -> np.ndarray:
726
  gray = cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY)
727
  blurred = cv2.bilateralFilter(gray, cfg.bilateral_d, cfg.bilateral_sigma_color, cfg.bilateral_sigma_space)
728
  blurred = cv2.GaussianBlur(blurred, (cfg.gaussian_ksize, cfg.gaussian_ksize), 0)
729
+
730
+ if getattr(cfg, 'is_cartoon', False):
731
+ # 1. Binarização adaptativa inteligente para extrair traços cheios (evita contorno duplo!)
732
+ corners = [blurred[0, 0], blurred[0, -1], blurred[-1, 0], blurred[-1, -1]]
733
+ bg = float(np.median(corners))
734
+ if bg > 127: # Fundo claro, traços escuros
735
+ thresh = cv2.adaptiveThreshold(
736
+ blurred, 255,
737
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
738
+ cv2.THRESH_BINARY_INV,
739
+ 21, 5
740
+ )
741
+ else: # Fundo escuro, traços claros
742
+ thresh = cv2.adaptiveThreshold(
743
+ blurred, 255,
744
+ cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
745
+ cv2.THRESH_BINARY,
746
+ 21, 5
747
+ )
748
+
749
+ # 2. Canny complementar para não perder pequenos detalhes de alto contraste
750
+ canny_edges = cv2.Canny(blurred, cfg.canny_low, cfg.canny_high)
751
+ # Dilata Canny levemente para fundir com os traços do limiar adaptativo
752
+ kernel_c = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
753
+ canny_dilated = cv2.dilate(canny_edges, kernel_c, iterations=1)
754
+
755
+ # Combina ambos
756
+ combined = cv2.bitwise_or(thresh, canny_dilated)
757
+
758
+ # 3. Esqueletização para converter todos os traços cheios em linhas de 1 pixel centralizadas
759
+ edges = _skeletonize(combined)
760
+ else:
761
+ edges = cv2.Canny(blurred, cfg.canny_low, cfg.canny_high)
762
 
763
  erode_size = max(5, cfg.silhouette_line_thickness * 2 + 3)
764
  if erode_size % 2 == 0:
 
795
  return filtered
796
 
797
 
798
+
799
  _LANDMARKER_LOCK = threading.Lock()
800
  _LANDMARKER_CACHE = None
801
  _LANDMARKER_NUM_FACES = None
 
958
  return eyebrows_layer
959
 
960
 
961
+
962
  def make_faceless_lineart(img: Image.Image, cfg: LineartConfig = None) -> Image.Image:
963
  cfg = cfg or LineartConfig()
964
 
 
1115
 
1116
 
1117
 
1118
+
1119
+
1120
+
1121
  def build_faceless_embroidery_assets(img: Image.Image, cfg: Optional[LineartConfig] = None, **kwargs) -> Tuple[Image.Image, Image.Image]:
1122
  if cfg is None:
1123
  cfg = LineartConfig()