Step counter test1
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file PoseFrame.kt
|
||||
* @brief Time-stamped, per-frame pose snapshot buffered across a recording session.
|
||||
*/
|
||||
package com.example.jnicpp.bowling
|
||||
|
||||
import com.google.mlkit.vision.pose.PoseLandmark
|
||||
|
||||
/**
|
||||
* @brief A single joint's 2D position, in the same analysis-image pixel space as [SmoothedLandmark].
|
||||
*
|
||||
* Deliberately drops the confidence field -- by the time a landmark becomes
|
||||
* part of a [PoseFrame] it's already passed the
|
||||
* [PoseSkeletonRenderer.MIN_LIKELIHOOD] gate (see [buildPoseFrame]), so
|
||||
* downstream step-detection logic only ever sees positions worth trusting.
|
||||
*
|
||||
* @param x Pixel x coordinate, in analysis-image space.
|
||||
* @param y Pixel y coordinate, in analysis-image space.
|
||||
*/
|
||||
data class LandmarkPoint(val x: Float, val y: Float)
|
||||
|
||||
/**
|
||||
* @brief One time-stamped sample of a bowler's pose, buffered by
|
||||
* [CameraViewModel] over a recording session for step-detection
|
||||
* logic to analyze frame-by-frame movement.
|
||||
*
|
||||
* Ankle/hip fields hold the position after [AnkleHipMovingAverageFilter]'s
|
||||
* simple moving average on top of [PoseLandmarkSmoother]'s per-frame EMA --
|
||||
* those are the joints step timing is derived from, so they get the extra
|
||||
* jitter reduction. The matching `*Raw` fields keep the pre-SMA (but still
|
||||
* EMA'd) position alongside it, so the smoothing can be compared against or
|
||||
* re-tuned later without needing to re-record; [LiveStepDetector] also
|
||||
* deliberately reads the `*Raw` fields itself for peak detection, since the
|
||||
* heavier SMA smoothing risks flattening a footfall's brief motion. Every
|
||||
* field is nullable because a joint isn't always reliably detected in a
|
||||
* given frame -- see [buildPoseFrame].
|
||||
*
|
||||
* @param timestampMs Wall-clock time this frame was captured, in milliseconds.
|
||||
* @param leftAnkle SMA-smoothed left ankle position, or null if unreliable.
|
||||
* @param rightAnkle SMA-smoothed right ankle position, or null if unreliable.
|
||||
* @param leftAnkleRaw EMA-only (pre-SMA) left ankle position, or null if unreliable.
|
||||
* @param rightAnkleRaw EMA-only (pre-SMA) right ankle position, or null if unreliable.
|
||||
* @param leftKnee Left knee position, or null if unreliable.
|
||||
* @param rightKnee Right knee position, or null if unreliable.
|
||||
* @param leftHip SMA-smoothed left hip position, or null if unreliable.
|
||||
* @param rightHip SMA-smoothed right hip position, or null if unreliable.
|
||||
* @param leftHipRaw EMA-only (pre-SMA) left hip position, or null if unreliable.
|
||||
* @param rightHipRaw EMA-only (pre-SMA) right hip position, or null if unreliable.
|
||||
* @param leftShoulder Left shoulder position, or null if unreliable.
|
||||
* @param rightShoulder Right shoulder position, or null if unreliable.
|
||||
* @param leftElbow Left elbow position, or null if unreliable.
|
||||
* @param rightElbow Right elbow position, or null if unreliable.
|
||||
* @param leftWrist Left wrist position, or null if unreliable.
|
||||
* @param rightWrist Right wrist position, or null if unreliable.
|
||||
* @param angles Joint angles computed for this same frame.
|
||||
*/
|
||||
data class PoseFrame(
|
||||
val timestampMs: Long,
|
||||
val leftAnkle: LandmarkPoint?,
|
||||
val rightAnkle: LandmarkPoint?,
|
||||
val leftAnkleRaw: LandmarkPoint?,
|
||||
val rightAnkleRaw: LandmarkPoint?,
|
||||
val leftKnee: LandmarkPoint?,
|
||||
val rightKnee: LandmarkPoint?,
|
||||
val leftHip: LandmarkPoint?,
|
||||
val rightHip: LandmarkPoint?,
|
||||
val leftHipRaw: LandmarkPoint?,
|
||||
val rightHipRaw: LandmarkPoint?,
|
||||
val leftShoulder: LandmarkPoint?,
|
||||
val rightShoulder: LandmarkPoint?,
|
||||
val leftElbow: LandmarkPoint?,
|
||||
val rightElbow: LandmarkPoint?,
|
||||
val leftWrist: LandmarkPoint?,
|
||||
val rightWrist: LandmarkPoint?,
|
||||
val angles: PoseAngles
|
||||
)
|
||||
|
||||
/**
|
||||
* @brief Builds a [PoseFrame] from one frame's detection results.
|
||||
*
|
||||
* @param timestampMs Wall-clock time this frame was captured, in milliseconds.
|
||||
* @param landmarks EMA-smoothed landmarks for this frame, keyed by ML Kit's `PoseLandmark` type constant.
|
||||
* @param smoothedAnkleHip SMA-smoothed ankle/hip positions for this frame,
|
||||
* expected to come from an [AnkleHipMovingAverageFilter] fed the
|
||||
* same [landmarks], keyed the same way as [landmarks] itself.
|
||||
* @param angles Joint angles computed for this same frame.
|
||||
* @return The assembled [PoseFrame], with each landmark field null wherever
|
||||
* it wasn't reliably detected.
|
||||
*/
|
||||
fun buildPoseFrame(
|
||||
timestampMs: Long,
|
||||
landmarks: Map<Int, SmoothedLandmark>,
|
||||
smoothedAnkleHip: Map<Int, LandmarkPoint>,
|
||||
angles: PoseAngles
|
||||
): PoseFrame {
|
||||
/**
|
||||
* @brief Looks up one landmark and converts it to a [LandmarkPoint], gated by confidence.
|
||||
* @param type ML Kit `PoseLandmark` type constant to look up.
|
||||
* @return The landmark's position, or null if missing or below [PoseSkeletonRenderer.MIN_LIKELIHOOD].
|
||||
*/
|
||||
fun point(type: Int): LandmarkPoint? {
|
||||
val landmark = landmarks[type] ?: return null
|
||||
if (landmark.inFrameLikelihood < PoseSkeletonRenderer.MIN_LIKELIHOOD) return null
|
||||
return LandmarkPoint(landmark.x, landmark.y)
|
||||
}
|
||||
|
||||
return PoseFrame(
|
||||
timestampMs = timestampMs,
|
||||
leftAnkle = smoothedAnkleHip[PoseLandmark.LEFT_ANKLE],
|
||||
rightAnkle = smoothedAnkleHip[PoseLandmark.RIGHT_ANKLE],
|
||||
leftAnkleRaw = point(PoseLandmark.LEFT_ANKLE),
|
||||
rightAnkleRaw = point(PoseLandmark.RIGHT_ANKLE),
|
||||
leftKnee = point(PoseLandmark.LEFT_KNEE),
|
||||
rightKnee = point(PoseLandmark.RIGHT_KNEE),
|
||||
leftHip = smoothedAnkleHip[PoseLandmark.LEFT_HIP],
|
||||
rightHip = smoothedAnkleHip[PoseLandmark.RIGHT_HIP],
|
||||
leftHipRaw = point(PoseLandmark.LEFT_HIP),
|
||||
rightHipRaw = point(PoseLandmark.RIGHT_HIP),
|
||||
leftShoulder = point(PoseLandmark.LEFT_SHOULDER),
|
||||
rightShoulder = point(PoseLandmark.RIGHT_SHOULDER),
|
||||
leftElbow = point(PoseLandmark.LEFT_ELBOW),
|
||||
rightElbow = point(PoseLandmark.RIGHT_ELBOW),
|
||||
leftWrist = point(PoseLandmark.LEFT_WRIST),
|
||||
rightWrist = point(PoseLandmark.RIGHT_WRIST),
|
||||
angles = angles
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user