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-61 — calculate_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
Summary
calculate_horizontal_angle(...)returns the rawatan2direction 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 takesabs(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-61—calculate_horizontal_anglereturnsdegrees(atan2(dy, dx))with no wraparound handling.evaluate_shoulder_tilt(...)usesabs(angle)against ±10/±20 thresholds, so ~±180° always fails.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.:
This is backend-independent (shoulder tilt is computed in 2D image space for both SAM 3D Body and YOLO11-Pose).
Acceptance criteria
Priority
medium