feat: 接口1/6 发际线贴近头顶时改为修正而非弃用置null
顶庭(头顶→发际线)<0.7cm 时不再返回 null: - 上庭 = 0.95×中庭 反推发际线;若越过头顶则顶庭固定 0.7cm(发际线钉在头顶下方) - hairline_source 新增 "corrected";to_response 始终输出完整四庭 - 标注图始终正常画发际线横线与庭段 - 接口6 三庭逻辑同步,去 discarded 分支 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -401,36 +401,22 @@ def _run_face_measure_data(image, variant="v1"):
|
||||
logger.warning("头发/耳朵分割失败,回退方案A:%s", seg_e)
|
||||
|
||||
result = measure_face(landmarks, hair_mask, w, h, head_pose=head_pose)
|
||||
discarded = result.hairline_discarded
|
||||
data = result.to_response()
|
||||
vd = result.vertical
|
||||
if variant == "v6":
|
||||
if discarded:
|
||||
# 发际线弃用:接口6 的上庭也依赖发际线,一并置 null;只保留中/下庭。
|
||||
base_px = vd["middle_court_px"] + vd["lower_court_px"]
|
||||
data["four_courts"]["upper_court_cm"] = None
|
||||
data["four_courts"]["ratios"] = {
|
||||
"upper_court": None,
|
||||
"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.middle_cm + result.lower_cm, 2)
|
||||
data["landmarks"]["hairline"] = None
|
||||
else:
|
||||
base_px = vd["upper_court_px"] + vd["middle_court_px"] + vd["lower_court_px"]
|
||||
# 接口6 是三庭:去掉顶庭相关字段(top_court_cm / ratios.top_court / landmarks.hair_top)
|
||||
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)
|
||||
# 注:landmarks.hair_top 保留返回(供前端/下游定位头顶),但顶庭数值、
|
||||
# 占比、标注图仍按三庭处理,显示效果不变。
|
||||
# 接口6 是三庭:去掉顶庭相关字段(top_court_cm / ratios.top_court),
|
||||
# 比例分母按上/中/下三庭。发际线贴近头顶时已在 measure 修正,hairline 正常返回。
|
||||
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)
|
||||
# 注:landmarks.hair_top 保留返回(供前端/下游定位头顶),但顶庭数值、
|
||||
# 占比、标注图仍按三庭处理,显示效果不变。
|
||||
|
||||
# 七眼段宽度(cm)。eye1=左耳外段 eye2=左脸颊 eye3=左眼 eye4=两眼间距 eye5=右眼 eye6=右脸颊 eye7=右耳外段。
|
||||
# eye2~eye6(5段)只用内部分点,接口1/6 共用;eye1/eye7 需耳朵分割端线,仅接口1 有。
|
||||
@@ -446,10 +432,9 @@ def _run_face_measure_data(image, variant="v1"):
|
||||
None if (a is None or b is None) else round((b - a) / pc, 2))
|
||||
if variant != "v6":
|
||||
# 接口1 额外算 eye1/eye7(左/右耳外段),需耳朵分割端线。
|
||||
# 竖向范围:发际线弃用时用眉心做上界(hair_top 不可靠),否则用头顶。
|
||||
# 竖向范围上界用头顶(hair_top 始终可用)。
|
||||
from face_analysis.annotation import _ear_edges_from_mask
|
||||
top_y = (vd["brow_center"][1] if result.hairline_discarded
|
||||
else vd["hair_top"][1])
|
||||
top_y = vd["hair_top"][1]
|
||||
head_l, head_r = _ear_edges_from_mask(
|
||||
ear_mask, hair_mask,
|
||||
top_y, vd["chin_tip"][1],
|
||||
@@ -709,11 +694,11 @@ def _run_face_measure_data_debug(image):
|
||||
_draw_text_cv2(vis_hl, f"hairline_y={hairline_y} (source={result.hairline_source})",
|
||||
(hairline_y, w - int(s * 0.5)), color=(0, 200, 255),
|
||||
scale=max(0.4, s * 0.0015))
|
||||
# 发际线弃用提示:顶庭 < 0.7cm 视为贴近头顶、不可靠
|
||||
if result.hairline_discarded:
|
||||
gap_cm = result.top_cm
|
||||
# 发际线修正提示:检测到的顶庭 < 0.7cm 视为贴近头顶、已按 0.95×中庭修正
|
||||
if getattr(result, "hairline_corrected", False):
|
||||
gap_cm = result.detected_top_cm
|
||||
_draw_text_cv2(vis_hl,
|
||||
f"⚠️ 发际线离头顶仅 {gap_cm:.2f}cm (<0.7cm),已弃用",
|
||||
f"⚠️ 发际线离头顶仅 {gap_cm:.2f}cm (<0.7cm),已按 0.95×中庭修正",
|
||||
(10, 10), color=(40, 40, 255), scale=max(0.5, s * 0.0022))
|
||||
put("hairline", vis_hl)
|
||||
|
||||
@@ -829,8 +814,8 @@ def _run_face_measure_data_debug(image):
|
||||
None if (a is None or b is None) else round((b - a) / pc, 2))
|
||||
from face_analysis.annotation import _ear_edges_from_mask as _eef
|
||||
lcx, rcx = epts["left_cheek"][0], epts["right_cheek"][0]
|
||||
# 弃用时用眉心做上界(与 _run_face_measure_data 一致)
|
||||
top_y = v["brow_center"][1] if result.hairline_discarded else v["hair_top"][1]
|
||||
# 竖向范围上界用头顶(hair_top 始终可用)
|
||||
top_y = v["hair_top"][1]
|
||||
head_l, head_r = _eef(ear_mask, hair_mask, top_y, v["chin_tip"][1],
|
||||
lcx, rcx, (lcx + rcx) / 2)
|
||||
data["seven_eyes"]["eye1"] = None if head_l is None else round((lcx - head_l) / pc, 2)
|
||||
|
||||
Reference in New Issue
Block a user