save code
This commit is contained in:
@@ -320,8 +320,12 @@ class ImageJsonBody(BaseModel):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
async def _face_measure_impl(image_file, image_url, image_base64):
|
||||
"""接口1/6 共用实现:四庭七眼测量 + 标注图生成。返回 (ok_dict, err_dict)。"""
|
||||
async def _face_measure_impl(image_file, image_url, image_base64, variant="v1"):
|
||||
"""接口1/6 共用实现:四庭七眼测量 + 标注图生成。返回 (ok_dict, err_dict)。
|
||||
|
||||
variant="v1"(接口1):完整四庭七眼 + 头部端线。
|
||||
variant="v6"(接口6):去掉头顶/顶庭、不画人头最左/最右端线、数据去顶庭。
|
||||
"""
|
||||
# 1. 三选一取图
|
||||
raw, e = await resolve_image_bytes(image_file, image_url, image_base64)
|
||||
if e is not None:
|
||||
@@ -368,12 +372,25 @@ async def _face_measure_impl(image_file, image_url, image_base64):
|
||||
|
||||
# 8. 测量 + 标注图
|
||||
result = measure_face(landmarks, hair_mask, w, h, head_pose=head_pose)
|
||||
annotated = create_annotated_image(image, result, hair_mask=hair_mask)
|
||||
annotated = create_annotated_image(image, result, hair_mask=hair_mask, variant=variant)
|
||||
buf = BytesIO()
|
||||
annotated.save(buf, format="PNG")
|
||||
|
||||
# 9. 拆分架构:返回 base64,不落盘不拼 URL(落盘改 URL 由网关完成)
|
||||
data = result.to_response()
|
||||
if variant == "v6":
|
||||
# 接口6:数据去顶庭(重算三庭比例与总高,移除顶庭/头顶字段)
|
||||
vd = result.vertical
|
||||
base_px = vd["upper_court_px"] + vd["middle_court_px"] + vd["lower_court_px"]
|
||||
data["four_courts"]["ratios"] = {
|
||||
"upper_court": round(vd["upper_court_px"] / base_px, 3),
|
||||
"middle_court": round(vd["middle_court_px"] / base_px, 3),
|
||||
"lower_court": round(vd["lower_court_px"] / base_px, 3),
|
||||
}
|
||||
data["four_courts"].pop("top_court_cm", None)
|
||||
data["face_total_height_cm"] = round(
|
||||
result.upper_cm + result.middle_cm + result.lower_cm, 2)
|
||||
data["landmarks"].pop("hair_top", None)
|
||||
data["annotated_image_base64"] = base64.b64encode(buf.getvalue()).decode()
|
||||
return ok(data), None
|
||||
except Exception as ex: # noqa: BLE001
|
||||
@@ -401,10 +418,11 @@ async def _face_measure_impl(image_file, image_url, image_base64):
|
||||
**坐标说明**:所有坐标以原图像素为基准,原点为图片左上角,x 向右,y 向下。
|
||||
|
||||
**标注图片 UI 规范**(真实版本生效):
|
||||
- 字体/线条颜色:`#FFFFFF 100%`
|
||||
- 四庭数值在图片**左侧**呈现,七眼间距**上下穿插**展示
|
||||
- 字体:PingFangSC-Regular 10pt,线宽 1pt
|
||||
- 横线/竖线渐变消失,虚线两侧带箭头
|
||||
- 字体/线条/箭头颜色:`#FFFFFF 100%`,透明底
|
||||
- 字号/线宽/虚线/箭头按图片短边自适应缩放
|
||||
- 四庭数值(名+数值两行,不带 cm)在图片**左侧**呈现,七眼段宽**上下穿插**展示,底部标「单位cm」
|
||||
- 横线/竖线渐变消失并略超出端点;段宽/庭高用虚线 + 实心三角双箭头标示
|
||||
- 竖线含人头最左/最右端线(取自头发分割轮廓),共 8 线 7 段
|
||||
""",
|
||||
responses={
|
||||
200: {
|
||||
@@ -483,11 +501,16 @@ async def face_measure(
|
||||
description=f"""
|
||||
输入用户正面照,返回:
|
||||
- 标注好四庭七眼数据的 **PNG 图片**(仅标注图层,不含人物)
|
||||
- 四庭(顶庭/上庭/中庭/下庭)各段**厘米数值及占比**
|
||||
- 三庭(上庭/中庭/下庭)各段**厘米数值及占比**(**不含顶庭**)
|
||||
- 七眼(眼宽/脸宽/两眼间距)**厘米数值及占比**
|
||||
- 五个关键分界点的**原图像素坐标**(头顶/发际线/眉心/鼻翼下缘/下巴尖)
|
||||
- 四个关键分界点的**原图像素坐标**(发际线/眉心/鼻翼下缘/下巴尖)
|
||||
|
||||
功能与接口1 完全一致,复刻实现。
|
||||
基于接口1 的变体,与接口1 的差异:
|
||||
- **去顶庭**:不画头顶横线、不返回顶庭数据;`face_total_height_cm` 为三庭之和
|
||||
- **竖线范围**:纵向竖线从发际线画到下巴尖(接口1 为头顶→下巴尖)
|
||||
- **不画人头最左/最右端线**:仅七眼 6 点共 5 段标尺,不取头发轮廓端线(接口1 为 8 线 7 段)
|
||||
|
||||
其余(箭头/虚线/字体/单位cm/七眼数据)与接口1 一致。
|
||||
|
||||
{_image_fields_desc}
|
||||
|
||||
@@ -498,10 +521,10 @@ async def face_measure(
|
||||
**坐标说明**:所有坐标以原图像素为基准,原点为图片左上角,x 向右,y 向下。
|
||||
|
||||
**标注图片 UI 规范**(真实版本生效):
|
||||
- 字体/线条颜色:`#FFFFFF 100%`
|
||||
- 四庭数值在图片**左侧**呈现,七眼间距**上下穿插**展示
|
||||
- 字体:PingFangSC-Regular 10pt,线宽 1pt
|
||||
- 横线/竖线渐变消失,虚线两侧带箭头
|
||||
- 字体/线条/箭头颜色:`#FFFFFF 100%`,透明底
|
||||
- 字号/线宽/虚线/箭头按图片短边自适应缩放
|
||||
- 三庭数值(名+数值两行,不带 cm)在图片**左侧**呈现,七眼段宽**上下穿插**展示,底部标「单位cm」
|
||||
- 段宽/庭高用虚线 + 实心三角双箭头标示
|
||||
""",
|
||||
responses={
|
||||
200: {
|
||||
@@ -514,17 +537,15 @@ async def face_measure(
|
||||
"request_id": "mock-request-id",
|
||||
"data": {
|
||||
"annotated_image_url": SAMPLE_IMAGE_URL,
|
||||
"face_total_height_cm": 13.76,
|
||||
"face_total_height_cm": 10.32,
|
||||
"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,
|
||||
"upper_court": 0.333,
|
||||
"middle_court": 0.333,
|
||||
"lower_court": 0.333,
|
||||
},
|
||||
},
|
||||
"seven_eyes": {
|
||||
@@ -534,7 +555,6 @@ async def face_measure(
|
||||
"ratios": {"eye_width": 0.143, "inter_eye_distance": 0.143},
|
||||
},
|
||||
"landmarks": {
|
||||
"hair_top": {"x": 540, "y": 120},
|
||||
"hairline": {"x": 540, "y": 430},
|
||||
"brow_center": {"x": 540, "y": 740},
|
||||
"nose_bottom": {"x": 540, "y": 1050},
|
||||
@@ -564,8 +584,9 @@ async def face_measure_v2(
|
||||
image_url: Optional[str] = Form(default=None, description="图片 URL"),
|
||||
image_base64: Optional[str] = Form(default=None, description="图片 base64(需带 data:image/...;base64, 前缀)"),
|
||||
):
|
||||
"""接口6:四庭七眼测量标注 v2(复刻接口1)"""
|
||||
ok_data, err_data = await _face_measure_impl(image_file, image_url, image_base64)
|
||||
"""接口6:四庭七眼测量标注 v2(复刻接口1,去顶庭 + 去头部端线)"""
|
||||
ok_data, err_data = await _face_measure_impl(
|
||||
image_file, image_url, image_base64, variant="v6")
|
||||
return ok_data if ok_data is not None else err_data
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user