···
30
30
import androidx.compose.ui.viewinterop.AndroidView
31
31
import androidx.lifecycle.LifecycleOwner
32
32
import androidx.lifecycle.compose.LocalLifecycleOwner
33
33
+
import com.google.android.gms.tasks.Tasks
33
34
import com.google.mlkit.vision.common.InputImage
34
35
import com.google.mlkit.vision.pose.Pose
35
36
import com.google.mlkit.vision.pose.PoseDetection
···
48
49
import com.performancecoachlab.posedetection.custom.CustomObjectRespository
49
50
import com.performancecoachlab.posedetection.objects.createObjectDetector
50
51
import com.performancecoachlab.posedetection.recording.AnalysisObject
52
52
+
import com.performancecoachlab.posedetection.recording.AnalysisResult
51
53
import kotlinx.coroutines.delay
52
54
import kotlinx.coroutines.launch
53
55
···
65
67
) {
66
68
var bitmap by remember { mutableStateOf<ImageBitmap?>(null) }
67
69
var skeleton by remember { mutableStateOf(Skeleton(width = 0f, height = 0f)) }
70
70
+
var objectsDetected by remember { mutableStateOf<List<AnalysisObject>>(emptyList()) }
68
71
val options =
69
72
PoseDetectorOptions.Builder().setDetectorMode(PoseDetectorOptions.STREAM_MODE).build()
70
73
val poseDetector = PoseDetection.getClient(options)
···
137
140
val img = InputImage.fromMediaImage(
138
141
image, imageProxy.imageInfo.rotationDegrees
139
142
)
140
140
-
objectDetector?.process(img)?.addOnSuccessListener { detectedObjects ->
143
143
+
val objectDetectionTask = objectDetector?.process(img)?.addOnSuccessListener { detectedObjects ->
141
144
detectedObjects.map { detectedObject ->
142
145
AnalysisObject(
143
146
boundingBox = Rect(
···
150
153
labels = detectedObject.labels.mapNotNull { if(it.confidence>0)it.text else null }
151
154
)
152
155
}.also {
156
156
+
objectsDetected = it
153
157
customObjectRepository.updateCustomObject(it)
154
158
}
155
159
}?.addOnFailureListener { e ->
156
160
println(e)
157
161
}
158
158
-
poseDetector.process(img).addOnSuccessListener { pose ->
162
162
+
163
163
+
val poseDetectionTask = poseDetector.process(img).addOnSuccessListener { pose ->
159
164
skeleton = skeleton(pose, timestamp, img.width, img.height)
160
165
skeletonRepository.updateSkeleton(skeleton.mirror())
166
166
+
}.addOnFailureListener { e ->
167
167
+
println(e)
168
168
+
}
169
169
+
170
170
+
Tasks.whenAllComplete(objectDetectionTask, poseDetectionTask).addOnCompleteListener {
161
171
bitmap =
162
172
imageProxy.toBitmap().rotate(imageProxy.imageInfo.rotationDegrees.toFloat())
163
173
.asImageBitmap().let {
164
174
addFrame(it,timestamp)
165
165
-
it.drawSkeleton(if (drawSkeleton) skeleton else null, 0f)
175
175
+
if( drawSkeleton) {
176
176
+
it.drawAnalysisResults(AnalysisResult(
177
177
+
skeleton = skeleton,
178
178
+
objects = objectsDetected
179
179
+
))
180
180
+
}else{
181
181
+
it.drawSkeleton(null)
182
182
+
}
166
183
}
167
167
-
}.addOnFailureListener { e ->
168
168
-
}.addOnCompleteListener {
169
184
imageProxy.close()
170
185
}
171
186
} ?: imageProxy.close()
···
14
14
import androidx.compose.ui.graphics.rotate
15
15
import androidx.compose.ui.unit.Density
16
16
import androidx.compose.ui.unit.LayoutDirection
17
17
+
import androidx.compose.ui.unit.min
17
18
import com.performancecoachlab.posedetection.recording.AnalysisResult
18
19
import com.performancecoachlab.posedetection.skeleton.Skeleton
19
20
···
133
134
val maxY = joints.maxOfOrNull { joint -> joint.y } ?: 0f
134
135
kotlin.math.max(maxX - minX, maxY - minY)
135
136
} ?: 1f
136
136
-
val scaleFactor = skeletonSize / kotlin.math.min(it.width, it.height)
137
137
+
val minDime = kotlin.math.min(it.width, it.height).toFloat()
138
138
+
val scaleFactor = skeletonSize / minDime
137
139
val baseStrokeWidth = 30f
138
138
-
val scaledStrokeWidth = baseStrokeWidth * scaleFactor
140
140
+
val scaledStrokeWidth = (baseStrokeWidth * scaleFactor).coerceIn(2f, minDime/50f)
139
141
140
142
drawScope.draw(
141
143
Density(1f),
···
146
148
drawImage(it)
147
149
analysisResults.objects.forEach { analysisObject ->
148
150
drawRect(
149
149
-
color = Color.Blue,
151
151
+
color = Color.Red,
150
152
topLeft = androidx.compose.ui.geometry.Offset(
151
153
analysisObject.boundingBox.left,
152
154
analysisObject.boundingBox.top