Add live final-position feedback and fix step detection accuracy
Shows a live banner as each step of the approach is counted, ending in "FINAL POSITION - RELEASE!" once the 5th footfall lands. Also fixes LiveStepDetector's peak-prominence check, which compared a candidate footfall only to its immediate neighboring frame and silently dropped real steps that landed across several closely-spaced frames; it now tracks the true rise/fall trough on each side instead. Switches PoseAnalyzer to ML Kit's faster base pose model (the accurate model was starving the peak detector of frames on unaccelerated hardware), and makes LiveStepDetector's stillness-based reset toggleable, currently off for easier testing against recorded reference clips. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
afb9d800ff
commit
2bb7c6ca7b
@@ -14,6 +14,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
@@ -42,6 +43,14 @@ class BowlingCameraActivity : AppCompatActivity(), CameraXController.Callback {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "BowlingCameraActivity"
|
||||
|
||||
// This app is built around a 5-step approach: the bowler is in
|
||||
// their "final position" (planted/sliding, about to swing through
|
||||
// and release) the moment the 5th foot-plant of the current attempt
|
||||
// is detected. Step counting itself is LiveStepDetector's job (via
|
||||
// CameraViewModel.stepEvents) -- this just interprets that count for
|
||||
// the live banner below.
|
||||
private const val FINAL_STEP_COUNT = 5
|
||||
}
|
||||
|
||||
private lateinit var binding: ActivityBowlingCameraBinding
|
||||
@@ -182,6 +191,34 @@ class BowlingCameraActivity : AppCompatActivity(), CameraXController.Callback {
|
||||
if (events.isNotEmpty()) {
|
||||
Log.d(TAG, "Step ${events.size}: ${events.last()}")
|
||||
}
|
||||
// stepEvents is cleared back to empty on every reset
|
||||
// (new recording, or LiveStepDetector seeing the
|
||||
// bowler return to a stationary stance -- see
|
||||
// CameraViewModel.onPoseFrameUpdated), so this banner
|
||||
// naturally clears itself for the next attempt too.
|
||||
//
|
||||
// Shows every step as it's counted (not just the
|
||||
// final one) so it's obvious on screen whether
|
||||
// detection is actually seeing each footfall while
|
||||
// testing/tuning it, rather than only finding out at
|
||||
// step 5 that earlier steps were silently missed.
|
||||
if (events.isEmpty()) {
|
||||
binding.textFinalPosition.visibility = View.GONE
|
||||
} else {
|
||||
val reachedFinal = events.size >= FINAL_STEP_COUNT
|
||||
binding.textFinalPosition.visibility = View.VISIBLE
|
||||
binding.textFinalPosition.text = if (reachedFinal) {
|
||||
getString(R.string.final_position_reached)
|
||||
} else {
|
||||
getString(R.string.step_reached_format, events.size)
|
||||
}
|
||||
binding.textFinalPosition.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
this@BowlingCameraActivity,
|
||||
if (reachedFinal) R.color.final_position_highlight else R.color.white
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user