alpha
Login
or
Join now
nateholland.bsky.social
/
PoseDetection
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
fix: smooth out ios skeletons
author
nathan holland
date
1 year ago
(Jun 2, 2025, 10:26 PM +0300)
commit
ca427f5e
ca427f5e6b30b792a2eb81228cdebfc505dfa980
parent
b73aa5f3
b73aa5f356f80d699bdc39c2001ed2204f513999
+39
-1
2 changed files
Expand all
Collapse all
Unified
Split
posedetection
src
iosMain
kotlin
com
performancecoachlab
posedetection
camera
CameraEngine.kt
FrameProcessor.kt
+2
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/CameraEngine.kt
Reviewed
···
390
390
frameProcessor.analyseFrame(
391
391
cgImage, timestamp
392
392
) { skeleton ->
393
393
+
println("timestamp: $timestamp")
394
394
+
println(skeleton?.toString() ?: "No skeleton detected")
393
395
cameraPreviewLayer?.also { preview ->
394
396
skeleton?.let {
395
397
mapSkeletonToPreview(
+37
-1
posedetection/src/iosMain/kotlin/com/performancecoachlab/posedetection/camera/FrameProcessor.kt
Reviewed
···
76
76
}
77
77
}
78
78
79
79
+
class SkelBuffer(private val maxSize: Int) {
80
80
+
private val buffer = ArrayDeque<Skeleton>()
81
81
+
82
82
+
fun add(skeleton: Skeleton) {
83
83
+
buffer.addLast(skeleton)
84
84
+
if (buffer.size > maxSize) buffer.removeFirst()
85
85
+
}
86
86
+
87
87
+
fun smooth(skeleton: Skeleton): Skeleton {
88
88
+
add(skeleton)
89
89
+
val recentSkeletons = buffer.filter { it.timestamp >= skeleton.timestamp - 200 }
90
90
+
fun findMostRecentNonNullPoint(selector: (Skeleton) -> Skeleton.SkeletonCoordinate?): Skeleton.SkeletonCoordinate? {
91
91
+
return recentSkeletons.asReversed().firstNotNullOfOrNull(selector)
92
92
+
}
93
93
+
94
94
+
return Skeleton(
95
95
+
timestamp = skeleton.timestamp,
96
96
+
leftShoulder = skeleton.leftShoulder ?: findMostRecentNonNullPoint { it.leftShoulder },
97
97
+
rightShoulder = skeleton.rightShoulder ?: findMostRecentNonNullPoint { it.rightShoulder },
98
98
+
leftElbow = skeleton.leftElbow ?: findMostRecentNonNullPoint { it.leftElbow },
99
99
+
rightElbow = skeleton.rightElbow ?: findMostRecentNonNullPoint { it.rightElbow },
100
100
+
leftWrist = skeleton.leftWrist ?: findMostRecentNonNullPoint { it.leftWrist },
101
101
+
rightWrist = skeleton.rightWrist ?: findMostRecentNonNullPoint { it.rightWrist },
102
102
+
leftHip = skeleton.leftHip ?: findMostRecentNonNullPoint { it.leftHip },
103
103
+
rightHip = skeleton.rightHip ?: findMostRecentNonNullPoint { it.rightHip },
104
104
+
leftKnee = skeleton.leftKnee ?: findMostRecentNonNullPoint { it.leftKnee },
105
105
+
rightKnee = skeleton.rightKnee ?: findMostRecentNonNullPoint { it.rightKnee },
106
106
+
leftAnkle = skeleton.leftAnkle ?: findMostRecentNonNullPoint { it.leftAnkle },
107
107
+
rightAnkle = skeleton.rightAnkle ?: findMostRecentNonNullPoint { it.rightAnkle },
108
108
+
width = skeleton.width,
109
109
+
height = skeleton.height
110
110
+
)
111
111
+
}
112
112
+
}
113
113
+
79
114
@OptIn(ExperimentalForeignApi::class)
80
115
class FrameProcessor() {
116
116
+
private val skelBuffer = SkelBuffer(maxSize = 10)
81
117
private var regionOfInterest = CGRectMake(0.0, 0.0, 1.0, 1.0)
82
118
@OptIn(BetaInteropApi::class)
83
119
fun analyseFrame(cgImage: CGImageRef?, timestamp: Long, onProccessed: (Skeleton?) -> Unit) {
···
143
179
height = height.toFloat(),
144
180
width = width.toFloat()
145
181
)
146
146
-
onProccessed(updatedSkeleton)
182
182
+
onProccessed(skelBuffer.smooth(updatedSkeleton))
147
183
}
148
184
}
149
185
}