Files
change_hair/docs/HAIR_GROWTH_FEASIBILITY.md
T
xsl 443cfa298f 初始化:换发型/换发色/训练发型服务
包含:
- hair_service_sd: 主服务(换发型/换发色/生发,端口8801)
- photo_service: LoRA调度+训练(端口32678)
- hair_grow_service: 调试测试页(端口8888,含4个测试页)
- 批量训练脚本(batch_train_hairstyles.py)
- 发际线mask自动识别(hairline_mask.py,4种方案)
- 手绘mask换发型(hair_swap_manual.py)
- 文档:README.md + LARGE_FILES.md + docs/

大文件(模型权重200G、训练数据123G)已排除,见 LARGE_FILES.md
OSS/COS密钥已脱敏为环境变量,原文件备份在本地
2026-07-07 13:53:52 +08:00

14 KiB
Raw Blame History

区域生发功能 - 技术调研报告

功能定义:输入一张头发稀少/发际线偏高的人头照片,在照片上指定一个区域或遮罩,输出在该区域内"生发"(补全/填充头发)的结果图。

调研日期:2026-06-21


一、需求分析与技术挑战

1.1 需求拆解

本功能本质是一个 "受限区域头发补全"constrained hair inpainting)任务,可拆为三个子问题:

子问题 描述 难度
① 在哪生发 确定缺发区域(发际线后退区、头顶稀疏区),即 mask 中(可人工画,也可自动检测)
② 生成什么 在 mask 区域内生成与本人发色、发质、走向自然衔接的头发 高(核心难点)
③ 如何融合 把生成结果无缝贴回原图,消除边缘拼接痕迹 低(已有成熟工具)

1.2 关键挑战

  1. 生成真实感:新生头发必须符合该人的发色/卷曲度/走向,不能突兀。SD1.5 对细密发丝的生成能力有限,容易出现"塑料感"或糊。
  2. 边缘自然衔接:新生头发与原有头发、额头皮质的交界处不能有硬边或色差。
  3. 发丝纹理一致性:新头发应延续原头发的纹理方向(从发旋/发根向外)。
  4. 不破坏五官:生发区域靠近额头/眉毛,生成时不能改变五官。
  5. mask 边界合理性:mask 区域应只覆盖"该长头发但目前没长"的地方,不能覆盖到脸上或背景。

二、技术方案全景

综合代码库已有能力和业界方案,归纳出 4 种实现路径,按推荐度排序。

方案 A:复用现有 webui Inpainting(★★★★★ 强烈推荐)

核心思路:把"生发"当作一次 SD inpainting——mask 区域重绘为头发,非 mask 区域保持不变。这正是换发型服务里 webui_img2img 已经在做的事,几乎可原样复用。

[原图] → [人检+1k关键点] → [构造生发mask] → [webui_img2img(mask内重绘为头发)] → [泊松融合] → [结果]

可复用的现成组件(均在代码库内,已验证可用):

环节 复用组件 文件:行号 说明
人脸检测 RetinaFaceDetector.forward models/detector.py:148 定位人脸框
1k关键点 MomocvFaceAlignment1K.stable_forward utils/MomocvFaceAlignment1K.py:404 发际线定位的关键
头发mask Generator_Matte.matte_inference hair_matting/Generator_Matte.py:81 现有头发alpha
发际线/头皮分割 Generator_BaldSeg_5c.forward models/Generator_BaldSeg.py:45 自动定位缺发区,权重存在
额头凸包mask draw_bigger_hull_mask utils/landmark_processor.py:1079 关键点→额头区mask
SD生成 webui_img2img(img, mask_img, ...) gen_super_image.py:416 核心生成,已验证可用
泊松融合 cv2.seamlessClone core/hairstyle_model.py:1380 消除拼接缝

mask 构造方法(两种交互模式)

  • 手动模式(用户画遮罩):前端提供画笔工具,用户在发际线/稀疏区涂抹 → 直接作为 inpainting mask。最简单可靠。
  • 自动模式(自动检测缺发区):BaldSeg 的 5 类分割直接区分"有发区/头皮区",或用 额头凸包mask - 现有头发mask = 缺发带。无需用户画,但需调参。

生成参数建议(基于 build_body_v2gen_super_image.py:86):

  • denoising_strength = 0.5~0.7(重绘强度,过低生不出新发,过高破坏原有头发)
  • mask_blur = 8~12(边缘羽化,避免硬边)
  • prompt = "thick natural hair, detailed hair strands, realistic hairline, high detail"
  • negative_prompt = "bald, receding hairline, thinning hair, bald spot, skin, low quality"
  • inpainting_fill = 1mask 区域填噪声重绘)
  • steps = 20~30

优势

  • 90% 代码已存在且验证过,开发量最小(主要是拼装 + mask 构造逻辑)
  • 与现有服务架构完全一致,可作为一个新接口 /api/hairGrow/v1 接入
  • 无需新增任何模型权重

劣势

  • ⚠️ SD1.5v1-5-pruned)生成细密发丝的真实感有限,发丝可能偏糊
  • ⚠️ 同一个人多次生发结果可能不一致(生成模型随机性)

预估工作量:2-3 天(mask 构造逻辑 + 接口封装 + 调参)


方案 BControlNet Canny 约束发丝走向(★★★★ 推荐)

核心思路:在方案 A 基础上,引入 ControlNet Canny 约束新生头发的走向,使其与已有头发的纹理方向一致,提升真实感。

[原图] → 提取已有头发的 canny 边缘 → [mask内: SD inpainting + ControlNet canny约束] → [结果]

关键改动(相对方案A):

  • 启用 webui 的 ControlNet(代码库已装 control_v11p_sd15_canny 模型,可用)
  • 参照 gen_super_image.py:244 build_bodyalwayson_scripts 结构,把 openpose 改成 canny
  • canny 输入图:对原图做 cv2.Canny,或在 mask 外保留原头发边缘作为约束

ControlNet 配置示例(需新增到 build_body):

"alwayson_scripts": {
    "controlnet": {
        "args": [{
            "model": "control_v11p_sd15_canny",
            "module": "canny",
            "weight": 0.5,           # 约束强度,0.3-0.7
            "input_image": <原图base64>,  # webui自动做canny
            "resize_mode": "just_resize"
        }]
    }
}

优势

  • 发丝走向更自然、与原发衔接更好
  • ControlNet 模型和扩展都已在 webui 里,无需额外部署

劣势

  • ⚠️ canny 约束在"完全无发的光头区"无法提供有效边缘(那里本来就没头发),主要对"稀疏→加密"有效
  • ⚠️ 需要调 weight,过强会让新生头发僵硬

预估工作量3-4 天(方案A + ControlNet 调试)


方案 CSAM 自动分割 + SD Inpainting(★★★ 可选)

核心思路:用 Segment Anything (SAM) 替代手动画 mask——用户点击缺发区域,SAM 自动分割出精确边界,再做 inpainting。

[原图] → [用户点击发际线区域] → [SAM分割出该区域mask] → [SD inpainting] → [结果]

业界实践:这是目前社区主流的"点击式 inpainting"范式,已有成熟工具:

是否需要 SAM

  • 若用户手动画 mask(方案A)→ 不需要 SAM
  • 若要点击式自动分割 → 需要 SAM(代码库没有,需新增 ~2.5G 模型)

优势

  • 交互体验好(点一下即可),mask 边界比手画精确

劣势

  • ⚠️ 需新增 SAM 模型(vit_h 约 2.5G),增加部署复杂度
  • ⚠️ SAM 对"发际线缺发带"这种渐变区域的分割不一定准确(头发与皮肤对比度低时)
  • ⚠️ 代码库已有 Generator_BaldSeg(头皮分割)+ 1k关键点(发际线定位),可达到类似自动 mask 效果,不一定非要用 SAM

预估工作量5-7 天(含 SAM 集成)

结论不优先推荐。代码库的 BaldSeg + 关键点方案已能实现"自动定位缺发区",SAM 的边际价值不大,除非未来需要通用点击分割。


方案 D:专项 LoRA 微调 / 训练生发模型(★★ 备选)

核心思路:收集"稀疏发/高发际线 → 浓密发"的配对数据,训练一个生发专用 LoRA 或微调模型,专门优化生发效果。

业界相关研究

  • HairDiffusion (NeurIPS 2024):把发型/发色编辑重新定义为 latent diffusion inpainting 任务
  • AnyBald (WACV 2026)diffusion inpainting + 可学习文本提示做头发去除(反向任务,架构可借鉴)
  • Stable-Hair (arXiv 2024)diffusion 真实世界发型迁移

适用场景:当方案 A/B 用通用 SD 的生发效果不够好(发丝太糊/不真实),且业务对质量要求高时。

优势

  • 可针对性优化生发质量,效果上限最高

劣势

  • 需要大量配对训练数据(稀疏发→浓密发),数据收集是最大瓶颈
  • 训练+调优周期长(2-4 周)
  • 代码库的 LoRA 训练流程(kohya)是针对"发型模板"的,生发是不同任务,需重新组织数据

预估工作量3-4 周(含数据收集、训练、调优)

结论作为后续优化手段备选,不作为首期方案。先用方案 A/B 跑通,效果不达标再考虑。


三、推荐方案与实施路径

3.1 推荐:方案 A 为主,方案 B 为增强

首期实现方案 A(复用 webui inpainting),最快验证可行性;若效果不足,叠加方案 BControlNet canny)。方案 C/D 暂不引入。

理由:

  1. 方案 A 的 90% 组件已存在且验证过,风险最低、见效最快
  2. 代码库的 Generator_BaldSeg 能自动定位缺发区,免去了 SAM 的额外部署
  3. 与现有服务架构一致,可作为 hair_service_sd 的新接口无缝接入

3.2 推荐的功能管线(方案A

输入: 人头图 + (可选)手绘mask
  │
  ├─ 若无手绘mask(自动模式):
  │    1. RetinaFace 检测人脸 → 1k关键点
  │    2. Generator_BaldSeg 分割 → 提取"头皮/发际线"区
  │    3. 或: 额头凸包mask(关键点) - 现有头发mask(matting) = 缺发带
  │    4. mask 形态学处理(dilate/erode 羽化)
  │
  ├─ 若有手绘mask(手动模式):
  │    直接使用,轻微 dilate 羽化
  │
  ▼
mask_blur=10 的 inpainting:
  webui_img2img(
      img = 原图,
      mask_img = 生发mask,
      tag = "thick natural hair, detailed hair strands, hairline",
      denoising_strength = 0.6,
      is_hr = True
  )
  │
  ▼
泊松融合贴回(cv2.seamlessClone + GaussianBlur)
  │
  ▼
输出: 生发结果图

3.3 接口设计建议

POST /api/hairGrow/v1
{
  "img": "data:image/jpeg;base64,...",     # 人头图
  "mask": "data:image/png;base64,...",      # 可选: 手绘mask(白色=生发区)
  "auto_mask": true,                        # 可选: 无mask时自动检测缺发区
  "userId": "xxx",
  "output_format": "base64"
}

返回(同换发型):

{"state": 0, "msg": "success", "data": "<base64结果图>", "task_id": "..."}

四、代码库可复用能力清单(详细)

以下能力全部已在本机部署中验证可用,无需新增模型:

能力 模块 文件:行号 权重 对生发的作用
人脸检测 RetinaFace models/detector.py:148 Resnet50_Final.pth (109M) 入口,定位人脸
1k关键点 MomocvFaceAlignment1K utils/MomocvFaceAlignment1K.py:404 face_alignment_1k.pth (49M) 发际线定位
头发抠图 Generator_Matte hair_matting/Generator_Matte.py:81 deeplabv3+gca (535M) 现有头发边界
头皮分割 Generator_BaldSeg_5c models/Generator_BaldSeg.py:45 ori_hair_checkpoint (134M) 自动定位缺发区
人脸分割 FaceSeg core/faceseg/face_seg.py:32 faceseg_20210927 (229M) 排除五官区
SD inpainting webui_img2img gen_super_image.py:416 v1-5 SD模型 (4.2G) 核心生成
额头mask构造 draw_bigger_hull_mask utils/landmark_processor.py:1079 - 关键点→额头区
泊松融合 cv2.seamlessClone core/hairstyle_model.py:1380 - 边缘融合
形态学处理 cv2.dilate/erode utils/landmark_processor.py 多处 - mask羽化
ControlNet canny sd-webui-controlnet webui扩展(已装) control_v11p_sd15_canny 发丝走向约束(方案B)

五、风险与质量评估

风险点 严重度 应对
SD1.5生发发丝偏糊 方案B加canny约束;或后续换SDXL inpainting模型(需升级webui)
自动mask不准(误判缺发区) 首期优先支持手绘mask;自动模式作为可选增强
生发破坏五官 mask构造时必须减去FaceSeg的人脸区;inpainting的mask严格限定
多次结果不一致 固定seed(代码已用seed=123456789);可返回多张供选
边缘拼接痕迹 泊松融合+GaussianBlur已有成熟方案

质量预期:方案A对手绘mask场景(用户明确指定生发区)效果应较好;对稀疏加密(发际线整体下移)效果中等;对完全光头大区域生发效果有限(建议用方案D专项优化)。


六、实施建议(分阶段)

阶段一(2-3天):MVP 手动 mask 生发

  • 实现 /api/hairGrow/v1 接口,接收手绘 mask
  • 复用 webui_img2imgprompt 写生发描述
  • 加泊松融合后处理
  • 用几张发际线高的测试图调参(denoising/mask_blur/prompt

阶段二(2-3天):自动 mask + ControlNet

  • 接入 Generator_BaldSeg 自动检测缺发区
  • 叠加 ControlNet canny 约束发丝走向(方案B)
  • 对比有无 canny 的效果差异

阶段三(按需):质量优化

  • 若效果不足:收集生发配对数据,训练专项 LoRA(方案D)
  • 或升级到 SDXL inpainting 模型提升发丝真实感

七、参考资料

学术论文

实践工具/社区