perf: 接口2/12 跳过 viz 叠图生成,省 ~80ms

compute_mask 新增 render_viz 开关(默认 True 保持接口11 行为不变)。
接口2/12 路径(generate_hairline_redraw)传 render_viz=False,跳过 6+ 张
overlay JPG 的 _jpg_b64 编码(baseline/upper/hair_seg/mask/hairline/pushed),
只保留必需的数据字段(_inner_pts/_outer_pts/_upper_mask/mask_pixels)。
This commit is contained in:
xsl
2026-07-17 01:37:53 +08:00
parent d9e96aca87
commit 2b1f528ddd
+32 -26
View File
@@ -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, 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。 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_push_cm: 仅 pushed 模式——发际线往头发方向外推的厘米数(进入现有头发)。
hairline_edge: 仅 pushed 模式——发际线提取方式 column(逐列最低点) | contour(形态学轮廓)。 hairline_edge: 仅 pushed 模式——发际线提取方式 column(逐列最低点) | contour(形态学轮廓)。
rid: 调用方的 request id,用于日志关联。 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)。 返回 (mask_bool, viz_dict)。
""" """
lg = lambda msg: logger.info("[%s] %s", rid, msg) if rid else None 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 流程; # eroded/closed 走 top_fill→closed/eroded 流程;
# pushed 走 baseline→头发分割→发际线→外推 流程,与 top_fill/closed 无关,故置空。 # pushed 走 baseline→头发分割→发际线→外推 流程,与 top_fill/closed 无关,故置空。
# render_viz=False(接口2/12 路径)时跳过 overlay JPG 编码,只保留数据字段。
viz = { viz = {
"erode_px": r, "erode_px": r,
"hair_pixels": int(hair_mask.sum()), "hair_pixels": int(hair_mask.sum()),
"closed_pixels": int(closed.sum()), "closed_pixels": int(closed.sum()),
"mask_pixels": int(mask_bool.sum()), "mask_pixels": int(mask_bool.sum()),
# 1. 发际线分割线(baseline):151 中心点标红,其余点标绿,黄线含左右延长线 # 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 半区):青色叠加 # 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):绿色叠加在原图上 # 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 流程无关,留空 # 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))), 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))), else _jpg_b64(_overlay(image_bgr, closed, (255, 0, 255))),
# 5. pushed 模式专有(发际线提取/外推)—— 非 pushed 留空 # 5. pushed 模式专有(发际线提取/外推)—— 非 pushed 留空
"hairline_overlay_base64": "", "hairline_overlay_base64": "",
"pushed_overlay_base64": "", "pushed_overlay_base64": "",
# —— 最终遮罩 —— # —— 最终遮罩 ——
"mask_overlay_base64": _jpg_b64(_overlay(image_bgr, mask_bool, (0, 0, 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), "mask_base64": _png_b64((mask_bool.astype(np.uint8)) * 255) if render_viz else "",
} }
# pushed 模式:补充内轮廓提取 + 外推线可视化 # pushed 模式:补充内轮廓提取 + 外推线可视化
if pushed_info is not None: if pushed_info is not None:
inner_pts, outer_pts, push_px = pushed_info inner_pts, outer_pts, push_px = pushed_info
# ①-f 提取内轮廓:绿=头发内轮廓线(额头弧+两侧到下颌),黄=baseline 折线 if render_viz:
hl_img = _draw_baseline(image_bgr, baseline_pts, w) # 画 baseline(黄线+关键点) # ①-f 提取内轮廓:绿=头发内轮廓线(额头弧+两侧到下颌),黄=baseline 折线
hl_img = _draw_polyline(hl_img, inner_pts, (0, 255, 0), 3) hl_img = _draw_baseline(image_bgr, baseline_pts, w) # 画 baseline(黄线+关键点)
viz["hairline_overlay_base64"] = _jpg_b64(hl_img) hl_img = _draw_polyline(hl_img, inner_pts, (0, 255, 0), 3)
# ①-g 外推:圆心红点(151) + 内轮廓(绿)+ 外推线(青)+ 遮罩(红半透明) viz["hairline_overlay_base64"] = _jpg_b64(hl_img)
ps_img = _draw_polyline(image_bgr.copy(), inner_pts, (0, 255, 0), 2) # ①-g 外推:圆心红点(151) + 内轮廓(绿)+ 外推线(青)+ 遮罩(红半透明)
ps_img = _draw_polyline(ps_img, outer_pts, (0, 255, 255), 3) ps_img = _draw_polyline(image_bgr.copy(), inner_pts, (0, 255, 0), 2)
# 画圆心(151 点)红点,标示径向外推的中心(_idx151 上方已按值查到) ps_img = _draw_polyline(ps_img, outer_pts, (0, 255, 255), 3)
if center is not None: # 画圆心(151 点)红点,标示径向外推的中心(_idx151 上方已按值查到)
cx151, cy151 = center if center is not None:
cv2.circle(ps_img, (cx151, cy151), 6, (0, 0, 255), -1, cv2.LINE_AA) cx151, cy151 = center
cv2.putText(ps_img, "151", (cx151 + 8, cy151 - 8), cv2.circle(ps_img, (cx151, cy151), 6, (0, 0, 255), -1, cv2.LINE_AA)
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, cv2.LINE_AA) cv2.putText(ps_img, "151", (cx151 + 8, cy151 - 8),
ps_img = _overlay(ps_img, mask_bool, (0, 0, 255), 0.3) cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1, cv2.LINE_AA)
viz["pushed_overlay_base64"] = _jpg_b64(ps_img) 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 viz["push_px"] = push_px
# 重绘带用原始数据:内轮廓点 + 外推点(供 _redraw_band_mask 连端点成带) # 重绘带用原始数据:内轮廓点 + 外推点(供 _redraw_band_mask 连端点成带)
viz["_inner_pts"] = inner_pts 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, edge_erode_px, denoising_strength, gen_backend, hairgrow_strength,
mb_levels, hairline_push_cm, hairline_edge, blend_method, color_match, mb_levels, hairline_push_cm, hairline_edge, blend_method, color_match,
color_match_strength, mb_feather_px, transition_band_px, 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。 """接口11 共享核心:遮罩(pushed)→生成→硬贴回→接缝融合,产出 ④ final。
不做任何重绘。返回中间产物 dict(供接口11 构造响应、接口12 取 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() t0 = time.time()
mask_bool, mask_viz = compute_mask( mask_bool, mask_viz = compute_mask(
image_bgr, landmarks, seg_model, mask_type, erode_cm, px_per_cm, 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 t_mask = time.time() - t0
logger.info("[%s] 步骤1 遮罩完成 耗时=%dms mask_pixels=%d", rid, int(t_mask*1000), int(mask_bool.sum())) 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, color_match=color_match, color_match_strength=color_match_strength,
mb_feather_px=mb_feather_px, transition_band_px=transition_band_px, mb_feather_px=mb_feather_px, transition_band_px=transition_band_px,
inpainting_fill=inpainting_fill, mask_blur=mask_blur, 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"] final = core["final"]
mask_viz = core["mask_viz"] mask_viz = core["mask_viz"]
w, h = core["w"], core["h"] w, h = core["w"], core["h"]