@@ -6,6 +6,7 @@ import android.graphics.BitmapFactory
66import android.graphics.Matrix
77import android.media.ExifInterface
88import android.net.Uri
9+ import android.util.Log
910import androidx.camera.core.ImageCapture
1011import androidx.compose.material.icons.Icons
1112import androidx.compose.material.icons.filled.PersonOff
@@ -14,9 +15,12 @@ import androidx.compose.material3.Icon
1415import androidx.compose.ui.graphics.Color
1516import co.stonephone.stonecamera.MyApplication
1617import co.stonephone.stonecamera.StoneCameraViewModel
17- import co.stonephone.stonecamera.utils.ImageSegmenterHelper
1818import com.google.mediapipe.framework.image.BitmapImageBuilder
1919import com.google.mediapipe.framework.image.ByteBufferExtractor
20+ import com.google.mediapipe.tasks.core.BaseOptions
21+ import com.google.mediapipe.tasks.core.Delegate
22+ import com.google.mediapipe.tasks.vision.core.RunningMode
23+ import com.google.mediapipe.tasks.vision.imagesegmenter.ImageSegmenter
2024import com.google.mediapipe.tasks.vision.imagesegmenter.ImageSegmenterResult
2125import kotlinx.coroutines.CoroutineScope
2226import kotlinx.coroutines.Dispatchers
@@ -26,20 +30,21 @@ import java.util.Objects
2630import kotlin.math.max
2731import kotlin.math.min
2832
33+
2934class PortraitModePlugin : IPlugin {
3035 override val id: String = " portraitModePlugin"
3136 override val name: String = " Portrait Mode"
3237
33- private lateinit var imageSegmenterHelper : ImageSegmenterHelper
38+ private val logTag : String = " PortraitMode "
3439
35- override fun initialize (viewModel : StoneCameraViewModel ) {
36- imageSegmenterHelper = ImageSegmenterHelper (
37- context = MyApplication .getAppContext(),
38- currentModel = ImageSegmenterHelper .MODEL_SELFIE_SEGMENTER ,
39- currentDelegate = ImageSegmenterHelper .DELEGATE_CPU ,
40- )
40+ private var imagesegmenter: ImageSegmenter ? = null
4141
42- imageSegmenterHelper.setupImageSegmenter()
42+ init {
43+ setupImageSegmenter()
44+ }
45+
46+ override fun initialize (viewModel : StoneCameraViewModel ) {
47+ setupImageSegmenter()
4348 }
4449
4550 override fun onImageSaved (
@@ -61,10 +66,10 @@ class PortraitModePlugin : IPlugin {
6166 val rotation: Int = getOriginalImageRotation(contentResolver, originalImageUri)
6267
6368 val segmentationResults: ImageSegmenterResult =
64- imageSegmenterHelper.segmentImageFile (BitmapImageBuilder (originalImage).build())
69+ imagesegmenter?.segment (BitmapImageBuilder (originalImage).build())
6570 ? : return @launch
6671
67- // TODO Blur mask edge with https://developer.android.com/reference/android/graphics/BlurMaskFilter
72+ // TODO try and use the confidence mask. Will give floats in range 0 => 1. Apply blur on a percent of the confidence.
6873 val backgroundMask: ByteBuffer =
6974 ByteBufferExtractor .extract(segmentationResults.categoryMask().get())
7075
@@ -133,7 +138,7 @@ class PortraitModePlugin : IPlugin {
133138 )
134139 }
135140
136- // Stolen from https://stackoverflow.com/questions/21418892/understanding-super-fast-blur-algorithm?fbclid=IwZXh0bgNhZW0CMTEAAR1w91ucNtw4nU-Z8Z9RyMYFVUHWxfgt7ivsE7foTkwR2wmdx2losQqQ0sk_aem_Zrf_8344PRxW6SFzutkE7g
141+ // Borrowed from https://stackoverflow.com/questions/21418892/understanding-super-fast-blur-algorithm?fbclid=IwZXh0bgNhZW0CMTEAAR1w91ucNtw4nU-Z8Z9RyMYFVUHWxfgt7ivsE7foTkwR2wmdx2losQqQ0sk_aem_Zrf_8344PRxW6SFzutkE7g
137142 // Edited to apply the blur only on the mask
138143 private fun fastBlur (original : Bitmap , mask : ByteBuffer , radius : Int ): Bitmap {
139144 if (radius < 1 ) {
@@ -299,4 +304,27 @@ class PortraitModePlugin : IPlugin {
299304 )
300305 )
301306 }
307+
308+ private fun setupImageSegmenter () {
309+ val baseOptionsBuilder = BaseOptions .builder()
310+ baseOptionsBuilder.setDelegate(Delegate .GPU )
311+ baseOptionsBuilder.setModelAssetPath(" selfie_segmenter.tflite" )
312+
313+ try {
314+ val baseOptions = baseOptionsBuilder.build()
315+ val optionsBuilder = ImageSegmenter .ImageSegmenterOptions .builder()
316+ .setRunningMode(RunningMode .IMAGE )
317+ .setBaseOptions(baseOptions)
318+ .setOutputCategoryMask(true )
319+ .setOutputConfidenceMasks(true )
320+
321+ val options = optionsBuilder.build()
322+ imagesegmenter = ImageSegmenter .createFromOptions(MyApplication .getAppContext(), options)
323+ } catch (e: IllegalStateException ) {
324+ Log .e(logTag, " Image segmenter failed to load model with error: " + e.message)
325+ } catch (e: RuntimeException ) {
326+ // This occurs if the model being used does not support GPU
327+ Log .e(logTag, " Image segmenter failed to load model with error: " + e.message)
328+ }
329+ }
302330}
0 commit comments