Files
hair/docs/接口文档.md
T

60 KiB
Raw Blame History

旷视五个接口 — 接口文档(输入 / 输出定义)

本文档依据《旷视具体需求.docx》整理,描述各接口的输入与输出。 文中标记为 【待确认】 的内容为需求文档中尚未明确、需与对方对齐的点。

当前为第一版 Mock 服务:所有接口已上线,但不做真实算法计算,统一返回下文「响应示例」中的默认值;所有图片字段均返回示例图 https://hair.xiangsilian.com/static/sample.jpg。真实逻辑后续接入。


服务地址与接口路径

  • Base URL:https://hair.xiangsilian.com
  • 在线接口文档(Swagger):https://hair.xiangsilian.com/docs
接口 方法 路径
1 四庭七眼测量 POST /api/v1/face/measure
6 四庭七眼测量 v2 POST /api/v1/face/measure-v2
2 C 端生发 POST /api/v1/hair/grow
22 生发密度与发际线高度 POST /api/v1/hair/grow-22
3 B 端生发 POST /api/v1/hair/grow-b
72 B 端五个关键点 POST /api/v1/face/b-end-points
4 用户特征 POST /api/v1/face/features
42号接口-加两个特征点 POST /api/v1/face/features-42
5 发际线 PNG 生成 POST /api/v1/hairline/generate
52 发际线新规则与裁切 POST /api/v1/hairline/generate-52

通用约定

GPU worker的所有动态接口均启用IP限制:允许本机及ip_access.json白名单(当前为网关IP 49.232.51.171),其他来源返回HTTP403、code=1010;静态页面与图片除外。按直接连接worker的IP判断,网关不启用此限制,已有鉴权继续有效。

以下约定适用于全部 5 个接口(最终以联调为准)。

请求

项目 约定
协议 HTTPS
请求方式 POST
图片传参方式 三选一,三种都支持:① multipart/form-data 上传文件、② 图片 URL、③ base64 字符串
字符编码 UTF-8
坐标基准 默认以原图像素为基准;接口52开启预处理时使用响应中的处理后底图坐标(原点为左上角,x向右、y向下)

图片传参字段(三者严格互斥,必须且只能传其一;传了 0 个或 ≥2 个均报错):

参数 类型 说明
image_file file 上传文件(multipart/form-data)
image_url string 图片 URL
image_base64 string 图片 base64 字符串,需带前缀,如 data:image/png;base64,xxxx

图片输入要求(接口 1/2/3/4/5 通用)

项目 要求
图片类型 用户正面照(人像)
人脸数量 默认仅支持单人;若检测到 2 或 3 张人脸(即多人),报错并提示客户端
单文件大小 ≤ 1 MB
最低分辨率 720 × 1024
最大分辨率 2160 × 3840
格式 目前仅支持 JPG / PNG

统一响应结构

{
  "code": 0,
  "message": "success",
  "request_id": "唯一请求标识",
  "data": { }
}
字段 类型 说明
code int 0 表示成功,非 0 表示失败
message string 结果描述 / 错误原因
request_id string 请求追踪 ID
data object 业务数据,结构见各接口

通用错误码(识别失败时返回,见需求文档)

code message 说明
1001 无法识别人像 图片中未检测到人脸
1002 人像分辨率过低 低于最低分辨率要求
1003 角度问题,非正面照 非正面 / 角度过大
1004 gender 必填/非法 接口2/5/52/7 的 gender 缺失或非 male/female
1005 检测到多张人脸 默认仅支持单人,检测到 2 人或以上时返回
1006 文件超出大小限制 单文件超过 1 MB
1007 图片参数错误 file / url / base64 未传,或同时传了多个(三者严格互斥)
1008 图片格式不支持 非 JPG / PNG
1010 来源IP不允许 仅GPU worker:直连IP不在本机/白名单内,或来源/白名单配置无效;HTTP403

接口 1:四庭七眼测量标注接口

说明:输入用户照片,输出一张标注好四庭七眼数据的 PNG 图片(不包含人物本体,仅标注图层),同时返回四庭、七眼的比例与厘米数值。

请求:POST /api/v1/face/measure

输入

图片参数见「通用约定 → 图片传参字段」(image_file / image_url / image_base64 三选一)。本接口无其他专属参数。

输出(data)

字段 类型 说明
annotated_image_url string 标注好数据的 PNG 图片(仅标注图层,不含人物)
face_total_height_cm number 全脸总高度(cm)
four_courts object 四庭数据,见下表
seven_eyes object 七眼数据,见下表
landmarks object 关键分界点坐标(头顶 / 发际线 / 眉心 / 鼻翼下缘 / 下巴尖),原图像素坐标
vertical_lines object 标注图竖线坐标,见下表。与标注 PNG 上的竖线同一套几何
left_position object MediaPipe 21 号关键点坐标(左脸定位点),原图像素:{ "x": int, "y": int }
right_position object MediaPipe 251 号关键点坐标(右脸定位点,与 21 号镜像),原图像素:{ "x": int, "y": int }

four_courts(四庭,自上而下):

字段 类型 说明
top_court_cm number 顶庭长度(cm),示例:约占全脸高度 22%
upper_court_cm number 上庭长度(cm),约占 25%
middle_court_cm number 中庭长度(cm),约占 28%
lower_court_cm number 下庭长度(cm),约占 25%
ratios object 各庭占全脸高度的百分比

seven_eyes(七眼,横向):

字段 类型 说明
eye_width_cm number 单眼宽度(cm)
face_width_cm number 脸宽(cm)
inter_eye_distance_cm number 两眼间距(cm)
ratios object 七眼各段占脸宽的比例
eye1 number | null 从左到右第 1 段宽度(cm):人头最左 → 左脸颊(左耳外侧段)。该侧耳朵不可见时为 null
eye2 number 从左到右第 2 段宽度(cm):左脸颊 → 左眼外角
eye3 number 从左到右第 3 段宽度(cm):左眼外角 → 左眼内角(左眼宽度)
eye4 number 从左到右第 4 段宽度(cm):左眼内角 → 右眼内角(两眼间距)
eye5 number 从左到右第 5 段宽度(cm):右眼内角 → 右眼外角(右眼宽度)
eye6 number 从左到右第 6 段宽度(cm):右眼外角 → 右脸颊
eye7 number | null 从左到右第 7 段宽度(cm):右脸颊 → 人头最右(右耳外侧段)。该侧耳朵不可见时为 null

eye1~eye7 为从左到右共 7 段宽度,与标注图竖线一一对应。最左/最右端线取自耳朵分割外缘;某侧耳朵被头发或侧脸遮挡(不可见)时该侧端线省略,对应 eye1 或 eye7 为 null(键始终保留),实际有效段为 5 或 6 段。eye3/eye5 为左右眼宽、eye4 为两眼间距,与 eye_width_cm / inter_eye_distance_cm 语义一致。eye1/eye7 的厘米数由 vertical_lines 里对应端点的 x 相减得到。

vertical_lines(竖线,原图像素,原点左上,x 向右,y 向下):

字段 类型 说明
y_top int 竖线共用上端。接口 1 在头顶之上,伸出 max(6, round(短边 × 0.03)) 像素,可能略小于 0
y_bottom int 竖线共用下端。接口 1 在下巴尖之下,伸出同样像素,可能略大于图高
lines array 从左到右实际画出的竖线。每项 { "name": string, "x": int }

lines[].name 从左到右:

name 竖线
left_head_edge 人头最左(耳朵外缘)。该侧耳朵不可见时不出现,此时 eye1 为 null
left_cheek 左脸颊
left_eye_outer 左眼外角
left_eye_inner 左眼内角
right_eye_inner 右眼内角
right_eye_outer 右眼外角
right_cheek 右脸颊
right_head_edge 人头最右(耳朵外缘)。该侧耳朵不可见时不出现,此时 eye7 为 null

标注图片(UI)规范

项目 要求
颜色 字体及所有线/箭头 #FFFFFF 100%,透明底
尺寸 字号/线宽/虚线/箭头按图片短边自适应缩放(非固定 pt)
横线 5 条分界线(头顶/发际线/眉心/鼻翼下缘/下巴尖),两端渐变消失并略超出最外侧竖线;线名在线右上方
竖线 人头最左 + 七眼 6 点 + 人头最右(最外两条取自头发分割轮廓),两端渐变消失并略超出头顶/下巴
数值排布 四庭数值(名 + 数值两行,不带 cm)统一在图片左侧呈现;七眼段宽上下穿插展示;底部统一标「单位cm」
线样式 段宽/庭高用虚线 + 实心三角双箭头标示(箭头尖端落在虚线两端)

响应示例(当前 Mock 返回值)

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "annotated_image_url": "https://hair.xiangsilian.com/static/sample.jpg",
    "face_total_height_cm": 13.76,
    "four_courts": {
      "top_court_cm": 3.44,
      "upper_court_cm": 3.44,
      "middle_court_cm": 3.44,
      "lower_court_cm": 3.44,
      "ratios": { "top_court": 0.25, "upper_court": 0.25, "middle_court": 0.25, "lower_court": 0.25 }
    },
    "seven_eyes": {
      "eye_width_cm": 3.44,
      "face_width_cm": 24.08,
      "inter_eye_distance_cm": 3.44,
      "ratios": { "eye_width": 0.143, "inter_eye_distance": 0.143 },
      "eye1": 3.44, "eye2": 3.44, "eye3": 3.44, "eye4": 3.44,
      "eye5": 3.44, "eye6": 3.44, "eye7": 3.44
    },
    "landmarks": {
      "hair_top": { "x": 540, "y": 120 },
      "hairline": { "x": 540, "y": 430 },
      "brow_center": { "x": 540, "y": 740 },
      "nose_bottom": { "x": 540, "y": 1050 },
      "chin_tip": { "x": 540, "y": 1360 }
    },
    "vertical_lines": {
      "y_top": 98, "y_bottom": 1410,
      "lines": [
        { "name": "left_head_edge", "x": 120 },
        { "name": "left_cheek", "x": 210 },
        { "name": "left_eye_outer", "x": 310 },
        { "name": "left_eye_inner", "x": 420 },
        { "name": "right_eye_inner", "x": 560 },
        { "name": "right_eye_outer", "x": 670 },
        { "name": "right_cheek", "x": 780 },
        { "name": "right_head_edge", "x": 890 }
      ]
    }
  }
}

接口 6:四庭七眼测量 v2 接口

说明:基于接口 1的变体。与接口 1 的差异:

  • 去顶庭:不画头顶横线、不返回顶庭数据。four_courts 仅含上/中/下庭,landmarks 无 hair_top,face_total_height_cm 为三庭之和(不含顶庭)。
  • 竖线范围:纵向竖线从发际线画到下巴尖(接口 1 为头顶→下巴尖)。
  • 不画人头最左/最右端线:仅画七眼 6 点(左脸颊/左眼外角/左眼内角/右眼内角/右眼外角/右脸颊)共 5 段标尺,不取头发轮廓的头部端线(接口 1 会多出最左/最右 2 条头部端线、共 7 段)。
  • 其余(实心三角箭头、虚线样式、字体、单位cm、七眼数据)与接口 1 一致。

请求:POST /api/v1/face/measure-v2

输入

与接口 1 完全相同。图片参数见「通用约定 → 图片传参字段」(image_file / image_url / image_base64 三选一)。本接口无其他专属参数。

输出(data)

字段 类型 说明
annotated_image_url string 标注图层 PNG URL(透明底,仅标注线/文字,不含人物)
face_total_height_cm number 面部总高度(cm)= 上庭 + 中庭 + 下庭(不含顶庭)
four_courts object 三庭数据(上/中/下庭,各含 cm 与 ratio;无顶庭)
seven_eyes object 七眼数据(眼宽/脸宽/两眼间距 cm + 占比 ratios + eye2~eye6 共 5 段宽度)
landmarks object 四个关键点像素坐标(发际线/眉心/鼻翼下缘/下巴尖)
vertical_lines object 标注图竖线坐标。结构同接口 1,但 y_top/y_bottom 为发际线到下巴尖(不伸出),lines 只有中间 6 条,无 left_head_edge / right_head_edge
left_position object MediaPipe 21 号关键点坐标(左脸定位点),原图像素:{ "x": int, "y": int }
right_position object MediaPipe 251 号关键点坐标(右脸定位点,与 21 号镜像),原图像素:{ "x": int, "y": int }

接口6 是三庭五眼:four_courts/landmarks 不含顶庭与头顶点(无 top_court_cm/hair_top);seven_eyes 只含 eye2~eye6(左脸颊/左眼/两眼间距/右眼/右脸颊,5 段),无 eye1/eye7(耳外段需头发轮廓端线,仅接口1 有)。

响应示例

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "annotated_image_url": "https://hair.xiangsilian.com/static/sample.jpg",
    "face_total_height_cm": 10.32,
    "four_courts": {
      "upper_court_cm": 3.44, "middle_court_cm": 3.44, "lower_court_cm": 3.44,
      "ratios": { "upper_court": 0.333, "middle_court": 0.333, "lower_court": 0.333 }
    },
    "seven_eyes": {
      "eye_width_cm": 3.44, "face_width_cm": 24.08, "inter_eye_distance_cm": 3.44,
      "ratios": { "eye_width": 0.143, "inter_eye_distance": 0.143 },
      "eye2": 3.0, "eye3": 3.44, "eye4": 3.44, "eye5": 3.44, "eye6": 3.0
    },
    "landmarks": {
      "hairline": { "x": 540, "y": 430 },
      "brow_center": { "x": 540, "y": 740 },
      "nose_bottom": { "x": 540, "y": 1050 },
      "chin_tip": { "x": 540, "y": 1360 }
    },
    "vertical_lines": {
      "y_top": 430, "y_bottom": 1360,
      "lines": [
        { "name": "left_cheek", "x": 210 },
        { "name": "left_eye_outer", "x": 310 },
        { "name": "left_eye_inner", "x": 420 },
        { "name": "right_eye_inner", "x": 560 },
        { "name": "right_eye_outer", "x": 670 },
        { "name": "right_cheek", "x": 780 }
      ]
    }
  }
}

接口 2:C 端生发接口

说明:输入用户正面照 + 性别 + 发型序号(可多选),按指定发际线类型渲染发际线曲线透明 PNG + 生发图。

每个方案返回两张图:image_url=「发际线曲线透明 PNG(仅白色曲线,透明底,需叠加原图显示)」;grown_image_url= 经 ComfyUI/Flux 的「植发 3 个月生发后图片」(完整人像照片)。两者均已实现,实现简述见 实现说明.md。

请求:POST /api/v1/hair/grow

输入

图片参数见「通用约定 → 图片传参字段」。专属参数:

参数 类型 必填 说明
gender string 是 性别:male / female。决定使用的发际线贴图集合
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, 7=wave。越界/非法返回 1007
beauty_enabled bool 否 生发图是否带美颜效果,默认 false(当前阶段不生效)
use_mask bool 否 是否启用 inpaint 遮罩,默认 true。false 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比。仅对原生发(male / female 6/7)管线生效
prompt string 否 ComfyUI 提示词,默认「填充遮罩区域的头发,人物增加一点磨皮」,会替换工作流节点 60 的文本。所有分支生效(male / female 6/7 原生生发,female 1..5 换发型后的发际线带重绘;不进 change_hair)。注:非默认提示词会使 ComfyUI 的 CLIP 条件缓存失效,换词后首次请求明显变慢(实测 45s vs 命中缓存 8s),相同提示词的后续请求恢复正常
flux_model string 否 Flux 模型文件名(如 flux-2-klein-9b-Q5_K_M.gguf)。缺省用工作流默认(9B-Q4_K_M);.gguf 自动切 UnetLoaderGGUF 并同步配套 qwen CLIP
redraw_max_side int 否 female 1..5 重绘管线送模型前的长边上限像素。缺省=服务端默认(REDRAW_MAX_SIDE,当前 1024);0=不缩图(原图直送,更慢)

输出(data)

results:发际线方案数组,数量 = 所选发型数。每个元素:

字段 类型 说明
image_url string 发际线曲线透明 PNG URL(仅白色发际线曲线,透明底,不含人物,需前端叠加原图显示)
grown_image_url string 生发后图片 URL(ComfyUI/Flux「植发 3 个月」效果图,完整人像照片)
hairline_type string 发际线类型 key:ellipse/flower/heart/straight/wave/bigflower/clasicalflower(female),ellipse/m/straight/inverse_arc/heart/Softpetal/wave(male)
order int 排序序号(当前阶段固定 1..N,按贴图顺序,暂不计算合适度)

⚠️ 生发图由本机 ComfyUI(Flux-2,端口 8188)生成,一次请求生成指定发型的 1 张、同步返回; female 1..5 的生发图另依赖 change_hair 换发型服务(:8801)。 worker 侧返回 image_base64 / grown_image_base64, 网关落盘后改写为上表的 image_url / grown_image_url。

💡 image_url 为透明底 PNG,前端需用绝对定位叠加到原图上显示(参考测试页的 .img-stack 叠加结构)。

响应示例

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "results": [
      { "image_url": "https://hair.xiangsilian.com/static/annotations/uuid1.png", "grown_image_url": "https://hair.xiangsilian.com/static/annotations/grown1.png", "hairline_type": "ellipse", "order": 1 },
      { "image_url": "https://hair.xiangsilian.com/static/annotations/uuid2.png", "grown_image_url": "https://hair.xiangsilian.com/static/annotations/grown2.png", "hairline_type": "flower", "order": 2 }
    ]
  }
}

识别失败时返回通用错误码(1001 / 1002 / 1003 等)。gender 缺失或非法值返回 1004;本接口已改为必填入参,不再自动判别性别。


接口 22 生发密度与发际线高度

POST /api/v1/hair/grow-22 使用接口 2 的图片输入、gender、hair_style 和返回结构。

表单字段 默认值 取值和效果
hair_density 必填 sparse 稀疏、normal 正常、dense 浓密。至少提交一档,多选时重复提交同名字段。提示词为「填充遮罩区域的头发,发量{描述},人物增加一点磨皮」,三档描述依次为「稀疏」「正常」「适中偏多」。
hairline_height 0 [-1, 1],-1 最高,0 正常,1 最低。端点相对正常位置移动眉心到下巴垂直像素距离的 10%。非零时须启用 use_mask。

每个发型用一张正常高度贴图渲染预览,按请求高度移动预览线。女性 1–5 号在 WebUI 出图后移动贴回区域和重绘带。其他发型用移动后的预览曲线生成生发遮罩。

例如选择两档时,表单传 hair_density=sparse 和 hair_density=dense。每个「密度 × 发型」组合返回一项,结果的 hair_density 字段标明对应档位。

生发图与透明发际线 PNG 对齐到输入照片尺寸。测试页运行在本机 Worker 的 /static/test_interface22.html,扶正裁切预览依赖接口 52。

接口 3:B 端生发接口

说明:医生/操作端在用户照片上用马克笔标注目标发际线后,只需上传这一张划线图。系统检测划线 → 据此生成生发后图片。

请求:POST /api/v1/hair/grow-b

输入

划线图片支持「文件 / URL / base64」三选一(字段:marked_image_file / marked_image_url / marked_image_base64)。 不需要原始照片(划线图本身就是用户照片 + 手绘线)。

参数 类型 必填 说明
marked_image_* file / string 是 已用马克笔标注发际线的图片,三选一
use_mask bool 否 是否画发际线,默认 true。false 时跳过划线检测、直接送划线图,模型仅凭手绘黑线生发,供测试对比
prompt string 否 ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本

输出(data)

字段 类型 说明
hair_growth_image_url string 生发后图片(检测划线 → ComfyUI/Flux「植发 3 个月」效果)。worker 返回 hair_growth_image_base64
hairline_type string 发际线形,手绘为定制,固定 "custom"

未检测到划线(或无人脸)返回 1001。

响应示例

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "hair_growth_image_url": "https://hair.xiangsilian.com/static/annotations/grown.png",
    "hairline_type": "custom"
  }
}

接口 4:用户特征接口

说明:输入用户照片,由火山方舟 豆包视觉模型(doubao-seed-1-6-vision)分析,输出一大批面部特征。

请求:POST /api/v1/face/features

输入

图片参数见「通用约定 → 图片传参字段」。本接口无其他专属参数。

输出(data)

data.features 是一个 JSON 字符串(不是对象,客户端 JSON.parse() 后用),仅含以下 6 个英文字段:

字段 说明
face_shape 脸形(脸型)
eyebrow_shape 眉形
facial_age 面部年龄(区间字符串,如"18-25岁")
dynamic_static_type 动静类型(静态型/动态型)
gender 性别(男/女)
gene_style 基因风格(如"自然型")

无人脸返回 1001(据 doubao「图片是否有人脸」判定)。⚠️ 本接口是唯一调外网云模型的接口, worker 需可访问 ark.cn-beijing.volces.com;API Key 走 worker 配置/环境变量。

响应示例

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "features": "{\"face_shape\":\"鹅蛋脸\",\"eyebrow_shape\":\"平眉\",\"facial_age\":\"18-25岁\",\"dynamic_static_type\":\"静态型\",\"gender\":\"女\",\"gene_style\":\"少年型\"}"
  }
}

features 为字符串形式的 JSON,固定上述 6 个字段。


接口 72:B 端五个关键点

POST /api/v1/face/b-end-points 接受三选一图片参数 image_file、image_url、image_base64。复用接口 52 的扶正裁切与虹膜/眼宽厘米估算,返回坐标以处理后底图为准。

点号 位置 标注
1 MediaPipe 4 白点
2 HL center 白点
3 HL center 向画面右侧水平偏移 2 cm 白点
4 HL left 白点
5 HL left left 白点
6 MediaPipe 446 白点,兼作射线锚点

六个白点的直径相同。标注层包含三条从起点向目标方向延伸并逐渐变淡的白色虚线(2→1、4→6、5→6),以及 2→3 白色虚线段。2→1 射线比默认可见长度短 15%,5→6 射线的绘制长度比默认长度多 30%,可见范围以图像边界为限。四个距离文字分别放在 2–1 中点左侧、2–3 中点上方、4–6 中点左侧和 5–6 中点右侧,距离保留一位小数,2–3 固定显示 2.0 CM。

data 字段 内容
input_image_url 扶正裁切后的底图
annotated_image_url 与底图同尺寸的透明 PNG 标注层
points 按字符串点号 "1" 到 "6" 索引的像素坐标 {x, y}
measurements_cm 四个距离,以 2-1、2-3、4-6、5-6 索引
image_size 处理后尺寸 {width, height}
coordinate_space processed_image
px_per_cm 估算的每厘米像素数

Worker 直连时图片字段使用 _base64 后缀。检测不到人脸返回 1001,非正面或标注所需点位无法取得时返回 1003,图片无法解码返回 1008。

对外 42、52、72 的客户端登录、令牌验证和刷新均由 main 分支的网关处理。网关将 52 和 72 转发至本分支的 Worker,Worker 通过直连来源 IP 白名单授权。对外测试请使用网关同源的测试页。


42号接口-加两个特征点

请求 POST /api/v1/face/features-42,使用 multipart/form-data。

请求字段 类型 说明
image_file 文件 上传 JPG 或 PNG
image_url 字符串 网关可访问的图片 URL
image_base64 字符串 图片 Base64,支持带 data:image/…;base64, 前缀

以上三个字段必须且只能传一个。图片按 EXIF 方向解码后,先检查原图的人脸完整性和俯拍角度。俯拍使用头部姿态估算的正向 pitch,超过服务端环境变量 FRONTAL_PITCH_THR(默认 30°)时拦截。通过质检后复用接口 52 的扶正裁切规则,再用处理后的图片做面部特征分析。

质检失败与异常响应

以下业务响应的 HTTP 状态均为 200。

code 情况 message
1001 原图未检测到人脸 无法识别人像,请上传包含完整人脸的照片
1003 人脸关键点触及或超出图片边界 人脸不完整,请保留完整的脸部轮廓
1003 估算的俯拍角度超过阈值 俯拍角度过大,请将相机调整至与脸部平视
1003 扶正裁切失败,无法保留所需人脸关键点 人脸过于贴近边缘,无法扶正裁切
1008 URL 图片下载失败 图片下载失败(URL 不可达)
1008 Base64 解码失败 图片格式不支持(base64 解码失败)
1008 图片无法读取 图片格式不支持(仅 JPG / PNG)
1007 图片字段未按三选一传入 图片参数错误:必须且只能传 image_file / image_url / image_base64 其中一个
1007 图片预处理内部异常 图片预处理失败
1001 质检通过,但视觉模型未识别到人脸 无法识别人像
1007 视觉模型调用异常 分析服务异常:…

响应包含 code(整数业务码)、message(字符串提示)、request_id(字符串请求标识)和 data(失败时为 null)。三个 1003 情况可通过 message 区分,响应中没有独立的质检原因或角度字段。

{
  "code": 1003,
  "message": "俯拍角度过大,请将相机调整至与脸部平视",
  "request_id": "gw-xxxxxxxx",
  "data": null
}

成功响应

data.features 仍为 JSON 字符串,保留接口 4 的六项特征,在其中新增:

字段 类型 说明
zygoma_expansion boolean 或 null 颧弓外扩
temple_hollowing boolean 或 null 太阳穴凹陷

Ft 两端保持横坐标并取平均高度,Zy 为 234 到 454 的距离。只有 Ft ÷ Zy 严格小于 0.8 时两项同时为 true,否则同时为 false。所需点位缺失或无法测量时两项均为 null。网关测量复用接口 99 的 MediaPipe 与 BiSeNet 依赖,裁切还需要 Pillow。


接口 5:发际线 PNG 生成接口

说明:入参同接口2(先选性别、再多选发型)。对每个选中发型返回 middle / high / low 三档发际线叠图与生发图,并返回「最合适发际线」的面部中间点坐标。

请求:POST /api/v1/hairline/generate

输入

图片参数见「通用约定 → 图片传参字段」。专属参数:

参数 类型 必填 说明
gender string 是 性别:male / female。决定发型集合(female 7 / male 7)。缺失/非法返回 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, 7=wave。缺失/越界/非法返回 1007
use_mask bool 否 生发是否启用 inpaint 遮罩,默认 true。false 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比
prompt string 否 ComfyUI 提示词,默认「补充遮罩区域的头发,加一点美颜」,会替换工作流节点 60 的文本
generate_grow_image bool 否 是否生成生发效果图(ComfyUI 生发,全流程最耗时),默认 true。传 false 时跳过生发,各发型 grown_image_* 恒为 null,仅返回三档发际线叠图与中心点,可大幅降低耗时

⚠️ 三档叠图分别用 hairline_texture / hairline_texture_high / hairline_texture_low 三套同名贴图;生发黑模板固定取自 hairline_texture_black/(middle 档),即生发目标固定压到 middle 档,每个发型仅 1 张生发图。

输出(data)

字段 类型 说明
hairline_images object[] 选中发型列表,数量 = 所选发型数,元素见下表
best_hairline_center_point object | null 首个选中发型的 middle 档发际线曲线「面部中间点」坐标,原图像素:{ "x": number, "y": number }
high_hairline_center_point object | null 同上,high 档发际线中点(发际线偏高)
low_hairline_center_point object | null 同上,low 档发际线中点(发际线偏低)
face_measure object | null 复用接口1的四庭七眼测量数值(不含标注图)。独立流程,测量失败(无人脸/非正面/分割失败)时为 null,不影响发际线主结果。字段结构见下表

hairline_images 元素:

字段 类型 说明
hairline_type string 发际线类型 key:ellipse/flower/heart/straight/wave/bigflower/clasicalflower(female),ellipse/m/straight/inverse_arc/heart/Softpetal/wave(male)
image_middle_url string middle 档发际线曲线透明 PNG URL(仅曲线,透明底,不含人物,需叠加原图显示)
image_high_url string high 档发际线曲线透明 PNG URL(同上,high 档曲线)
image_low_url string low 档发际线曲线透明 PNG URL(同上,low 档曲线)
grown_image_url string | null 生发后图片 URL(ComfyUI「植发」效果图,完整人像照片,生发失败或 generate_grow_image=false 时为 null)
order int 发型序号(= 传入的 hair_style 值)

worker 侧返回 image_middle_base64 / image_high_base64 / image_low_base64 / grown_image_base64,网关落盘后改写为上表对应的 *_url。

💡 三档 image_*_url 为透明底 PNG,前端需用绝对定位叠加到原图上显示(参考测试页的 .img-stack 叠加结构)。grown_image_url 是完整人像照片,直接显示即可。

face_measure 元素(与接口1的 data 同构,不含 annotated_image_* 标注图字段):

字段 类型 说明
face_total_height_cm number 全脸总高度(cm)= 四庭之和
four_courts object 四庭数据(顶/上/中/下庭 cm + 占比 ratios),结构同接口1
seven_eyes object 七眼数据(眼宽/脸宽/两眼间距 cm + 占比 ratios + eye1~eye7 从左到右 7 段宽度),结构同接口1
landmarks object 5 个纵向关键点像素坐标(hair_top/hairline/brow_center/nose_bottom/chin_tip),结构同接口1
vertical_lines object 竖线坐标,结构同接口1
hairline_source string 发际线来源:segmentation(真实分割)/ estimated(比例估算)/ corrected(发际线贴近头顶、分割不可靠,已按 0.95×中庭反推修正)
head_pose object 头部姿态角度(yaw/pitch/roll,单位:度)
left_position object MediaPipe 21 号关键点坐标(左脸定位点),原图像素:{ "x": int, "y": int }
right_position object MediaPipe 251 号关键点坐标(右脸定位点,与 21 号镜像),原图像素:{ "x": int, "y": int }

eye1~eye7 为从左到右共 7 段宽度,eye1=左耳外段、eye7=右耳外段,某侧耳朵不可见时对应段为 null。详见接口1说明。

响应示例(当前 Mock 返回值)

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "hairline_images": [
      {
        "hairline_type": "ellipse",
        "image_middle_url": "https://hair.xiangsilian.com/static/annotations/mid1.png",
        "image_high_url": "https://hair.xiangsilian.com/static/annotations/high1.png",
        "image_low_url": "https://hair.xiangsilian.com/static/annotations/low1.png",
        "grown_image_url": "https://hair.xiangsilian.com/static/annotations/grown1.png",
        "order": 1
      },
      {
        "hairline_type": "heart",
        "image_middle_url": "https://hair.xiangsilian.com/static/annotations/mid3.png",
        "image_high_url": "https://hair.xiangsilian.com/static/annotations/high3.png",
        "image_low_url": "https://hair.xiangsilian.com/static/annotations/low3.png",
        "grown_image_base64": null,
        "order": 3
      }
    ],
    "best_hairline_center_point": { "x": 540, "y": 430 },
    "high_hairline_center_point": { "x": 540, "y": 380 },
    "low_hairline_center_point": { "x": 540, "y": 480 },
    "face_measure": {
      "face_total_height_cm": 26.76,
      "four_courts": {
        "top_court_cm": 5.77, "upper_court_cm": 5.93,
        "middle_court_cm": 7.62, "lower_court_cm": 7.44,
        "ratios": { "top_court": 0.216, "upper_court": 0.222,
                    "middle_court": 0.285, "lower_court": 0.278 }
      },
      "seven_eyes": {
        "eye_width_cm": 2.76, "face_width_cm": 15.08,
        "inter_eye_distance_cm": 3.9,
        "ratios": { "eye_width": 0.183, "inter_eye_distance": 0.259 },
        "eye1": null, "eye2": 3.0, "eye3": 2.76, "eye4": 3.9,
        "eye5": 2.76, "eye6": 3.0, "eye7": null
      },
      "landmarks": {
        "hair_top": { "x": 504, "y": 103 },
        "hairline": { "x": 504, "y": 228 },
        "brow_center": { "x": 504, "y": 357 },
        "nose_bottom": { "x": 505, "y": 522 },
        "chin_tip": { "x": 506, "y": 683 }
      },
      "hairline_source": "segmentation",
      "head_pose": { "yaw": -1.39, "pitch": 2.49, "roll": -0.06 }
    }
  }
}

说明:生发失败的元素中,网关不改写 null 值,故字段名保持为 grown_image_base64: null(有值时才改写为 grown_image_url),与接口2生发失败项一致。


接口 52:发际线 PNG 生成接口

说明:入参同接口2(先选性别、再多选发型)。对每个选中发型返回一张 middle 设计叠图与生发图。目标上庭 =(中庭 + 下庭)×0.45,从眉心向上定位;所有形状的中点对齐同一目标。high / low 已停用,旧字段保留为 null。

请求:POST /api/v1/hairline/generate-52(仅GPU worker,端口8187;本次不在网关新增路由)

IP限制:GPU worker的所有动态接口统一仅允许本机回环地址、本机网卡地址及白名单;目前白名单含网关IP 49.232.51.171,其他直连来源需加入ip_access.json的allowed_ips。该文件支持单个IP与CIDR,修改后立即生效;拒绝时返回HTTP403、code=1010。网关不启用此限制,已有鉴权仍保留。详见接口IP白名单。

图片扶正与标准构图

显式传normalize_image=true时,先扶正9→152,再按**高(3÷0.9)×L≈3.3333×L、宽2.5×L(3:4)**裁切,L为9→152的直线像素距离。相对原3L规则,裁切框宽高均扩大约11.11%,同样显示尺寸下人物缩小约10%。高度取最接近的4的倍数,宽度取高度的3/4。眉心定位沿用已扶正参考图:9号点相对位置约(49.0061%,34.4136%)。参考图仍为786×1048,两点X均为385.18784。

目标窗口完全在原图有效区域内才进行标准裁切。标准窗口不足时,偏长图片(宽/高<3/4)采用原图有效范围内最大的3:4窗口,尽量贴近眉心目标位置并保留完整人脸,status=aspect_crop;人脸放不进3:4窗口时回退仅扶正并返回原因。其余图片空间不足时仍仅扶正、去除旋转空角。不放大小图。所有叠图与坐标使用响应中的处理后底图 input_image_*,调用方应使用该底图叠加;normalize_image=false 可关闭此预处理。

framing包含处理前后尺寸、旋转角、是否标准裁切、跳过原因、source_to_processed/processed_to_source仿射矩阵。status区分reference_crop(标准窗口)、aspect_crop(长图3:4裁切)和rotation_only(仅扶正);standard_crop=false时仍可能有aspect_crop=true。aspect_crop_skip_reason说明长图无法保留人脸时的回退原因。original_image_*保留EXIF方向修正后的上传图,原图坐标可通过逆矩阵还原。

输入

图片参数见「通用约定 → 图片传参字段」。专属参数:

参数 类型 必填 说明
gender string 是 性别:male / female。决定发型集合(female 7 / male 7)。缺失/非法返回 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, 7=wave。缺失/越界/非法返回 1007
use_mask bool 否 生发是否启用 inpaint 遮罩,默认 true。false 时用干净原图生成(空遮罩、不烧模板黑线),供测试对比
prompt string 否 ComfyUI 提示词,默认「填充遮罩区域的头发,人物增加一点磨皮」,会替换工作流节点 60 的文本
normalize_image bool 否 新增可选开关,默认false:保留原图尺寸与坐标。传true开启扶正和裁切;规则测试页显式传true,对比调试页默认开启
generate_grow_image bool 否 是否生成生发效果图(ComfyUI 生发,全流程最耗时),默认 true。传 false 时跳过生发,各发型 grown_image_* 恒为 null,仅返回设计叠图、中心点与高度规则数据,可大幅降低耗时

生发划线与遮罩直接取新位置的 middle 曲线;旧规则的头发边界与模板用于保留形状和倾斜,不决定新中心高度。计算使用未取整的像素高度,与四庭测量采用同一 Y 方向;测量主流程失败时用发际线管线的同编号关键点计算,measurement_source 标明来源。目标越出图片或无法对齐时返回 1007,不静默回退旧规则。

高度规则与对比

  • 参数与字段:原有8个请求参数、响应外层结构和所有旧返回字段均保留。use_mask=true、默认prompt、generate_grow_image=true保持原值。新功能只新增可选参数和返回字段;旧请求未传normalize_image时保留原图坐标,high/low按已约定保留null,worker始终返回*_base64,不负责保存图片、生成公网URL或改名;网关保持原样。
  • height_rule:middle_height_px、lower_height_px、target_upper_height_px、target_upper_height_cm(可空)、target_center、brow_center、nose_bottom、chin_tip、measurement_source。
  • 每项 height_placement:old_center、new_center、shift_x_px、shift_y_px(正=下移)、target_error_px。浮点坐标保留精度,旧中心点字段继续返回取整像素。
  • face_measure 为处理后底图的实际测量值,未被设计目标覆盖。
  • guide_landmarks:9、150、152、162、251、389 号 MediaPipe 点的图片像素坐标,供对比页绘制参考框。参考框左/右边分别经过162/389,底边经过9,高度为9→152距离的70%;两侧均固定平行9→152。
  • 规则页:/static/test_interface52.html;旧/新规则对比:/static/test_interface52_compare.html。
  • 规则页每个发型依次展示未裁切原图、middle、裁切发际线叠加、生发图。“裁切发际线叠加”由页面按guide_landmarks生成:在相同处理后底图上叠加矩形内的middle PNG,矩形外保持透明;左/右边过162/389,底边过9,高度0.7×9→152,左右边平行9→152。
  • 对比调试接口:POST /api/v1/debug/hairline-height-compare,图片三选一、gender、hair_style;默认只出旧/新曲线,可选 generate_grow_image=true 额外验证新规则生发。
  • 测试清单:tests/fixtures/hairline_height_cases.json(用户指定30张);批量运行:./venv/bin/python scripts/compare_hairline_height.py,默认全部30张、男女各7型,共420组。每人一行,未裁切原图放在最前,后接一张可切换样式的旧规则图和全部新规则样式。可用 --cases 1,2,3,4,5 指定部分案例。

输出(data)

字段 类型 说明
hairline_images object[] 选中发型列表,数量 = 所选发型数,元素见下表
best_hairline_center_point object | null 首个选中发型的 middle 档发际线曲线「面部中间点」坐标,当前底图像素:{ "x": number, "y": number }
high_hairline_center_point object | null 已停用,固定 null
low_hairline_center_point object | null 已停用,固定 null
input_image_base64 string 当前底图的JPEG base64,发际线叠图、参考点和测量值均使用该图的坐标系
original_image_base64 string EXIF方向修正后的上传原图JPEG base64
width / height int 当前底图的实际像素宽 / 高
coordinate_space string 开启预处理时为 processed_image,关闭时为 original_image
framing object | null 裁切状态、旋转角、前后尺寸、轴线误差及双向仿射矩阵;关闭预处理时为 null
height_rule object 中庭/下庭、目标上庭高度、目标中心及测量来源,详见“高度规则与对比”
guide_landmarks object 9、150、152、162、251、389 号点的当前底图像素坐标;参考框实际使用9、152、162、389
face_measure object | null 复用接口1的四庭七眼测量数值(不含标注图)。独立流程,测量失败(无人脸/非正面/分割失败)时为 null,不影响发际线主结果。字段结构见下表

hairline_images 元素:

字段 类型 说明
hairline_type string 发际线类型 key:ellipse/flower/heart/straight/wave/bigflower/clasicalflower(female),ellipse/m/straight/inverse_arc/heart/Softpetal/wave(male)
image_middle_base64 string middle 档发际线曲线透明 PNG base64(仅曲线,透明底,不含人物,需叠加 input_image_base64 显示)
image_high_base64 null 已停用,保留字段为 null
image_low_base64 null 已停用,保留字段为 null
grown_image_base64 string | null 生发后图片 JPEG base64(ComfyUI「植发」效果图,完整人像照片,生发失败或 generate_grow_image=false 时为 null)
order int 发型序号(= 传入的 hair_style 值)
height_placement object 旧/新中心、XY移动距离、目标误差,均为未取整的像素值

上表为GPU worker的实际响应字段;所有图片使用base64,空图片保留原字段并返回null。网关的落盘与URL改写属于网关职责,本次不修改。

前端将base64转为data URI后显示。middle透明图叠加到input_image_base64,生发图直接显示。GPU worker本机测试页为http://localhost:8187/static/test_interface52.html。

face_measure 元素(与接口1的 data 同构,不含 annotated_image_* 标注图字段):

字段 类型 说明
face_total_height_cm number 全脸总高度(cm)= 四庭之和
four_courts object 四庭数据(顶/上/中/下庭 cm + 占比 ratios),结构同接口1
seven_eyes object 七眼数据(眼宽/脸宽/两眼间距 cm + 占比 ratios + eye1~eye7 从左到右 7 段宽度),结构同接口1
landmarks object 5 个纵向关键点像素坐标(hair_top/hairline/brow_center/nose_bottom/chin_tip),结构同接口1
vertical_lines object 竖线坐标,结构同接口1
hairline_source string 发际线来源:segmentation(真实分割)/ estimated(比例估算)/ corrected(发际线贴近头顶、分割不可靠,已按 0.95×中庭反推修正)
head_pose object 头部姿态角度(yaw/pitch/roll,单位:度)
left_position object MediaPipe 21 号关键点坐标(左脸定位点),当前底图像素:{ "x": int, "y": int }
right_position object MediaPipe 251 号关键点坐标(右脸定位点,与 21 号镜像),当前底图像素:{ "x": int, "y": int }

eye1~eye7 为从左到右共 7 段宽度,eye1=左耳外段、eye7=右耳外段,某侧耳朵不可见时对应段为 null。详见接口1说明。

GPU worker响应结构示例(normalize_image=false)

此例未开启裁切,坐标基于原图;face_measure=null时仍可按发际线关键点计算目标。图片内容以缩略base64字符串示意,空图片字段返回null,字段名不变。

{
  "code": 0,
  "message": "success",
  "request_id": "mock-request-id",
  "data": {
    "hairline_images": [
      {
        "hairline_type": "ellipse",
        "image_middle_base64": "iVBORw0KGgo...",
        "image_high_base64": null,
        "image_low_base64": null,
        "grown_image_base64": "/9j/4AAQ...",
        "order": 1,
        "height_placement": {
          "old_center": {"x": 540.0, "y": 450.0},
          "new_center": {"x": 540.0, "y": 461.0},
          "shift_x_px": 0.0, "shift_y_px": 11.0, "target_error_px": 0.0
        }
      }
    ],
    "best_hairline_center_point": {"x": 540, "y": 461},
    "high_hairline_center_point": null,
    "low_hairline_center_point": null,
    "input_image_base64": "/9j/4AAQ...",
    "original_image_base64": "/9j/4AAQ...",
    "width": 1080, "height": 1440,
    "coordinate_space": "original_image",
    "framing": null,
    "height_rule": {
      "name": "court_average", "formula": "上庭 = (中庭 + 下庭) × 0.45",
      "measurement_source": "hairline_landmarks",
      "brow_center": {"x": 540.0, "y": 740.0},
      "nose_bottom": {"x": 540.0, "y": 1050.0},
      "chin_tip": {"x": 540.0, "y": 1360.0},
      "middle_height_px": 310.0, "lower_height_px": 310.0,
      "target_upper_height_px": 279.0, "target_upper_height_cm": null,
      "target_center": {"x": 540.0, "y": 461.0}
    },
    "guide_landmarks": {
      "9": {"x": 540.0, "y": 740.0}, "150": {"x": 470.0, "y": 1340.0},
      "152": {"x": 540.0, "y": 1360.0}, "162": {"x": 300.0, "y": 680.0},
      "251": {"x": 770.0, "y": 630.0}, "389": {"x": 780.0, "y": 680.0}
    },
    "face_measure": null
  }
}

开启normalize_image=true后,coordinate_space=processed_image,framing包含前述裁切状态和坐标变换,所有发际线图片须叠加到input_image_base64。原始图片仅用于展示和坐标回溯。


接口 9:头发遮罩生成接口

说明:输入一张含人头的照片,生成头发遮罩,并返回每一步的可视化图(供对比调试)。

请求:POST /api/v1/head/mask

输入

图片参数见「通用约定 → 图片传参字段」。专属参数:

参数 类型 必填 说明
erode_cm float 否 外缘朝中心(鼻梁 151 点)内缩的距离(厘米),默认 1.2

处理流程

  1. MediaPipe 关键点 → 底部分割线(关键点 21,68,104,69,108,151,337,299,333,298,251 的连线,21 水平延伸到最左、251 延伸到最右)。
  2. 分割线以上为「上半区」。
  3. 头发分割(BiSeNet 与 SegFormer 两套);从每列最顶端头发向下填充到分割线,得到含额头的闭合区域(头发+额头,不割断)。
  4. 外缘朝中心点 151 内缩 erode_cm(虹膜标定换算像素)、底线不动 → 最终遮罩。

输出(data)

字段 类型 说明
px_per_cm float 虹膜标定出的像素/厘米
erode_cm / erode_px float / int 内缩距离(厘米 / 像素)
image_size object {width, height} 原图尺寸
steps_common object landmarks_baseline_*(关键点/分割线)、upper_region_*(上半区)
bisenet / segformer object 两套分割模型各自的结果:hair_mask_*(原始头发分割)、closed_region_*(含额头闭合区域)、final_overlay_*(最终遮罩叠加可视化)、mask_*(最终遮罩 PNG)及 hair_pixels/closed_pixels/mask_pixels 像素计数

worker 返回 *_base64(data URI),经网关改写为 *_url。


接口 10:头部外缘膨胀带遮罩接口

说明:先和接口9 一样得到内缩后的基准遮罩,再沿头部外缘生成一条膨胀带遮罩。

请求:POST /api/v1/head/band

输入

参数 类型 必填 说明
erode_cm float 否 基准遮罩外缘朝 151 内缩距离(厘米,同接口9),默认 1.2
dilate_cm float 否 外轮廓线膨胀后带子总宽(厘米),默认 2.0

处理流程

  1. 取基准遮罩的外轮廓线,去掉贴着底部分割线的那一段(只留头发/头部外缘弧线)。
  2. 把外轮廓线膨胀成带子(总宽 dilate_cm;半径=总宽/2,虹膜标定换算像素)。
  3. 裁到分割线以上(不越过底线)。

输出(data)

结构同接口9,但每组结果为 base_mask_*(基准遮罩)/ contour_*(外轮廓线)/ band_overlay_*(带子叠加可视化)/ mask_*(最终带状遮罩)及 base_pixels/band_pixels 计数,另有 dilate_cm/dilate_radius_px。


接口 11:发际线生发接口(不含重绘)

说明:输入一张发际线较高 / 头发稀少的正脸图 + 发际线类型 ID,输出同一个人、同一发型、按该类型压低发际线后的图片,并返回每一步可视化。重绘版见接口12。

请求:POST /api/v1/hairline/grow

输入

参数 类型 必填 说明
hairline_id string 是 发际线类型 ID(= change_hair hair_id):chang_tuoyuan / chang_huaban / chang_xinxing / chang_zhixian / chang_bolang
gen_backend string 否 生成后端:swaphair(换发型 LoRA,默认)|hairgrow(区域生发 inpaint)
hairgrow_strength float 否 区域生发强度(仅 hairgrow 后端),默认 0.75
is_hr bool 否 高清模式(换发型输出 1152×1536,否则 576×768),默认 false
seg_model string 否 头发分割模型:bisenet | segformer(默认)
erode_cm float 否 baseline 参考内缩距离(厘米),默认 0.6
hairline_push_cm float 否 发际线外推距离(厘米,往头发方向推进),默认 1.0
hairline_edge string 否 发际线提取方式:column(默认)|contour
swap_mode string 否 换发型取图模式:ext_mask(默认,把接口9 遮罩传给 webui 精确重绘)|as_is(用内部遮罩,贴回时再裁)
edge_erode_px int 否 贴图前遮罩内缩像素(防边缘露皮/光晕),默认 3
denoising_strength float 否 换发型 webui 重绘强度(越大生发越激进),默认 0.6
mb_levels int 否 多频段金字塔层数(2~6),默认 5
blend_method string 否 接缝融合:multiband(默认)|seamless(泊松)|two_stage(泊松→多频段)|feather(高斯羽化)|alpha_gradient(距离渐变)
color_match bool 否 融合前 Reinhard 颜色迁移消除整体色差,默认 true
color_match_strength float 否 颜色迁移强度(0~1),默认 1.0
mb_feather_px int 否 多频段最细层掩码轻羽化像素,默认 1
transition_band_px int 否 keep-region 过渡带边距(-1=自动按层数 2^n),默认 -1
inpainting_fill int 否 change_hair 服务端重绘填充:0=保留原图 | 1=噪声(默认)| 2=纯色 | 3=潜变量噪声
mask_blur int 否 change_hair 服务端遮罩边缘模糊像素,默认 11
mask_dilate_scale float 否 change_hair 服务端遮罩膨胀缩放(<1 收缩防越界),默认 1.0

输出(data)

steps:input(原图)/ baseline(底部分割线)/ hair_mask(头发分割)/ mask_overlay(遮罩叠加)/ mask(遮罩)/ swap_raw(换发型原始输出)/ alpha(融合权重)/ final(最终结果)各步图(*_base64,经网关改写为 *_url),另有 timings_ms 分步耗时。

⚠️ swaphair 后端依赖 change_hair(:8801)在跑;hairgrow 后端依赖 ComfyUI(:8188)。


接口 12:发际线带重绘接口

说明:接口11 的下游重绘阶段——内部先跑接口11 核心管线拿 ④ 接缝融合最终图(final),再取发际线重绘带(外推 band_lo_mult×push ~ band_hi_mult×push 之间、经 baseline 截断只留上部的带状区域)作遮罩,用 Flux-2(ComfyUI,reference-latent 保色重绘) 重绘。

同时产出两版结果:

  • redraw_full:ComfyUI 整帧输出(全脸美颜 + 全脸重绘)。
  • redraw_band:加发只在发际线带内、band 外保留 final 结构并按 beauty_alpha 融入全脸美颜。

请求:POST /api/v1/hairline/grow_v2

输入

接口11 的全部参数(见上表)再叠加:

参数 类型 必填 说明
comfyui_prompt string 否 Flux-2 重绘提示词,缺省「填充遮罩区域的头发,人物增加一点磨皮」
beauty_alpha float 否 redraw_band 版 band 外的全脸美颜融入强度(0=band 外纯用 final,1≈整帧版),默认 0.6
band_lo_mult float 否 重绘带外推倍率下限(相对 hairline_push_cm),默认 0.5
band_hi_mult float 否 重绘带外推倍率上限(相对 hairline_push_cm),默认 1.5

输出(data)

steps:input / final(重绘输入基底)/ redraw_band_overlay(重绘带可视化)/ redraw_full(A 整帧)/ redraw_band(B 局部+美颜)/ redraw_c(兼容旧字段,=redraw_full);重绘异常在 redraw.c_error 报告。

精简变体(生产推荐)

路径 说明
POST /api/v1/hairline/grow_v2_final 仅需图片 + hairline_id,其余参数固化为调优默认值(push=0.8cm / two_stage / color_match=关 等),最终取整帧重绘 redraw_full
POST /api/v1/hairline/grow_v2_final_v2 参数同上,最终取 B 局部加发+全脸美颜 redraw_band

⚠️ 依赖 ComfyUI(:8188)与 change_hair(:8801)均在跑。接口2 女性 1..5 的生发图即复用 grow_v2_final 管线。


接口 99:人脸特殊点检测接口

说明:输入一张人脸照片,返回一组固定编号 MediaPipe Face Mesh 关键点的像素坐标,外加 5 个发际线特殊点(射线与头发分割发际线的交点)。生产路径:网关本机实现(纯 CPU,不转发 worker,同接口4 模式);worker 侧保留同路径接口供测试页直连。

请求:POST /api/v1/face/special-points

输入

图片参数见「通用约定 → 图片传参字段」,无专属参数。要求单人正面照(非正面返回 1003)。

输出(data)

points:字段名 = <组英文名>_<点ID>,值为原图像素坐标 {x, y}(int);发际线点不可得(秃顶/分割失败)时为 null。

组 字段前缀 点 ID
眉毛 eyebrow 107 66 105 63 70 336 296 334 293 300
眼睛 eye 189 222 224 113 226 413 442 444 342 446
嘴 mouth 0 37 40 67 91 84 17 405 375 409 269
中线鼻 nose_midline 9 168 197 5 4 194 278 48 437 217
面颊 cheek 101 117 123 187 205 50 330 346 352 280 425
边线 face_edge 162 234 58 136 149 152 378 365 288 401 366 389 251

发际线特殊点(沿关键点 a→b 方向射线步进,首次进入 BiSeNet 头发 mask 处为交点;双射线取中点,仅一条命中返回该点):

字段 计算
hair_line_center 151→10 方向交点
hair_line_right mid(108→109 交点A, 69→67 交点B)
hair_line_right_right mid(104→103 交点A, 68→54 交点B)
hair_line_left mid(337→338 交点A, 299→297 交点B)
hair_line_left_left mid(333→332 交点A, 298→284 交点B)

另有 image_size(宽高)与 hairline_source(segmentation=发际线点已算出 / unavailable=分割不可用,发际线点为 null)。


汇总:输入输出一览

接口 路径 输入 主要输出
1 四庭七眼测量 /api/v1/face/measure 用户照片 标注 PNG(无人物)+ 四庭/七眼厘米数值与坐标
6 四庭七眼测量 v2 /api/v1/face/measure-v2 用户照片 同接口1,去顶庭变体
2 C 端生发 /api/v1/hair/grow 用户照片 + gender + hair_style(多选) 每发型预览 PNG + 生发图(female 1..5=换发型+重绘,其余=原生生发)
7 C 端生发 v2 /api/v1/hair/grow-v2 同接口2 同接口2(add_hair2 工作流,已弃用隐藏)
3 B 端生发 /api/v1/hair/grow-b 划线图片 检测到的发际线 + 生发后图片
4 用户特征 /api/v1/face/features 用户照片 6 个用户特征字段(脸形/眉形/年龄/动静/性别/基因风格),网关本机实现
5 发际线 PNG /api/v1/hairline/generate 用户照片 + gender + hair_style(多选) 每个选中发型 middle/high/low 三档发际线叠图 + 生发图 + 最合适发际线面部中间点坐标
52 发际线新规则 /api/v1/hairline/generate-52 用户照片 + gender + hair_style(多选) 每个选中发型的新规则 middle 设计叠图 + 生发图 + 目标中心坐标;high/low 旧字段为 null
9 头发遮罩 /api/v1/head/mask 用户照片 头发遮罩 + 分步可视化(BiSeNet/SegFormer 双路)
10 外缘膨胀带 /api/v1/head/band 用户照片 头部外缘带状遮罩 + 分步可视化
11 发际线生发 /api/v1/hairline/grow 用户照片 + hairline_id 压低发际线图 + 全步骤可视化(不含重绘)
12 发际线带重绘 /api/v1/hairline/grow_v2 同接口11 + 重绘带参数 final 基底 + Flux-2 保色重绘(整帧/局部两版);精简版 grow_v2_final[_v2] 仅需图片+hairline_id
99 人脸特殊点 /api/v1/face/special-points 用户照片 60 个固定编号关键点 + 5 个发际线特殊点像素坐标 JSON(网关本机实现,同接口4)

另有 worker 本机工具路由(不在对外契约内):/api/swapHair/v1、/hairColor/v2(CORS 代理 change_hair)、/api/v1/redraw(直接 ComfyUI 重绘)、/api/v1/debug/*。


已确认结论

  • 图片传参:文件 / URL / base64 三种都支持,严格互斥(必须且只能传一个,base64 需带 data:image/...;base64, 前缀)。
  • 默认单人;检测到 2~3 人报错提示客户端;单文件 ≤ 1 MB;格式仅 JPG / PNG。
  • 坐标基准:默认原图像素;接口52开启预处理时使用响应中的处理后底图像素。
  • 接口 2:提供「美颜」开关 beauty_enabled。
  • 接口 3:仅传划线图(marked_image_* 三选一),需返回发际线类型(custom)。
  • 接口 4:data 返回一个 JSON 字符串,字段不固定,可随时调整。
  • 接口 5:发际线 PNG 数量 N 不固定,需按合适度排序。
  • 英文字段命名由本文档约定(见各接口表格)。

待与需求方确认的问题清单

  1. 接口 1 标注图片设计稿(见下方说明)。