save code

This commit is contained in:
xsl
2026-06-23 23:26:40 +08:00
parent 6e8113b3ff
commit 57d1a876cc
6 changed files with 116 additions and 66 deletions
+36 -17
View File
@@ -141,7 +141,7 @@ def _head_edges_from_mask(hair_mask, y0, y1, left_cheek_x, right_cheek_x, min_ga
hr if (hr - right_cheek_x) >= min_gap else None)
def create_annotated_image(image_bgr, measure_result, hair_mask=None):
def create_annotated_image(image_bgr, measure_result, hair_mask=None, variant="v1"):
"""生成标注图层 PNG(透明底 RGBA,尺寸同原图)。返回 PIL.Image。
布局(对齐 img1.png 版本5):
@@ -152,6 +152,10 @@ def create_annotated_image(image_bgr, measure_result, hair_mask=None):
- 四庭(顶/上/中/下庭)在左侧:名 + 数值两行换行(无 cm),竖向虚线双箭头。
- 七眼段宽数值上下交替(上 3 / 下 4,无 cm),横向虚线双箭头。
- 底部统一标「单位cm」。
variant="v6"(接口6):去掉头顶横线与顶庭(只画发际线/眉心/鼻翼下缘/下巴尖 4 条
横线 + 上/中/下庭),竖线纵向范围改为发际线→下巴尖,且不画人头最左/最右端线
(仅七眼 6 点 5 段,不取头部端)。
"""
h, w = image_bgr.shape[:2]
v = measure_result.vertical
@@ -169,21 +173,27 @@ def create_annotated_image(image_bgr, measure_result, hair_mask=None):
buf = np.zeros((h, w, 4), dtype=np.uint8)
order = ["hair_top", "hairline", "brow_center", "nose_bottom", "chin_tip"]
if variant == "v6":
order = ["hairline", "brow_center", "nose_bottom", "chin_tip"]
else:
order = ["hair_top", "hairline", "brow_center", "nose_bottom", "chin_tip"]
ys = [v[name][1] for name in order]
pts = measure_result.eyes["points"]
seven_keys = ["left_cheek", "left_outer", "left_inner",
"right_inner", "right_outer", "right_cheek"]
base_xs = [pts[k][0] for k in seven_keys]
# 人头最左/最右:取自头发分割掩膜(方案B),脸纵向范围内统计;无掩膜则省略。
# 与脸颊线间距 < 脸宽×8% 视为太近,只保留脸颊线(不画头部端线)。
face_w = pts["right_cheek"][0] - pts["left_cheek"][0]
min_gap = max(1.0, face_w * 0.08)
head_l, head_r = _head_edges_from_mask(
hair_mask, ys[0], ys[-1], pts["left_cheek"][0], pts["right_cheek"][0], min_gap)
head_xs = [x for x in (head_l, head_r) if x is not None]
xs = sorted(base_xs + head_xs) # 自左向右(6 或 7/8 点)
if variant == "v6":
xs = sorted(base_xs) # 接口6:仅七眼 6 点,不画人头最左/最右端线
else:
# 人头最左/最右:取自头发分割掩膜(方案B),脸纵向范围内统计;无掩膜则省略。
# 与脸颊线间距 < 脸宽×8% 视为太近,只保留脸颊线(不画头部端线)。
face_w = pts["right_cheek"][0] - pts["left_cheek"][0]
min_gap = max(1.0, face_w * 0.08)
head_l, head_r = _head_edges_from_mask(
hair_mask, ys[0], ys[-1], pts["left_cheek"][0], pts["right_cheek"][0], min_gap)
head_xs = [x for x in (head_l, head_r) if x is not None]
xs = sorted(base_xs + head_xs) # 自左向右(6 或 7/8 点)
# 人脸/人头包围盒
fx0, fx1 = xs[0], xs[-1]
@@ -191,14 +201,17 @@ def create_annotated_image(image_bgr, measure_result, hair_mask=None):
face_cx = (fx0 + fx1) / 2
over = max(6, round(s * 0.030)) # 线超出包围盒的长度(参考图风格)
face_half = (fx1 - fx0) / 2 + over # 横线超出最外侧竖线一点
# v6 竖线纵向范围 = 发际线→下巴尖(不超出);v1 = 头顶→下巴尖并两端超出一点
v_top = fy0 if variant == "v6" else fy0 - over
v_bot = fy1 if variant == "v6" else fy1 + over
# --- 1. 横向 5 条分界线(渐变,覆盖头宽并超出一点) ---
# --- 1. 横向分界线(渐变,覆盖头宽并超出一点) ---
for cy in ys:
draw_gradient_horizontal_line(buf, face_cx, cy, half_length=face_half, width=line_w)
# --- 2. 纵向竖线(渐变,超出头顶/下巴一点 ---
# --- 2. 纵向竖线(渐变,覆盖 v_top→v_bot ---
for vx in xs:
draw_gradient_vertical_line(buf, vx, fy0 - over, fy1 + over, width=line_w)
draw_gradient_vertical_line(buf, vx, v_top, v_bot, width=line_w)
canvas = Image.fromarray(buf, mode="RGBA")
draw = ImageDraw.Draw(canvas)
@@ -214,11 +227,17 @@ def create_annotated_image(image_bgr, measure_result, hair_mask=None):
draw.text((x, max(2, ys[i] - th - name_gap)), text, fill=LINE_COLOR, font=font)
# --- 3b. 左侧四庭:名 + 数值两行(无 cm)+ 竖向虚线双箭头 ---
court_cm = [measure_result.top_cm, measure_result.upper_cm,
measure_result.middle_cm, measure_result.lower_cm]
court_name = ["顶庭", "上庭", "中庭", "下庭"]
if variant == "v6":
court_cm = [measure_result.upper_cm, measure_result.middle_cm, measure_result.lower_cm]
court_name = ["上庭", "中庭", "下庭"]
n_court = 3
else:
court_cm = [measure_result.top_cm, measure_result.upper_cm,
measure_result.middle_cm, measure_result.lower_cm]
court_name = ["顶庭", "上庭", "中庭", "下庭"]
n_court = 4
arrow_x = max(arrow_size + 1, fx0 - pad) # 竖箭头所在 x(脸左侧,贴近最左竖线)
for i in range(4):
for i in range(n_court):
y_a, y_b = ys[i], ys[i + 1]
# 竖向虚线双箭头,覆盖该庭高度(略收一点避免压到横线)
inset = min(arrow_size, (y_b - y_a) * 0.12)