# 区域生发功能 - 技术调研报告 > **功能定义**:输入一张头发稀少/发际线偏高的人头照片,在照片上指定一个区域或遮罩,输出在该区域内"生发"(补全/填充头发)的结果图。 > > 调研日期: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_v2`,gen_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 = 1`(mask 区域填噪声重绘) - `steps = 20~30` **优势**: - ✅ 90% 代码已存在且验证过,开发量最小(主要是拼装 + mask 构造逻辑) - ✅ 与现有服务架构完全一致,可作为一个新接口 `/api/hairGrow/v1` 接入 - ✅ 无需新增任何模型权重 **劣势**: - ⚠️ SD1.5(v1-5-pruned)生成细密发丝的真实感有限,发丝可能偏糊 - ⚠️ 同一个人多次生发结果可能不一致(生成模型随机性) **预估工作量**:2-3 天(mask 构造逻辑 + 接口封装 + 调参) --- ### 方案 B:ControlNet Canny 约束发丝走向(★★★★ 推荐) **核心思路**:在方案 A 基础上,引入 **ControlNet Canny** 约束新生头发的走向,使其与已有头发的纹理方向一致,提升真实感。 ``` [原图] → 提取已有头发的 canny 边缘 → [mask内: SD inpainting + ControlNet canny约束] → [结果] ``` **关键改动**(相对方案A): - 启用 webui 的 ControlNet(代码库已装 `control_v11p_sd15_canny` 模型,可用) - 参照 `gen_super_image.py:244 build_body` 的 `alwayson_scripts` 结构,把 openpose 改成 canny - canny 输入图:对原图做 `cv2.Canny`,或在 mask 外保留原头发边缘作为约束 **ControlNet 配置示例**(需新增到 build_body): ```python "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 调试) --- ### 方案 C:SAM 自动分割 + SD Inpainting(★★★ 可选) **核心思路**:用 **Segment Anything (SAM)** 替代手动画 mask——用户点击缺发区域,SAM 自动分割出精确边界,再做 inpainting。 ``` [原图] → [用户点击发际线区域] → [SAM分割出该区域mask] → [SD inpainting] → [结果] ``` **业界实践**:这是目前社区主流的"点击式 inpainting"范式,已有成熟工具: - **sd-webui-inpaint-anything** 扩展([GitHub](https://github.com/Uminosachi/sd-webui-inpaint-anything)):webui 集成 SAM + inpainting - 学术:[Segment Anything Meets Image Inpainting (arXiv:2304.06790)](https://arxiv.org/abs/2304.06790) 提出 click-and-fill 范式 **是否需要 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),最快验证可行性;**若效果不足,叠加方案 B**(ControlNet 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" } ``` 返回(同换发型): ```json {"state": 0, "msg": "success", "data": "", "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_img2img`,prompt 写生发描述 - 加泊松融合后处理 - 用几张发际线高的测试图调参(denoising/mask_blur/prompt) **阶段二(2-3天):自动 mask + ControlNet** - 接入 `Generator_BaldSeg` 自动检测缺发区 - 叠加 ControlNet canny 约束发丝走向(方案B) - 对比有无 canny 的效果差异 **阶段三(按需):质量优化** - 若效果不足:收集生发配对数据,训练专项 LoRA(方案D) - 或升级到 SDXL inpainting 模型提升发丝真实感 --- ## 七、参考资料 **学术论文**: - [HairDiffusion: Vivid Multi-Colored Hair Editing via Latent Diffusion (NeurIPS 2024)](https://openreview.net/forum?id=UQflshLbZv) — 发型编辑的 inpainting 范式 - [Stable-Hair: Real-World Hair Transfer via Diffusion Model (arXiv 2024)](https://arxiv.org/html/2407.14078v1) — 扩散发型迁移 - [Segment Anything Meets Image Inpainting (arXiv:2304.06790)](https://arxiv.org/abs/2304.06790) — SAM click-and-fill 范式 **实践工具/社区**: - [sd-webui-inpaint-anything (GitHub)](https://github.com/Uminosachi/sd-webui-inpaint-anything) — SAM + inpainting webui 扩展 - [Stable Diffusion Inpainting with SAM (HuggingFace Space)](https://huggingface.co/spaces/Sanshruth/Stable-Diffusion-Inpainting_with_SAM) — 在线 demo - [Reddit: 用 inpainting 添加头发的技巧](https://www.reddit.com/r/StableDiffusion/comments/15x9yvs/) — 社区经验:先预填底色再 inpainting - [Evoto Hair Editor](https://www.evoto.ai/features/hair-part) — 商业产品效果参考(稀疏加密/发际线调整)