Files
change_hair/project/hair_service_sd/inpaint_mask.py
T
xsl 215663177a feat: 新增mask区域重绘功能 + 羽化贴回优化 + 发丝增强
新增功能:
- inpaint_mask.py: mask区域重绘服务(enhance/pure_inpaint两种模式)
  严格只在mask区做SD inpainting,发丝自然化
- /inpaint 页面 + /api/inpaint 接口:画板手绘mask + 提示词编辑 + denoising可调
- enhance_hair.webui_img2img: 新增denoising_strength参数(原硬编码0.35)

羽化贴回优化(hair_swap_manual.py 步骤⑥):
- feather_px(羽化范围)+ feather_alpha(羽化强度)拆分为两个独立参数
- 改为只羽化边缘(mask内部保持硬切,仅边缘带渐变)
- 新增黑底羽化对比图(纯黑背景凸显边缘过渡)

其他改动:
- OSS/COS密钥脱敏:改为可选import,未设环境变量时不崩溃
- manual页面:发型列表改为本次训练的8个(含hair_flow)
- enhance二次增强:重绘区改为「原图头发∪手绘mask」并外扩10%+减发际线带3cm
- 发型清单文档更新:179→180个可用发型(+hair_flow)

涉及文件:
- 新增: inpaint_mask.py, inpaint.html
- 修改: app.py, manual.html, hair_swap_manual.py, enhance_hair.py
- 修改: oss_module.py, upload_oss.py, cos_module.py(密钥脱敏)
- 文档: HAIRSTYLES_AVAILABLE.md, hairstyles_available.csv
2026-07-08 20:38:31 +08:00

65 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""mask 区域重绘(inpainting)服务
两种模式(底层都是 webui img2img inpainting,严格只在mask区重绘):
1. enhance: 用 enhance_hair.webui_img2img(默认提示词=发丝增强,denoising默认0.35
2. pure_inpaint: 纯SD inpainting(默认提示词=自然头发,denoising默认0.5
严格只重绘 mask 区域:inpainting_fill=1mask外保留原图)
"""
import cv2
import numpy as np
from utils import enhance_hair
def inpaint_mask(img, mask, prompt="", denoising_strength=0.5, mode="enhance"):
"""在 mask 区域做 SD inpainting 重绘。
参数:
img: 输入图 BGR
mask: 灰度mask,白色(255)=重绘区,与img同尺寸
prompt: 提示词(空则用模式默认值)
denoising_strength: 重绘强度 0~1
mode: "enhance" 或 "pure_inpaint"
返回:
result: 重绘后的图(mask区已重绘,其余保留原图)
info: 本次参数说明
"""
h, w = img.shape[:2]
# 归一化 mask(保证 0/255,尺寸一致)
if mask.shape[:2] != (h, w):
mask = cv2.resize(mask, (w, h), interpolation=cv2.INTER_NEAREST)
if mask.ndim == 3:
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
_, mask_bin = cv2.threshold(mask, 30, 255, cv2.THRESH_BINARY)
# 模式默认值
if not prompt:
if mode == "enhance":
prompt = "high quality, detailed natural hair strands, realistic hair texture, sharp focus, photorealistic"
else:
prompt = "natural realistic hair, soft hair strands, photorealistic, high quality, detailed"
# 统计 mask 区域占比
mask_ratio = float((mask_bin > 0).sum()) / mask_bin.size * 100
# 调用 enhance_hair.webui_img2img(底层是 inpaintinginpainting_fill=1 严格只在mask区重绘)
result = enhance_hair.webui_img2img(
img, mask_bin, prompt=prompt,
denoising_strength=denoising_strength
)
# webui 可能调整尺寸(调整到8的倍数),resize 回原图尺寸
if result.shape[:2] != (h, w):
result = cv2.resize(result, (w, h), interpolation=cv2.INTER_LANCZOS4)
# 双重保险:强制 mask 外区域用原图(虽然 inpainting_fill=1 已保证,再加一层确保严格)
mask_3c = (mask_bin > 0)[..., None]
result = np.where(mask_3c, result, img).astype(np.uint8)
info = (f"模式={mode},提示词=\"{prompt[:50]}...\"denoising={denoising_strength}"
f"mask区域={mask_ratio:.1f}%。严格只重绘mask区,其余保留原图。")
return result, mask_bin, info