feat(gateway): 接入52号发际线接口与公开测试页
新增52号同路径转发,沿用现有主备派发、鉴权、队列和图片URL改写。空图片保留既有base64字段名,不带入worker算法及IP限制。 同步52号测试页、图片解析和矩形叠加依赖,公开页面不包含内部Token。补全网关契约与部署文档,Nginx示例读取超时延长至660秒。 验证:42项网关测试通过;临时网关连接真实GPU worker,5号三档与52号七型URL、长图裁切和边框均通过浏览器检查。
This commit is contained in:
+149
-1
@@ -3,7 +3,7 @@
|
||||
> 本文档依据《旷视具体需求.docx》整理,描述各接口的**输入**与**输出**。
|
||||
> 文中标记为 **【待确认】** 的内容为需求文档中尚未明确、需与对方对齐的点。
|
||||
|
||||
> **当前为第一版 Mock 服务**:所有接口已上线,但**不做真实算法计算**,统一返回下文「响应示例」中的默认值;所有图片字段均返回示例图 `https://hair.xiangsilian.com/static/sample.jpg`。真实逻辑后续接入。
|
||||
> 下文示例用于说明响应结构。接口52由网关转发至GPU worker执行真实计算,具体接入与部署见[接口52网关接入](接口52网关接入.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
| 3 B 端生发 | POST | `/api/v1/hair/grow-b` |
|
||||
| 4 用户特征 | POST | `/api/v1/face/features` |
|
||||
| 5 发际线 PNG 生成 | POST | `/api/v1/hairline/generate` |
|
||||
| 52 发际线新规则 | POST | `/api/v1/hairline/generate-52` |
|
||||
|
||||
---
|
||||
|
||||
@@ -519,6 +520,153 @@
|
||||
|
||||
---
|
||||
|
||||
## 接口 52:发际线 PNG 生成接口
|
||||
|
||||
**说明**:入参同接口2(先选性别、再多选发型)。对每个选中发型返回一张 `middle` 设计叠图与生发图。**目标上庭 =(中庭 + 下庭)÷2**,从眉心向上定位;所有形状的中点对齐同一目标。`high` / `low` 已停用,旧字段保留为 `null`。
|
||||
|
||||
**请求**:`POST /api/v1/hairline/generate-52`(网关透传至同路径GPU worker)
|
||||
|
||||
**职责**:GPU worker返回base64并完成算法处理,网关负责透传参数、附加内部Token、保存非空图片及返回公网URL。网关不增加IP限制;网关出口IP须已在worker白名单内。部署与完整字段约定见[接口52网关接入](接口52网关接入.md)。
|
||||
|
||||
### 图片扶正与标准构图
|
||||
|
||||
显式传`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`,空图片保留`*_base64: null`。
|
||||
- `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`。worker本机另有旧/新规则对比页,本次不向网关开放调试接口。
|
||||
- 规则页每个发型依次展示未裁切原图、middle、裁切发际线叠加、生发图。“裁切发际线叠加”由页面按`guide_landmarks`生成:在相同处理后底图上叠加矩形内的middle PNG,矩形外保持透明;左/右边过162/389,底边过9,高度0.7×9→152,左右边平行9→152。
|
||||
|
||||
### 网关输出(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_url | string | 当前底图JPEG的URL,发际线叠图、参考点和测量值均使用该图的坐标系 |
|
||||
| original_image_url | string | EXIF方向修正后的上传原图JPEG的URL |
|
||||
| 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_url | string | middle 档发际线曲线**透明 PNG** URL(仅曲线,透明底,**不含人物**,需叠加 `input_image_url` 显示) |
|
||||
| image_high_base64 | null | 已停用,保留字段为 `null` |
|
||||
| image_low_base64 | null | 已停用,保留字段为 `null` |
|
||||
| grown_image_url | string | 生发成功时的完整人像JPEG URL |
|
||||
| grown_image_base64 | null | 生发失败或`generate_grow_image=false`时返回;此时没有`grown_image_url` |
|
||||
| order | int | 发型序号(= 传入的 hair_style 值) |
|
||||
| height_placement | object | 旧/新中心、XY移动距离、目标误差,均为未取整的像素值 |
|
||||
|
||||
> 上表为网关响应字段。worker直连时所有图片字段均为`*_base64`;网关仅对有图片内容的字段生成`*_url`,high/low等空字段保留`*_base64: null`,沿用既有行为。
|
||||
>
|
||||
> middle透明PNG叠加到`input_image_url`,生发图直接显示。网关测试页为`/static/test_interface52.html`,页面不包含内部Token。
|
||||
|
||||
`face_measure` 元素(与[接口1](#接口-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 |
|
||||
| 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说明。
|
||||
|
||||
### 网关响应结构示例(normalize_image=false)
|
||||
|
||||
此例未开启裁切,坐标基于原图;`face_measure=null`时仍可按发际线关键点计算目标。有图片内容的字段已落盘为公网URL;空图片字段仍返回null,保留base64字段名。
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"request_id": "mock-request-id",
|
||||
"data": {
|
||||
"hairline_images": [
|
||||
{
|
||||
"hairline_type": "ellipse",
|
||||
"image_middle_url": "https://hair.xiangsilian.com/static/annotations/middle.png",
|
||||
"image_high_base64": null,
|
||||
"image_low_base64": null,
|
||||
"grown_image_url": "https://hair.xiangsilian.com/static/annotations/grown.jpg",
|
||||
"order": 1,
|
||||
"height_placement": {
|
||||
"old_center": {"x": 540.0, "y": 450.0},
|
||||
"new_center": {"x": 540.0, "y": 430.0},
|
||||
"shift_x_px": 0.0, "shift_y_px": -20.0, "target_error_px": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"best_hairline_center_point": {"x": 540, "y": 430},
|
||||
"high_hairline_center_point": null,
|
||||
"low_hairline_center_point": null,
|
||||
"input_image_url": "https://hair.xiangsilian.com/static/annotations/input.jpg",
|
||||
"original_image_url": "https://hair.xiangsilian.com/static/annotations/original.jpg",
|
||||
"width": 1080, "height": 1440,
|
||||
"coordinate_space": "original_image",
|
||||
"framing": null,
|
||||
"height_rule": {
|
||||
"name": "court_average", "formula": "上庭 = (中庭 + 下庭) / 2",
|
||||
"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": 310.0, "target_upper_height_cm": null,
|
||||
"target_center": {"x": 540.0, "y": 430.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_url`。原始图片仅用于展示和坐标回溯。
|
||||
|
||||
---
|
||||
|
||||
## 接口 9:头发遮罩生成接口
|
||||
|
||||
**说明**:输入一张含人头的照片,生成头发遮罩,并返回**每一步的可视化图**(供对比调试)。
|
||||
|
||||
Reference in New Issue
Block a user