diff --git a/face_analysis/hairline_grow.py b/face_analysis/hairline_grow.py index 229143b..10957cd 100644 --- a/face_analysis/hairline_grow.py +++ b/face_analysis/hairline_grow.py @@ -357,7 +357,7 @@ def _redraw_band_mask(inner_pts, outer_pts, h, w, rid="", upper=None, def compute_mask(image_bgr, landmarks, seg_model, mask_type, erode_cm, px_per_cm, - hairline_push_cm=0.0, hairline_edge="column", rid=""): + hairline_push_cm=0.0, hairline_edge="column", rid="", render_viz=True): """算出布尔遮罩 + 可视化。 seg_model: bisenet | segformer。 @@ -365,6 +365,9 @@ def compute_mask(image_bgr, landmarks, seg_model, mask_type, erode_cm, px_per_cm hairline_push_cm: 仅 pushed 模式——发际线往头发方向外推的厘米数(进入现有头发)。 hairline_edge: 仅 pushed 模式——发际线提取方式 column(逐列最低点) | contour(形态学轮廓)。 rid: 调用方的 request id,用于日志关联。 + render_viz: 是否生成各阶段叠图 overlay JPG(接口11 调试页用)。接口2/12 路径传 False + 可跳过 6+ 张 base64 编码,省 ~80ms;数据字段(_inner_pts/_outer_pts/_upper_mask/ + mask_pixels 等)始终返回,不受影响。 返回 (mask_bool, viz_dict)。 """ lg = lambda msg: logger.info("[%s] %s", rid, msg) if rid else None @@ -425,47 +428,49 @@ def compute_mask(image_bgr, landmarks, seg_model, mask_type, erode_cm, px_per_cm # 遮罩计算过程可视化: # eroded/closed 走 top_fill→closed/eroded 流程; # pushed 走 baseline→头发分割→发际线→外推 流程,与 top_fill/closed 无关,故置空。 + # render_viz=False(接口2/12 路径)时跳过 overlay JPG 编码,只保留数据字段。 viz = { "erode_px": r, "hair_pixels": int(hair_mask.sum()), "closed_pixels": int(closed.sum()), "mask_pixels": int(mask_bool.sum()), # 1. 发际线分割线(baseline):151 中心点标红,其余点标绿,黄线含左右延长线 - "baseline_overlay_base64": _jpg_b64(_draw_baseline(image_bgr, baseline_pts, w)), + "baseline_overlay_base64": _jpg_b64(_draw_baseline(image_bgr, baseline_pts, w)) if render_viz else "", # 2. 分割线以上区域(upper 半区):青色叠加 - "upper_overlay_base64": _jpg_b64(_overlay(image_bgr, upper, (0, 255, 255))), + "upper_overlay_base64": _jpg_b64(_overlay(image_bgr, upper, (0, 255, 255))) if render_viz else "", # 3. 头发分割原始结果(hair_mask):绿色叠加在原图上 - "hair_seg_overlay_base64": _jpg_b64(_overlay(image_bgr, hair_mask, (0, 255, 0))), + "hair_seg_overlay_base64": _jpg_b64(_overlay(image_bgr, hair_mask, (0, 255, 0))) if render_viz else "", # 4. top_fill / closed —— 仅 eroded/closed 流程用;pushed 流程无关,留空 - "top_fill_overlay_base64": "" if mask_type == "pushed" + "top_fill_overlay_base64": "" if (mask_type == "pushed" or not render_viz) else _jpg_b64(_overlay(image_bgr, top_fill, (255, 0, 0))), - "closed_overlay_base64": "" if mask_type == "pushed" + "closed_overlay_base64": "" if (mask_type == "pushed" or not render_viz) else _jpg_b64(_overlay(image_bgr, closed, (255, 0, 255))), # 5. pushed 模式专有(发际线提取/外推)—— 非 pushed 留空 "hairline_overlay_base64": "", "pushed_overlay_base64": "", # —— 最终遮罩 —— - "mask_overlay_base64": _jpg_b64(_overlay(image_bgr, mask_bool, (0, 0, 255))), - "mask_base64": _png_b64((mask_bool.astype(np.uint8)) * 255), + "mask_overlay_base64": _jpg_b64(_overlay(image_bgr, mask_bool, (0, 0, 255))) if render_viz else "", + "mask_base64": _png_b64((mask_bool.astype(np.uint8)) * 255) if render_viz else "", } # pushed 模式:补充内轮廓提取 + 外推线可视化 if pushed_info is not None: inner_pts, outer_pts, push_px = pushed_info - # ①-f 提取内轮廓:绿=头发内轮廓线(额头弧+两侧到下颌),黄=baseline 折线 - hl_img = _draw_baseline(image_bgr, baseline_pts, w) # 画 baseline(黄线+关键点) - hl_img = _draw_polyline(hl_img, inner_pts, (0, 255, 0), 3) - viz["hairline_overlay_base64"] = _jpg_b64(hl_img) - # ①-g 外推:圆心红点(151) + 内轮廓(绿)+ 外推线(青)+ 遮罩(红半透明) - ps_img = _draw_polyline(image_bgr.copy(), inner_pts, (0, 255, 0), 2) - ps_img = _draw_polyline(ps_img, outer_pts, (0, 255, 255), 3) - # 画圆心(151 点)红点,标示径向外推的中心(_idx151 上方已按值查到) - if center is not None: - cx151, cy151 = center - cv2.circle(ps_img, (cx151, cy151), 6, (0, 0, 255), -1, cv2.LINE_AA) - cv2.putText(ps_img, "151", (cx151 + 8, cy151 - 8), - cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, cv2.LINE_AA) - ps_img = _overlay(ps_img, mask_bool, (0, 0, 255), 0.3) - viz["pushed_overlay_base64"] = _jpg_b64(ps_img) + if render_viz: + # ①-f 提取内轮廓:绿=头发内轮廓线(额头弧+两侧到下颌),黄=baseline 折线 + hl_img = _draw_baseline(image_bgr, baseline_pts, w) # 画 baseline(黄线+关键点) + hl_img = _draw_polyline(hl_img, inner_pts, (0, 255, 0), 3) + viz["hairline_overlay_base64"] = _jpg_b64(hl_img) + # ①-g 外推:圆心红点(151) + 内轮廓(绿)+ 外推线(青)+ 遮罩(红半透明) + ps_img = _draw_polyline(image_bgr.copy(), inner_pts, (0, 255, 0), 2) + ps_img = _draw_polyline(ps_img, outer_pts, (0, 255, 255), 3) + # 画圆心(151 点)红点,标示径向外推的中心(_idx151 上方已按值查到) + if center is not None: + cx151, cy151 = center + cv2.circle(ps_img, (cx151, cy151), 6, (0, 0, 255), -1, cv2.LINE_AA) + cv2.putText(ps_img, "151", (cx151 + 8, cy151 - 8), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, cv2.LINE_AA) + ps_img = _overlay(ps_img, mask_bool, (0, 0, 255), 0.3) + viz["pushed_overlay_base64"] = _jpg_b64(ps_img) viz["push_px"] = push_px # 重绘带用原始数据:内轮廓点 + 外推点(供 _redraw_band_mask 连端点成带) viz["_inner_pts"] = inner_pts @@ -844,7 +849,7 @@ def _grow_core(image_bgr, hairline_id, *, is_hr, seg_model, erode_cm, swap_mode, edge_erode_px, denoising_strength, gen_backend, hairgrow_strength, mb_levels, hairline_push_cm, hairline_edge, blend_method, color_match, color_match_strength, mb_feather_px, transition_band_px, - inpainting_fill, mask_blur, mask_dilate_scale, rid): + inpainting_fill, mask_blur, mask_dilate_scale, rid, render_viz=True): """接口11 共享核心:遮罩(pushed)→生成→硬贴回→接缝融合,产出 ④ final。 不做任何重绘。返回中间产物 dict(供接口11 构造响应、接口12 取 final+重绘带用): @@ -873,7 +878,8 @@ def _grow_core(image_bgr, hairline_id, *, is_hr, seg_model, erode_cm, swap_mode, t0 = time.time() mask_bool, mask_viz = compute_mask( image_bgr, landmarks, seg_model, mask_type, erode_cm, px_per_cm, - hairline_push_cm=hairline_push_cm, hairline_edge=hairline_edge, rid=rid) + hairline_push_cm=hairline_push_cm, hairline_edge=hairline_edge, rid=rid, + render_viz=render_viz) t_mask = time.time() - t0 logger.info("[%s] 步骤1 遮罩完成 耗时=%dms mask_pixels=%d", rid, int(t_mask*1000), int(mask_bool.sum())) @@ -1050,7 +1056,7 @@ def generate_hairline_redraw(image_bgr, hairline_id, is_hr=False, seg_model="seg color_match=color_match, color_match_strength=color_match_strength, mb_feather_px=mb_feather_px, transition_band_px=transition_band_px, inpainting_fill=inpainting_fill, mask_blur=mask_blur, - mask_dilate_scale=mask_dilate_scale, rid=rid) + mask_dilate_scale=mask_dilate_scale, rid=rid, render_viz=False) final = core["final"] mask_viz = core["mask_viz"] w, h = core["w"], core["h"]