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
chore: android use wide angle camera
author
nate
date
5 months ago
(Jan 22, 2026, 3:02 PM +0200)
commit
47014b33
47014b33ee36da3d12ecdb40cc1220ff5a4a942a
parent
0cf98462
0cf98462d3fde66b0a17bd8a9826ef3e7bc747f1
+58
-4
2 changed files
Expand all
Collapse all
Unified
Split
posedetection
build.gradle.kts
src
androidMain
kotlin
com.performancecoachlab
posedetection
camera
CameraView.android.kt
+1
-1
posedetection/build.gradle.kts
Reviewed
···
6
6
7
7
mavenPublishing {
8
8
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
9
9
-
coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.5.1")
9
9
+
coordinates("com.performancecoachlab.posedetection", "posedetection-compose", "4.6.0")
10
10
11
11
pom {
12
12
name.set("Pose Detection")
+57
-3
posedetection/src/androidMain/kotlin/com.performancecoachlab/posedetection/camera/CameraView.android.kt
Reviewed
···
55
55
import kotlinx.coroutines.launch
56
56
import org.tensorflow.lite.support.image.TensorImage
57
57
import org.tensorflow.lite.task.vision.detector.ObjectDetector
58
58
+
import android.hardware.camera2.CameraCharacteristics
59
59
+
import androidx.camera.camera2.interop.Camera2CameraInfo
60
60
+
import androidx.camera.core.CameraInfo
61
61
+
import androidx.camera.core.CameraSelector
62
62
+
import co.touchlab.kermit.Logger
58
63
59
64
// Data class to hold recording state for each recording ID
60
65
data class RecordingSlot(
···
62
67
var firstTimestampMs: Long? = null,
63
68
val outputPath: String
64
69
)
70
70
+
71
71
+
private fun buildBackUltraWideSelectorOrNull(cameraProvider: ProcessCameraProvider): CameraSelector? {
72
72
+
return try {
73
73
+
val bestBackInfo: CameraInfo? = cameraProvider.availableCameraInfos
74
74
+
.asSequence()
75
75
+
.filter { info ->
76
76
+
Camera2CameraInfo.from(info)
77
77
+
.getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK
78
78
+
}
79
79
+
.mapNotNull { info ->
80
80
+
val focalLengths: FloatArray? = Camera2CameraInfo.from(info)
81
81
+
.getCameraCharacteristic(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
82
82
+
val minFocal = focalLengths?.minOrNull()
83
83
+
if (minFocal != null) info to minFocal else null
84
84
+
}
85
85
+
// Smallest focal length => widest FOV (ultra-wide on multi-cam devices)
86
86
+
.minByOrNull { (_, minFocal) -> minFocal }
87
87
+
?.first
88
88
+
89
89
+
bestBackInfo?.let { selectedInfo ->
90
90
+
CameraSelector.Builder()
91
91
+
.addCameraFilter { cameraInfos ->
92
92
+
// Defensive: ensure we ONLY ever return a back-facing camera.
93
93
+
cameraInfos.filter { candidate ->
94
94
+
candidate == selectedInfo &&
95
95
+
Camera2CameraInfo.from(candidate)
96
96
+
.getCameraCharacteristic(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK
97
97
+
}
98
98
+
}
99
99
+
.build()
100
100
+
}
101
101
+
} catch (t: Throwable) {
102
102
+
Logger.w(t) { "Failed to select ultra-wide back camera, falling back to default back." }
103
103
+
null
104
104
+
}
105
105
+
}
65
106
66
107
@OptIn(ExperimentalGetImage::class)
67
108
@Composable
···
193
234
194
235
}
195
236
196
196
-
LaunchedEffect(lifecycleOwner) {
237
237
+
LaunchedEffect(lifecycleOwner, frontCamera) {
197
238
val cameraProvider = ProcessCameraProvider.getInstance(context).get()
198
239
cameraProvider.unbindAll()
199
199
-
val cameraSelector = if (frontCamera) DEFAULT_FRONT_CAMERA else DEFAULT_BACK_CAMERA
240
240
+
241
241
+
val cameraSelector = if (frontCamera) {
242
242
+
DEFAULT_FRONT_CAMERA
243
243
+
} else {
244
244
+
buildBackUltraWideSelectorOrNull(cameraProvider) ?: DEFAULT_BACK_CAMERA
245
245
+
}
246
246
+
200
247
val preview = Preview.Builder().build().also {
201
248
it.surfaceProvider = previewView.surfaceProvider
202
249
}
···
234
281
}
235
282
}
236
283
}
237
237
-
cameraProvider.bindToLifecycle(
284
284
+
val camera = cameraProvider.bindToLifecycle(
238
285
lifecycleOwner,
239
286
cameraSelector,
240
287
preview,
241
288
imageAnalysis
242
289
)
290
290
+
291
291
+
// Helpful debug: see which physical camera ID CameraX picked.
292
292
+
runCatching {
293
293
+
val cameraId = Camera2CameraInfo.from(camera.cameraInfo).cameraId
294
294
+
Logger.d { "CameraX bound cameraId=$cameraId frontCamera=$frontCamera" }
295
295
+
}
296
296
+
243
297
previewView.scaleType = PreviewView.ScaleType.FIT_CENTER
244
298
}
245
299
Box(