Skip to content

Commit 0a69ea2

Browse files
committed
Android 💚
- Adding image label
1 parent 776ce5a commit 0a69ea2

6 files changed

Lines changed: 107 additions & 20 deletions

File tree

android/ML Kit Examples/app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
implementation(libs.camera.camera2)
5858
implementation(libs.camera.view)
5959
implementation(libs.camera.lifecycle)
60+
implementation(libs.image.labeling)
6061

6162
testImplementation(libs.junit)
6263

android/ML Kit Examples/app/src/main/java/com/pradyotprakash/posedetection/MainActivity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ class MainActivity : ComponentActivity() {
3030

3131
override fun onCreate(savedInstanceState: Bundle?) {
3232
super.onCreate(savedInstanceState)
33-
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
33+
if (whichToRun == WhichToRun.PoseDetection) {
34+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
35+
}
3436
checkCameraPermission()
3537
enableEdgeToEdge()
3638
}

android/ML Kit Examples/app/src/main/java/com/pradyotprakash/posedetection/ProcessImage.kt

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,72 @@ import androidx.camera.core.ImageProxy
77
import androidx.compose.runtime.MutableState
88
import androidx.compose.runtime.snapshots.SnapshotStateList
99
import com.google.mlkit.vision.common.InputImage
10+
import com.google.mlkit.vision.label.ImageLabel
11+
import com.google.mlkit.vision.label.ImageLabeling
12+
import com.google.mlkit.vision.label.defaults.ImageLabelerOptions
1013
import com.google.mlkit.vision.pose.PoseDetection
1114
import com.google.mlkit.vision.pose.PoseLandmark
1215
import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions
1316

17+
val whichToRun = WhichToRun.ImageLabelling
18+
19+
enum class WhichToRun {
20+
PoseDetection,
21+
ImageLabelling,
22+
}
23+
1424
@OptIn(ExperimentalGetImage::class)
1525
fun processImageProxy(
26+
whichToRun: WhichToRun,
1627
imageProxy: ImageProxy,
1728
poseLandmarks: SnapshotStateList<PoseLandmark>,
29+
imageLabel: SnapshotStateList<ImageLabel>,
1830
imageWidth: MutableState<Int>,
1931
imageHeight: MutableState<Int>,
2032
) {
2133
val mediaImage = imageProxy.image ?: return
2234
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
2335

24-
val options = PoseDetectorOptions.Builder()
25-
.setDetectorMode(PoseDetectorOptions.STREAM_MODE)
26-
.setPreferredHardwareConfigs(PoseDetectorOptions.CPU_GPU)
27-
.build()
36+
when (whichToRun) {
37+
WhichToRun.PoseDetection -> {
38+
val poseDetectorOptions = PoseDetectorOptions.Builder()
39+
.setDetectorMode(PoseDetectorOptions.STREAM_MODE)
40+
.setPreferredHardwareConfigs(PoseDetectorOptions.CPU_GPU)
41+
.build()
2842

29-
val poseDetector = PoseDetection.getClient(options)
43+
val poseDetector = PoseDetection.getClient(poseDetectorOptions)
3044

31-
poseDetector.process(image)
32-
.addOnSuccessListener { pose ->
33-
poseLandmarks.clear()
34-
poseLandmarks.addAll(pose.allPoseLandmarks)
35-
imageWidth.value = mediaImage.width
36-
imageHeight.value = mediaImage.height
37-
}
38-
.addOnFailureListener { e ->
39-
Log.e("PoseDetection", "Detection failed", e)
45+
poseDetector.process(image)
46+
.addOnSuccessListener { pose ->
47+
poseLandmarks.clear()
48+
poseLandmarks.addAll(pose.allPoseLandmarks)
49+
imageWidth.value = mediaImage.width
50+
imageHeight.value = mediaImage.height
51+
}
52+
.addOnFailureListener { e ->
53+
Log.e("PoseDetection", "Detection failed", e)
54+
}
55+
.addOnCompleteListener {
56+
imageProxy.close()
57+
}
4058
}
41-
.addOnCompleteListener {
42-
imageProxy.close()
59+
60+
WhichToRun.ImageLabelling -> {
61+
val imageLabelerOptions = ImageLabelerOptions.Builder()
62+
.build()
63+
64+
val labeler = ImageLabeling.getClient(imageLabelerOptions)
65+
66+
labeler.process(image)
67+
.addOnSuccessListener { label ->
68+
imageLabel.addAll(label)
69+
}
70+
.addOnFailureListener { e ->
71+
Log.e("ImageLabeler", "Detection failed", e)
72+
}
73+
.addOnSuccessListener {
74+
imageProxy.close()
75+
}
4376
}
77+
}
4478
}

android/ML Kit Examples/app/src/main/java/com/pradyotprakash/posedetection/cameraScreen/CameraScreen.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,25 @@ import androidx.camera.lifecycle.ProcessCameraProvider
88
import androidx.camera.view.PreviewView
99
import androidx.compose.foundation.layout.Box
1010
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.lazy.LazyColumn
13+
import androidx.compose.foundation.lazy.items
14+
import androidx.compose.material.icons.Icons
15+
import androidx.compose.material.icons.automirrored.filled.List
16+
import androidx.compose.material.icons.filled.List
17+
import androidx.compose.material3.Checkbox
18+
import androidx.compose.material3.ExperimentalMaterial3Api
19+
import androidx.compose.material3.Icon
20+
import androidx.compose.material3.IconButton
21+
import androidx.compose.material3.ModalBottomSheet
22+
import androidx.compose.material3.ModalBottomSheetDefaults
23+
import androidx.compose.material3.Text
24+
import androidx.compose.material3.rememberModalBottomSheetState
1125
import androidx.compose.runtime.Composable
1226
import androidx.compose.runtime.mutableIntStateOf
1327
import androidx.compose.runtime.remember
28+
import androidx.compose.runtime.rememberCoroutineScope
29+
import androidx.compose.ui.Alignment
1430
import androidx.compose.ui.Modifier
1531
import androidx.compose.ui.platform.LocalConfiguration
1632
import androidx.compose.ui.platform.LocalContext
@@ -19,9 +35,13 @@ import androidx.compose.ui.unit.dp
1935
import androidx.compose.ui.viewinterop.AndroidView
2036
import androidx.core.content.ContextCompat
2137
import androidx.lifecycle.compose.LocalLifecycleOwner
38+
import com.pradyotprakash.posedetection.WhichToRun
2239
import com.pradyotprakash.posedetection.processImageProxy
40+
import com.pradyotprakash.posedetection.whichToRun
41+
import kotlinx.coroutines.launch
2342
import java.util.concurrent.Executors
2443

44+
@OptIn(ExperimentalMaterial3Api::class)
2545
@Composable
2646
fun CameraScreen(modifier: Modifier = Modifier) {
2747
val configuration = LocalConfiguration.current
@@ -30,8 +50,10 @@ fun CameraScreen(modifier: Modifier = Modifier) {
3050
val lifecycleOwner = LocalLifecycleOwner.current
3151
val previewView = remember { PreviewView(context) }
3252
val poseLandmarks = rememberPoseState()
53+
val imageLabel = rememberImageLabel()
3354
val imageWidth = remember { mutableIntStateOf(1) }
3455
val imageHeight = remember { mutableIntStateOf(1) }
56+
val sheetState = rememberModalBottomSheetState()
3557

3658
Box(
3759
modifier = modifier,
@@ -50,8 +72,10 @@ fun CameraScreen(modifier: Modifier = Modifier) {
5072

5173
imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor()) { imageProxy ->
5274
processImageProxy(
75+
whichToRun,
5376
imageProxy,
5477
poseLandmarks,
78+
imageLabel,
5579
imageWidth,
5680
imageHeight,
5781
)
@@ -85,5 +109,23 @@ fun CameraScreen(modifier: Modifier = Modifier) {
85109
screenHeight
86110
)
87111
}
112+
113+
if (whichToRun == WhichToRun.ImageLabelling) {
114+
ModalBottomSheet(
115+
sheetState = sheetState,
116+
onDismissRequest = {}
117+
) {
118+
LazyColumn(
119+
modifier = Modifier.fillMaxSize(),
120+
) {
121+
items(imageLabel.map { it.text }.toSet().toList()) {
122+
Text(
123+
it,
124+
modifier = Modifier.padding(2.dp)
125+
)
126+
}
127+
}
128+
}
129+
}
88130
}
89131
}

android/ML Kit Examples/app/src/main/java/com/pradyotprakash/posedetection/cameraScreen/PoseState.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.mutableStateListOf
55
import androidx.compose.runtime.remember
66
import androidx.compose.runtime.snapshots.SnapshotStateList
7+
import com.google.mlkit.vision.label.ImageLabel
78
import com.google.mlkit.vision.pose.PoseLandmark
89

910
@Composable
1011
fun rememberPoseState(): SnapshotStateList<PoseLandmark> {
1112
return remember { mutableStateListOf() }
13+
}
14+
15+
@Composable
16+
fun rememberImageLabel(): SnapshotStateList<ImageLabel> {
17+
return remember { mutableStateListOf() }
1218
}

android/ML Kit Examples/gradle/libs.versions.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
[versions]
2-
agp = "8.8.0"
2+
agp = "8.8.2"
33
kotlin = "2.0.0"
44
coreKtx = "1.15.0"
55
junit = "4.13.2"
66
junitVersion = "1.2.1"
77
espressoCore = "3.6.1"
88
lifecycleRuntimeKtx = "2.8.7"
9-
activityCompose = "1.10.0"
10-
composeBom = "2025.01.01"
9+
activityCompose = "1.10.1"
10+
composeBom = "2025.03.00"
1111
poseDetectionAccurate = "18.0.0-beta5"
1212
poseDetection = "18.0.0-beta5"
1313
cameraxVersion = "1.4.1"
14+
imageLabeling = "17.0.9"
1415

1516
[libraries]
1617
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -33,6 +34,7 @@ camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "
3334
camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "cameraxVersion" }
3435
camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraxVersion" }
3536
camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraxVersion" }
37+
image-labeling = { group = "com.google.mlkit", name = "image-labeling", version.ref = "imageLabeling" }
3638

3739
[plugins]
3840
android-application = { id = "com.android.application", version.ref = "agp" }

0 commit comments

Comments
 (0)