Building an AI-Powered Jumping Jacks Counter App with Pose Estimation Using QuickPose iOS SDK
Are you searching for a way to develop an AI-powered Jumping Jacks counter for your fitness app? Jumping Jacks are a classic full-body exercise that engages multiple muscle groups, including the deltoids, quadriceps, hamstrings, calves, and core. This aerobic exercise is excellent for improving cardiovascular fitness, enhancing coordination, and burning calories.
In this guide, you’ll learn how to create a Jumping Jacks counter app using pose estimation with the QuickPose iOS SDK. Whether you’re building a new fitness app or adding advanced features to an existing one, this tutorial will help you leverage AI and pose estimation technology to deliver an accurate and user-friendly Jumping Jacks counter that stands out in the competitive fitness app market.
Steps to integrate a Jumping Jacks Counter into your app:
Register an SDK Key with QuickPose
Get your free SDK key on https://dev.quickpose.ai, usage limits may apply. SDK Keys are linked to your bundle ID, please check Key before distributing to the App Store.
This is a quick look to integrate the jumping jacks counter using the QuickPose iOS SDK. You can see the full documentation here: QuickPose iOS SDK Jumping Jacks Counter installation.
Activate Jumping Jacks Feature
feature = .fitness(.jumpingJacks)
feature = .fitness(.jumpingJacks, style: customOrConditionalStyle)
Form Feedback
We recommend using the feature feedback to guide the user if an error occurs.
quickPose.start(features: [.fitness(.jumpingJacks)], onFrame: { status, image, features, feedback, landmarks in
switch status {
case .success:
overlayImage = image
if let result = features.values.first {
feedbackText = "Jumping Jacks: \(Int(result.value * 100))%"
} else if let feedback = feedback.values.first, feedback.isRequired {
feedbackText = feedback.displayString
} else {
feedbackText = nil
}
case .noPersonFound:
feedbackText = "Stand in view";
case .sdkValidationError:
feedbackText = "Be back soon";
}
})
Conditional Styling
To give user feedback consider using conditional styling so that when the user’s measurement goes above a threshold, here 0.8, a green highlight is shown.
let greenHighlightStyle = QuickPose.Style(conditionalColors: [QuickPose.Style.ConditionalColor(min: 0.8, max: nil, color: UIColor.green)])
quickPose.start(features: [.fitness(.jumpingJacks, style: customOrConditionalStyle)],
onFrame: { status, image, features, feedback, landmarks in ...
})
How to Count Jumping Jacks
Real-time Jumping Jacks counting with AI
To count the Jumping Jacks declare a configurable threshold counter, which can be used to turn lots of our features into counts.
@State private var counter = QuickPoseThresholdCounter()
Then pass QuickPose’s Jumping Jacks result to the counter, and display in the feedback text declared above.
quickPose.start(features: [.fitness(.jumpingJacks)], onFrame: { status, image, features, feedback, landmarks in
switch status {
case .success:
overlayImage = image
if let result = features.values.first {
let counterState = counter.count(result.value)
feedbackText = "\(counterState.count) Jumping Jacks"
} else {
feedbackText = nil
}
case .noPersonFound:
feedbackText = "Stand in view";
case .sdkValidationError:
feedbackText = "Be back soon";
}
})
Jumping Jacks Timer
To time the Jumping Jacks declare a configurable threshold timer, which can be used to turn lots of our features into timers. For Jumping Jacks, we suggest modifying the default threshold, taking account of expected camera positioning and tilt.
@State private var timer = QuickPoseThresholdTimer(threshold: 0.2)
Then pass the result’s raw value to the timer, and display in the feedback text declared above.
quickPose.start(features: [.fitness(.jumpingJacks)], onFrame: { status, image, features, feedback, landmarks in
switch status {
case .success:
overlayImage = image
if let result = features.values.first {
let timerState = timer.time(result.value)
feedbackText = String(format: "%.1f", timerState.time) + "secs"
} else {
feedbackText = nil
}
case .noPersonFound:
feedbackText = "Stand in view";
case .sdkValidationError:
feedbackText = "Be back soon";
}
})