save
@@ -1139,10 +1139,11 @@ async def face_measure_v2(
|
||||
- 发际线类型 `hairline_type`(英文 key)
|
||||
- 顺序 `order`(本期固定 `1..N`,不排序)
|
||||
|
||||
> **female 走「换发型」模式**:生发图 `grown_image_base64` 由换发型(change_hair)
|
||||
> **female 走「换发型」模式**:1..5 的生发图 `grown_image_base64` 由换发型(change_hair)
|
||||
> + Flux-2 整帧重绘(= 接口12 final 管线,整帧美颜+整帧重绘)生成,其余参数用固化默认值。
|
||||
> **male 仍走原生发(ComfyUI add_hair)管线**。入参与返回结构不变。
|
||||
> female 依赖 change_hair 与 ComfyUI(:8188) 均在跑。
|
||||
> **6/7(bigflower/clasicalflower)与 male 一样走原生发(ComfyUI add_hair)管线**。
|
||||
> **male 全部走原生发(ComfyUI add_hair)管线**。入参与返回结构不变。
|
||||
> female 1..5 依赖 change_hair 与 ComfyUI(:8188) 均在跑。
|
||||
|
||||
{_image_fields_desc}
|
||||
|
||||
@@ -1150,15 +1151,15 @@ async def face_measure_v2(
|
||||
|
||||
---
|
||||
|
||||
- **gender**(必填):`male` / `female`。决定返回的贴图集合(female 5 张 / male 4 张)。
|
||||
- **gender**(必填):`male` / `female`。决定返回的贴图集合(female 7 张 / male 6 张)。
|
||||
非法或缺失返回 `1004`。
|
||||
- **hair_style**(必填):发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数量。
|
||||
`female`:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave;
|
||||
`male`:1=ellipse, 2=inverse_arc, 3=m, 4=straight。越界/非法返回 `1007`。
|
||||
`female`:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;
|
||||
`male`:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。越界/非法返回 `1007`。
|
||||
- **beauty_enabled**:本期保留但不生效。
|
||||
|
||||
`hairline_type` 取值:`ellipse` / `flower` / `heart` / `straight` / `wave`(female),
|
||||
`ellipse` / `m` / `straight` / `inverse_arc`(male)。
|
||||
`hairline_type` 取值:`ellipse` / `flower` / `heart` / `straight` / `wave` / `bigflower` / `clasicalflower`(female),
|
||||
`ellipse` / `m` / `straight` / `inverse_arc` / `heart` / `Softpetal`(male)。
|
||||
""",
|
||||
responses={
|
||||
200: {
|
||||
@@ -1197,7 +1198,7 @@ async def hair_grow(
|
||||
image_url: Optional[str] = Form(default=None, description="图片 URL"),
|
||||
image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"),
|
||||
gender: Optional[str] = Form(default=None, description="性别 male/female(必填)"),
|
||||
hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填),如 1,2,3。female:1-5 male:1-4"),
|
||||
hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填),如 1,2,3。female:1-7 male:1-6"),
|
||||
beauty_enabled: bool = Form(default=False, description="是否开启美颜(本期不生效)"),
|
||||
use_mask: bool = Form(default=True, description="是否启用 inpaint 遮罩(测试对比用)。false 时用干净原图生成(空遮罩,不烧模板线)"),
|
||||
prompt: str = Form(default="填充遮罩区域的头发", description="ComfyUI 提示词,会替换工作流节点60的文本"),
|
||||
@@ -1209,7 +1210,7 @@ async def hair_grow(
|
||||
return err(1004, "gender 必填且只能为 male / female")
|
||||
|
||||
# 2. hair_style 必填校验(解析逗号分隔,越界 → 1007)
|
||||
max_styles = {"female": 5, "male": 4}[gender]
|
||||
max_styles = {"female": 7, "male": 6}[gender]
|
||||
hair_styles = _parse_hair_styles(hair_style, max_styles)
|
||||
if hair_styles is None:
|
||||
return err(1007, f"hair_style 必填且为 1..{max_styles} 的整数(逗号分隔),收到 {hair_style!r}")
|
||||
@@ -1232,7 +1233,7 @@ async def hair_grow(
|
||||
from hairline.service import generate_grow_results_swap
|
||||
items = await run_in_threadpool(
|
||||
generate_grow_results_swap, image, hair_styles, _V2_FINAL_DEFAULTS,
|
||||
redraw_max_side=redraw_max_side, unet_name=flux_model)
|
||||
redraw_max_side=redraw_max_side, unet_name=flux_model, prompt=prompt)
|
||||
else:
|
||||
from hairline.service import generate_grow_results
|
||||
items = await run_in_threadpool(
|
||||
@@ -1295,7 +1296,7 @@ async def debug_grow_timing(
|
||||
return err(1008, "图片格式不支持(仅 JPG / PNG)")
|
||||
|
||||
try:
|
||||
max_styles = 5
|
||||
max_styles = 7
|
||||
hair_styles = _parse_hair_styles(hair_style, max_styles)
|
||||
if hair_styles is None:
|
||||
return err(1007, f"hair_style 必须为 1..{max_styles}")
|
||||
@@ -1584,9 +1585,10 @@ async def face_features(
|
||||
---
|
||||
|
||||
**入参**(同接口2:先选性别,再多选发型):
|
||||
- 必填 `gender`(`male`/`female`),决定发型集合(female 5 / male 4)。
|
||||
- 必填 `gender`(`male`/`female`),决定发型集合(female 7 / male 6)。
|
||||
- 必填 `hair_style`(发型序号,逗号分隔如 `1,2,3`),决定返回哪些发际线类型。缺失/越界/非法返回 `1007`。
|
||||
`female`:1=ellipse,2=flower,3=heart,4=straight,5=wave;`male`:1=ellipse,2=inverse_arc,3=m,4=straight。
|
||||
`female`:1=ellipse,2=flower,3=heart,4=straight,5=wave,6=bigflower,7=clasicalflower;
|
||||
`male`:1=ellipse,2=inverse_arc,3=m,4=straight,5=heart,6=Softpetal。
|
||||
- 可选 `use_mask` / `prompt`:同接口2 的生发控制参数。
|
||||
注:生发黑模板固定取 `hairline_texture_black/`(middle 档),即三档叠图分别用各自贴图、但生发目标固定 middle。
|
||||
- 可选 `generate_grow_image`(默认 `true`):是否生成生发效果图(ComfyUI 生发,全流程最耗时)。
|
||||
@@ -1666,7 +1668,7 @@ async def hairline_generate(
|
||||
image_url: Optional[str] = Form(default=None, description="图片 URL"),
|
||||
image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"),
|
||||
gender: Optional[str] = Form(default=None, description="性别 male/female(必填)"),
|
||||
hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填,如 1,2,3)。female:1-5 male:1-4"),
|
||||
hair_style: Optional[str] = Form(default=None, description="发型序号逗号分隔(必填,如 1,2,3)。female:1-7 male:1-6"),
|
||||
use_mask: bool = Form(default=True, description="生发是否启用 inpaint 遮罩(同接口2,测试对比用)"),
|
||||
prompt: str = Form(default="填充遮罩区域的头发", description="ComfyUI 提示词(同接口2),会替换工作流节点60的文本"),
|
||||
generate_grow_image: bool = Form(default=True, description="是否生成生发效果图(ComfyUI 生发,最耗时)。默认 true 出图;false 时跳过生发,各发型 grown_image 恒为 null,仅返回三档发际线叠图与中心点"),
|
||||
@@ -1675,7 +1677,7 @@ async def hairline_generate(
|
||||
return err(1004, "gender 必填且只能为 male / female")
|
||||
|
||||
# hair_style 必填(同接口2):解析逗号分隔,缺失/越界/非法 → 1007
|
||||
max_styles = {"female": 5, "male": 4}[gender]
|
||||
max_styles = {"female": 7, "male": 6}[gender]
|
||||
hair_styles = _parse_hair_styles(hair_style, max_styles)
|
||||
if hair_styles is None:
|
||||
return err(1007, f"hair_style 必填且为 1..{max_styles} 的整数(逗号分隔),收到 {hair_style!r}")
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
按 `face_ext.obj` 的 UV 把发际线贴图渲染到额头(预览)。生发:黑贴图渲染遮罩 → 调本机 **ComfyUI 8182** 的
|
||||
`add_hair.json`(Flux-2) 出图。**关键坑**:obj 是重排序,需 `INDEX_MAP_468` 把 MP 序→OBJ 序。
|
||||
返回 `results[].image_base64` + `grown_image_base64`。
|
||||
- `hair_style` 映射:female 1=ellipse 2=flower 3=heart 4=straight 5=wave;male 1=ellipse 2=inverse_arc 3=m 4=straight。
|
||||
- `hair_style` 映射:female 1=ellipse 2=flower 3=heart 4=straight 5=wave 6=bigflower 7=clasicalflower;male 1=ellipse 2=inverse_arc 3=m 4=straight 5=heart 6=Softpetal。female 1..5 走「换发型(change_hair)」+Flux-2 重绘管线;female 6/7 与 male 全部走原生发(ComfyUI add_hair)管线。
|
||||
|
||||
### 接口7 C端生发 v2 `/api/v1/hair/grow-v2`(worker)—— 接口2同款,add_hair2 工作流
|
||||
- **做什么**:与接口 2 完全一致(正面照 + `gender` + `hair_style` 逗号分隔多选 → N 组预览+生发图)。
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| gender | string | **是** | 性别:`male` / `female`。决定使用的发际线贴图集合 |
|
||||
| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight。越界/非法返回 `1007` |
|
||||
| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),最多不超过该性别的预设数。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。越界/非法返回 `1007` |
|
||||
| beauty_enabled | bool | 否 | 生发图是否带美颜效果,默认 false(当前阶段不生效) |
|
||||
| use_mask | bool | 否 | 是否启用 inpaint 遮罩,默认 `true`。`false` 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比 |
|
||||
| prompt | string | 否 | ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本 |
|
||||
@@ -278,7 +278,7 @@
|
||||
|------|------|------|
|
||||
| image_url | string | 发际线曲线**透明 PNG** URL(仅白色发际线曲线,透明底,**不含人物**,需前端叠加原图显示) |
|
||||
| grown_image_url | string | **生发后图片** URL(ComfyUI/Flux「植发 3 个月」效果图,完整人像照片) |
|
||||
| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`(female),`ellipse`/`m`/`straight`/`inverse_arc`(male) |
|
||||
| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`(male) |
|
||||
| order | int | 排序序号(当前阶段固定 `1..N`,按贴图顺序,暂不计算合适度) |
|
||||
|
||||
> ⚠️ 生发图由本机 ComfyUI(Flux-2,端口 8182)生成,**一次请求生成指定发型的 1 张、同步返回**。
|
||||
@@ -405,8 +405,8 @@
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| gender | string | **是** | 性别:`male` / `female`。决定发型集合(female 5 / male 4)。缺失/非法返回 `1004` |
|
||||
| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),决定返回哪些发际线类型。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight。缺失/越界/非法返回 `1007` |
|
||||
| gender | string | **是** | 性别:`male` / `female`。决定发型集合(female 7 / male 6)。缺失/非法返回 `1004` |
|
||||
| hair_style | string | **是** | 发型序号,**逗号分隔多选**(如 `1,2,3`),决定返回哪些发际线类型。female:1=ellipse, 2=flower, 3=heart, 4=straight, 5=wave, 6=bigflower, 7=clasicalflower;male:1=ellipse, 2=inverse_arc, 3=m, 4=straight, 5=heart, 6=Softpetal。缺失/越界/非法返回 `1007` |
|
||||
| use_mask | bool | 否 | 生发是否启用 inpaint 遮罩,默认 `true`。`false` 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比 |
|
||||
| prompt | string | 否 | ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本 |
|
||||
| generate_grow_image | bool | 否 | 是否生成生发效果图(ComfyUI 生发,全流程最耗时),默认 `true`。传 `false` 时跳过生发,各发型 `grown_image_*` 恒为 `null`,仅返回三档发际线叠图与中心点,可大幅降低耗时 |
|
||||
@@ -427,7 +427,7 @@
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`(female),`ellipse`/`m`/`straight`/`inverse_arc`(male) |
|
||||
| hairline_type | string | 发际线类型 key:`ellipse`/`flower`/`heart`/`straight`/`wave`/`bigflower`/`clasicalflower`(female),`ellipse`/`m`/`straight`/`inverse_arc`/`heart`/`Softpetal`(male) |
|
||||
| image_middle_url | string | middle 档发际线曲线**透明 PNG** URL(仅曲线,透明底,**不含人物**,需叠加原图显示) |
|
||||
| image_high_url | string | high 档发际线曲线**透明 PNG** URL(同上,high 档曲线) |
|
||||
| image_low_url | string | low 档发际线曲线**透明 PNG** URL(同上,low 档曲线) |
|
||||
|
||||
@@ -29,7 +29,8 @@ import logging
|
||||
logger = logging.getLogger("hair.worker")
|
||||
|
||||
# 接口2 女性发型 key → change_hair hair_id(chang_*)映射:换发型+Flux-2 整帧重绘用。
|
||||
# 与接口12 final 的 5 型一一对应。
|
||||
# 与接口12 final 的 5 型一一对应。female 6/7(bigflower/clasicalflower)无对应 LoRA,
|
||||
# 走与男性一致的原生生发(ComfyUI add_hair)管线,故不在本表。
|
||||
_FEMALE_KEY_TO_CHANG = {
|
||||
"ellipse": "chang_tuoyuan", # 椭圆
|
||||
"flower": "chang_huaban", # 花瓣
|
||||
@@ -38,6 +39,16 @@ _FEMALE_KEY_TO_CHANG = {
|
||||
"wave": "chang_bolang", # 波浪
|
||||
}
|
||||
|
||||
# 发际线贴图显式顺序表:决定 hair_style 序号(1-indexed)。
|
||||
# 不再依赖文件名字母序——字母序会因新增/重命名文件而错位,破坏现有前端/客户端取值。
|
||||
# key 须与 _gender_key 派生结果一致(已去空格):如 "inverse_arc"(源 man_ inverse_arc.png)、
|
||||
# "Softpetal"(源 man_Soft petal.png,大写 S 保留)。表外未知 key 兜底排到末尾。
|
||||
_HAIRSTYLE_ORDER = {
|
||||
"female": ["ellipse", "flower", "heart", "straight", "wave",
|
||||
"bigflower", "clasicalflower"], # 1..7
|
||||
"male": ["ellipse", "inverse_arc", "m", "straight", "heart", "Softpetal"], # 1..6
|
||||
}
|
||||
|
||||
_REPO = os.path.dirname(os.path.dirname(__file__))
|
||||
_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture")
|
||||
_BLACK_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture_black")
|
||||
@@ -130,10 +141,13 @@ def _gender_key(stem: str):
|
||||
|
||||
|
||||
def get_texture_map(level: str = "middle") -> dict:
|
||||
"""扫描指定档位贴图目录建 {gender: [(key, path)]},按 key 排序、按档位缓存。
|
||||
"""扫描指定档位贴图目录建 {gender: [(key, path)]},按显式顺序表排序、按档位缓存。
|
||||
|
||||
level:middle(默认) / high / low,分别对应 hairline_texture[/_high|/_low]。
|
||||
文件名规范化去空格(如 `man_ inverse_arc.png` → key `inverse_arc`)。
|
||||
|
||||
排序依据 _HAIRSTYLE_ORDER:表内 key 按表序、表外未知 key 兜底排到末尾(再按字母序),
|
||||
保证新增/重命名文件不会打乱现有 hair_style 序号。
|
||||
"""
|
||||
if level not in _TEXTURE_DIRS:
|
||||
raise ValueError(f"hairline_level 必须是 middle/high/low,收到 {level!r}")
|
||||
@@ -147,7 +161,9 @@ def get_texture_map(level: str = "middle") -> dict:
|
||||
if gender:
|
||||
mapping[gender].append((key, path))
|
||||
for g in mapping:
|
||||
mapping[g].sort(key=lambda kp: kp[0])
|
||||
order = _HAIRSTYLE_ORDER.get(g, [])
|
||||
idx = {k: i for i, k in enumerate(order)}
|
||||
mapping[g].sort(key=lambda kp: (idx.get(kp[0], len(idx)), kp[0]))
|
||||
_texture_maps[level] = mapping
|
||||
return mapping
|
||||
|
||||
@@ -211,7 +227,7 @@ def generate_grow_results(image_bgr: np.ndarray, gender: str, use_mask: bool = T
|
||||
unet_name: str | None = None):
|
||||
"""指定发际线类型:发际线透明叠图(白线 RGBA) + 生发图(ComfyUI)。
|
||||
|
||||
hair_styles(1-indexed 列表):指定生成哪几张发际线(按贴图排序)。female: 1..5,male: 1..4。
|
||||
hair_styles(1-indexed 列表):指定生成哪几张发际线(按贴图排序)。female: 1..7,male: 1..6。
|
||||
为 None 时生成全部(兼容旧调用)。
|
||||
use_mask(默认 True):是否启用 inpaint 遮罩,用于测试对比(同接口3)。
|
||||
False 时用**干净原图 + 空遮罩**送 ComfyUI(不烧黑色模板线)。
|
||||
@@ -285,15 +301,20 @@ def generate_grow_results(image_bgr: np.ndarray, gender: str, use_mask: bool = T
|
||||
def generate_grow_results_swap(image_bgr: np.ndarray, hair_styles: list[int] | None,
|
||||
redraw_defaults: dict,
|
||||
redraw_max_side: int | None = None,
|
||||
unet_name: str | None = None):
|
||||
"""接口2 女性专用:发际线透明叠图(同 generate_grow_results)+ 换发型重绘图。
|
||||
unet_name: str | None = None,
|
||||
prompt: str | None = None):
|
||||
"""接口2 女性专用:发际线透明叠图(同 generate_grow_results)+ 生发图。
|
||||
|
||||
grown 图来源(新流程):对每个选中发型把 female key 映射到 change_hair 的 chang_* hair_id,
|
||||
调 face_analysis.hairline_grow.generate_hairline_redraw(= 接口12 final 管线,参数用
|
||||
redraw_defaults)拿到 ④ final(接缝融合基底)+ ⑤-② 纯红遮罩 PNG,再**后端直接调
|
||||
ComfyUI**(0716add-hair-api.json 工作流)完成发际线带重绘,重绘结果作为生发图。
|
||||
生发图来源按发型分两路:
|
||||
- 换发型(chang_* 表内,1..5):female key → change_hair 的 chang_* hair_id,调
|
||||
face_analysis.hairline_grow.generate_hairline_redraw(= 接口12 final 管线,参数用
|
||||
redraw_defaults)拿到 ④ final(接缝融合基底)+ ⑤-② 纯红遮罩 PNG,再**后端直接调
|
||||
ComfyUI**(0716add-hair-api.json 工作流)完成发际线带重绘。
|
||||
- 原生生发(表外,6/7 bigflower/clasicalflower 等):无对应 change_hair LoRA,改走与男性
|
||||
一致的原生生发(ComfyUI add_hair),由 _grow_native_one 完成(黑模板 + inpaint 遮罩)。
|
||||
|
||||
overlay 仍是发际线曲线透明层(与 generate_grow_results 完全一致)。
|
||||
prompt 仅用于原生生发分支(换发型分支的提示词由 redraw 流程内部固定)。
|
||||
Returns: list[dict] {"hairline_type","order","overlay","grown_png"(jpg bytes 或 None)};
|
||||
无人脸返回 None。单个发型换发型/重绘失败时 grown_png=None,不抛异常。
|
||||
"""
|
||||
@@ -338,7 +359,10 @@ def generate_grow_results_swap(image_bgr: np.ndarray, hair_styles: list[int] | N
|
||||
grown_png = None
|
||||
chang_id = _FEMALE_KEY_TO_CHANG.get(key)
|
||||
if chang_id is None:
|
||||
logger.warning("接口2 换发型:female key=%s 无对应 chang_id,跳过生发图", key)
|
||||
# 无对应 change_hair LoRA(如 bigflower/clasicalflower)→ 走与男性一致的原生生发
|
||||
logger.info("接口2 女 key=%s 无 chang_id,走原生生发(ComfyUI add_hair)", key)
|
||||
grown_png = _grow_native_one(image_bgr, ctx, white_path,
|
||||
prompt=prompt, unet_name=unet_name)
|
||||
else:
|
||||
try:
|
||||
import time as _t
|
||||
@@ -409,6 +433,32 @@ def _grow_from_texture(image_bgr: np.ndarray, ctx: dict, white_path: str | None,
|
||||
return None
|
||||
|
||||
|
||||
def _grow_native_one(image_bgr: np.ndarray, ctx: dict, white_path: str,
|
||||
prompt: str | None = None, unet_name: str | None = None):
|
||||
"""对单个发际线做原生生发(ComfyUI add_hair),与男性 generate_grow_results 一致。
|
||||
|
||||
接口2 女性新发型(bigflower/clasicalflower 等)无对应 change_hair LoRA,改走此路径:
|
||||
黑模板 → build_inpaint_mask → 限边(_prep_comfy_input)→ comfyui.run(front=True)。
|
||||
失败返回 None,不抛异常。结果按限边前原图尺寸放大回原尺寸(仅展示对齐)。
|
||||
"""
|
||||
try:
|
||||
h, w = image_bgr.shape[:2]
|
||||
black = load_texture_rgba(_black_texture_path(white_path))
|
||||
marked, mask = build_inpaint_mask(
|
||||
image_bgr, ctx["landmarks"], ctx["parse_map"], ctx["points"], black)
|
||||
m_s, msk_s, gsc = _prep_comfy_input(marked, mask)
|
||||
buf = io.BytesIO()
|
||||
compose_comfy_rgba(m_s, msk_s).save(buf, format="PNG", compress_level=1)
|
||||
# front=True:接口2 时延敏感,插到 ComfyUI 队列最前
|
||||
grown_png = comfyui.run(buf.getvalue(), prompt=prompt, front=True, unet_name=unet_name)
|
||||
if gsc < 1.0 and grown_png:
|
||||
grown_png = _upscale_png_to(grown_png, w, h)
|
||||
return grown_png
|
||||
except Exception as e: # noqa: BLE001 单张失败不拖垮整请求
|
||||
logger.warning("接口2 女原生生发图失败:%s", e)
|
||||
return None
|
||||
|
||||
|
||||
def generate_hairline_pngs(image_bgr: np.ndarray, gender: str,
|
||||
hair_styles: list[int], use_mask: bool = True,
|
||||
prompt: str | None = None,
|
||||
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
@@ -237,12 +237,16 @@ const HAIR_STYLES = {
|
||||
{ value:'3', label:'heart 心形' },
|
||||
{ value:'4', label:'straight 直线形' },
|
||||
{ value:'5', label:'wave 波浪形' },
|
||||
{ value:'6', label:'bigflower 大花瓣型' },
|
||||
{ value:'7', label:'clasicalflower 古典花瓣型' },
|
||||
],
|
||||
male: [
|
||||
{ value:'1', label:'ellipse 椭圆形' },
|
||||
{ value:'2', label:'inverse_arc 倒弧形' },
|
||||
{ value:'3', label:'m M形' },
|
||||
{ value:'4', label:'straight 直线形' },
|
||||
{ value:'5', label:'heart 桃心形' },
|
||||
{ value:'6', label:'Softpetal 柔和花瓣形' },
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<div class="file-input"><input type="file" id="imageFile" accept="image/jpeg,image/png,.jpg,.jpeg,.png"></div>
|
||||
<div class="form-group">
|
||||
<label>性别</label>
|
||||
<select id="gender" onchange="onGenderChange()"><option value="female" selected>👩 Female(5种)</option><option value="male">👨 Male(4种)</option></select>
|
||||
<select id="gender" onchange="onGenderChange()"><option value="female" selected>👩 Female(7种)</option><option value="male">👨 Male(6种)</option></select>
|
||||
</div>
|
||||
<div class="form-group" style="align-items:flex-start">
|
||||
<label style="padding-top:3px">发型 *</label>
|
||||
@@ -174,12 +174,16 @@ const HAIR_STYLES = {
|
||||
{ value:'3', label:'3. heart 心形' },
|
||||
{ value:'4', label:'4. straight 直线' },
|
||||
{ value:'5', label:'5. wave 波浪' },
|
||||
{ value:'6', label:'6. bigflower 大花瓣型' },
|
||||
{ value:'7', label:'7. clasicalflower 古典花瓣型' },
|
||||
],
|
||||
male: [
|
||||
{ value:'1', label:'1. ellipse 椭圆' },
|
||||
{ value:'2', label:'2. inverse_arc 倒弧' },
|
||||
{ value:'3', label:'3. m M形' },
|
||||
{ value:'4', label:'4. straight 直线' },
|
||||
{ value:'5', label:'5. heart 桃心形' },
|
||||
{ value:'6', label:'6. Softpetal 柔和花瓣形' },
|
||||
]
|
||||
};
|
||||
|
||||
|
||||