feat(v2): add fall event regression engine
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package fall
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"silverpose/v2/internal/pose"
|
||||
)
|
||||
|
||||
var torsoJoints = [...]int{5, 6, 11, 12}
|
||||
var lowerJoints = [...]int{13, 14, 15, 16}
|
||||
|
||||
func assessPoseQuality(person pose.PersonPose, threshold float32, requireLowerBody bool) PoseQuality {
|
||||
if threshold < 0 || threshold > 1 {
|
||||
return PoseQuality{Reason: "invalid_threshold"}
|
||||
}
|
||||
visible := 0
|
||||
for _, keypoint := range person.Keypoints {
|
||||
if keypoint.Confidence >= threshold {
|
||||
visible++
|
||||
}
|
||||
}
|
||||
for _, index := range torsoJoints {
|
||||
if person.Keypoints[index].Confidence < threshold {
|
||||
return PoseQuality{Reason: "required_joint_low_confidence", VisibleJointCount: visible}
|
||||
}
|
||||
}
|
||||
if requireLowerBody {
|
||||
for _, index := range lowerJoints {
|
||||
if person.Keypoints[index].Confidence < threshold {
|
||||
return PoseQuality{Reason: "required_joint_low_confidence", VisibleJointCount: visible}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PoseQuality{Accepted: true, Reason: "accepted", VisibleJointCount: visible}
|
||||
}
|
||||
|
||||
func extractEvidence(person pose.PersonPose, quality PoseQuality, previous *PoseEvidence, horizontalAngleThreshold float32) PoseEvidence {
|
||||
if !quality.Accepted {
|
||||
return PoseEvidence{Reason: quality.Reason}
|
||||
}
|
||||
shoulderX, shoulderY := midpoint(person, 5, 6)
|
||||
hipX, hipY := midpoint(person, 11, 12)
|
||||
vectorX := hipX - shoulderX
|
||||
vectorY := hipY - shoulderY
|
||||
torsoLength := float32(math.Hypot(float64(vectorX), float64(vectorY)))
|
||||
if torsoLength == 0 {
|
||||
return PoseEvidence{HipCenterY: hipY, HasHipCenterY: true, TorsoLength: 0, Reason: "degenerate_torso"}
|
||||
}
|
||||
cosine := math.Max(-1, math.Min(1, math.Abs(float64(vectorX))/float64(torsoLength)))
|
||||
angle := float32(math.Acos(cosine) * 180 / math.Pi)
|
||||
rapid := previous != nil && previous.Accepted && previous.HasHipCenterY && hipY-previous.HipCenterY >= 0.5*torsoLength
|
||||
return PoseEvidence{
|
||||
Accepted: true, HorizontalPose: angle <= horizontalAngleThreshold,
|
||||
RapidVerticalChange: rapid, HorizontalAngleDegree: angle, HasAngle: true,
|
||||
HipCenterY: hipY, HasHipCenterY: true, TorsoLength: torsoLength, Reason: "accepted",
|
||||
}
|
||||
}
|
||||
|
||||
func midpoint(person pose.PersonPose, first, second int) (float32, float32) {
|
||||
return (person.Keypoints[first].X + person.Keypoints[second].X) / 2,
|
||||
(person.Keypoints[first].Y + person.Keypoints[second].Y) / 2
|
||||
}
|
||||
Reference in New Issue
Block a user