Skip to content

bug(pose): shoulder tilt wraps to ~±180° and misreads as over-tilt #12

Description

@kmch4n

Summary

calculate_horizontal_angle(...) returns the raw atan2 direction angle of the left→right shoulder vector. When that vector points in the −x image direction (right-shoulder keypoint lands left of the left-shoulder keypoint, common at oblique camera angles or certain body orientations), the angle comes out near ±180° even when the shoulder line is nearly horizontal. evaluate_shoulder_tilt(...) then takes abs(angle), so a near-horizontal posture is scored as a large tilt → "Over-tilt" (Fix).

Expected behavior

A near-horizontal shoulder line should read ~0° regardless of which shoulder is on the left/right in image space. Tilt magnitude should be the deviation from horizontal, folded into [−90°, 90°].

Actual behavior

Frames with a left-pointing shoulder vector report values like -163° / -176° and are graded "Over-tilt", even when the skier's shoulders are visually level.

Evidence

  • src/skisense/pose_analyzer.py:59-61calculate_horizontal_angle returns degrees(atan2(dy, dx)) with no wraparound handling.
  • evaluate_shoulder_tilt(...) uses abs(angle) against ±10/±20 thresholds, so ~±180° always fails.
  • Observed during SAM 3D Body verification on input/skier.jpg (Shoulder Tilt -163.8°) and a video best shot (-176.3°).

Suspected cause

Direction angle (full −180°..180° range) is used where only tilt-from-horizontal (a ±90° quantity) is meaningful.

Suggested fix

Normalize the angle into [−90°, 90°], e.g.:

angle = math.degrees(math.atan2(dy, dx))
if angle > 90:
    angle -= 180
elif angle < -90:
    angle += 180
return angle

This is backend-independent (shoulder tilt is computed in 2D image space for both SAM 3D Body and YOLO11-Pose).

Acceptance criteria

  • A near-horizontal shoulder line reads ~0° irrespective of left/right image ordering.
  • Sign convention (which way is "right side higher") documented and consistent.
  • Re-verify on the frames that previously reported ~±180°.

Priority

medium

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:mediumMedium priority

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions