Skip to content

Commit d26e1e2

Browse files
author
izaak
committed
Clean up the SegmenterHelper to remove stream specific code
1 parent 6c58f8e commit d26e1e2

File tree

1 file changed

+1
-164
lines changed

1 file changed

+1
-164
lines changed
Lines changed: 1 addition & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package co.stonephone.stonecamera.utils
22

33
import android.content.Context
4-
import android.graphics.Bitmap
5-
import android.graphics.Matrix
6-
import android.os.SystemClock
74
import android.util.Log
8-
import androidx.camera.core.ImageProxy
9-
import com.google.mediapipe.framework.image.BitmapImageBuilder
10-
import com.google.mediapipe.framework.image.ByteBufferExtractor
115
import com.google.mediapipe.framework.image.MPImage
126
import com.google.mediapipe.tasks.core.BaseOptions
137
import com.google.mediapipe.tasks.core.Delegate
@@ -18,10 +12,8 @@ import java.nio.ByteBuffer
1812

1913
class ImageSegmenterHelper(
2014
var currentDelegate: Int = DELEGATE_CPU,
21-
var runningMode: RunningMode = RunningMode.IMAGE,
2215
var currentModel: Int = MODEL_DEEPLABV3,
2316
val context: Context,
24-
var imageSegmenterListener: SegmenterListener? = null
2517
) {
2618

2719
// For this example this needs to be a var so it can be reset on changes. If the Imagesegmenter
@@ -32,26 +24,6 @@ class ImageSegmenterHelper(
3224
setupImageSegmenter()
3325
}
3426

35-
// Segmenter must be closed when creating a new one to avoid returning results to a
36-
// non-existent object
37-
fun clearImageSegmenter() {
38-
imagesegmenter?.close()
39-
imagesegmenter = null
40-
}
41-
42-
fun setListener(listener: SegmenterListener) {
43-
imageSegmenterListener = listener
44-
}
45-
46-
fun clearListener() {
47-
imageSegmenterListener = null
48-
}
49-
50-
// Return running status of image segmenter helper
51-
fun isClosed(): Boolean {
52-
return imagesegmenter == null
53-
}
54-
5527
// Initialize the image segmenter using current settings on the
5628
// thread that is using it. CPU can be used with detectors
5729
// that are created on the main thread and used on a background thread, but
@@ -83,139 +55,36 @@ class ImageSegmenterHelper(
8355
}
8456
}
8557

86-
// if (imageSegmenterListener == null) {
87-
// throw IllegalStateException(
88-
// "ImageSegmenterListener must be set."
89-
// )
90-
// }
91-
9258
try {
9359
val baseOptions = baseOptionsBuilder.build()
9460
val optionsBuilder = ImageSegmenter.ImageSegmenterOptions.builder()
95-
.setRunningMode(runningMode)
61+
.setRunningMode(RunningMode.IMAGE)
9662
.setBaseOptions(baseOptions)
9763
.setOutputCategoryMask(true)
9864
.setOutputConfidenceMasks(false)
9965

100-
if (runningMode == RunningMode.LIVE_STREAM) {
101-
optionsBuilder.setResultListener(this::returnSegmentationResult)
102-
.setErrorListener(this::returnSegmentationHelperError)
103-
}
104-
10566
val options = optionsBuilder.build()
10667
imagesegmenter = ImageSegmenter.createFromOptions(context, options)
10768
} catch (e: IllegalStateException) {
108-
imageSegmenterListener?.onError(
109-
"Image segmenter failed to initialize. See error logs for details"
110-
)
11169
Log.e(
11270
TAG,
11371
"Image segmenter failed to load model with error: " + e.message
11472
)
11573
} catch (e: RuntimeException) {
11674
// This occurs if the model being used does not support GPU
117-
imageSegmenterListener?.onError(
118-
"Image segmenter failed to initialize. See error logs for " + "details",
119-
GPU_ERROR
120-
)
12175
Log.e(
12276
TAG,
12377
"Image segmenter failed to load model with error: " + e.message
12478
)
12579
}
12680
}
12781

128-
// Runs image segmentation on live streaming cameras frame-by-frame and
129-
// returns the results asynchronously to the caller.
130-
fun segmentLiveStreamFrame(imageProxy: ImageProxy, isFrontCamera: Boolean) {
131-
if (runningMode != RunningMode.LIVE_STREAM) {
132-
throw IllegalArgumentException(
133-
"Attempting to call segmentLiveStreamFrame" + " while not using RunningMode.LIVE_STREAM"
134-
)
135-
}
136-
137-
val frameTime = SystemClock.uptimeMillis()
138-
val bitmapBuffer = Bitmap.createBitmap(
139-
imageProxy.width, imageProxy.height, Bitmap.Config.ARGB_8888
140-
)
141-
142-
imageProxy.use {
143-
bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer)
144-
}
145-
146-
// Used for rotating the frame image so it matches our models
147-
val matrix = Matrix().apply {
148-
postRotate(imageProxy.imageInfo.rotationDegrees.toFloat())
149-
150-
if(isFrontCamera) {
151-
postScale(
152-
-1f,
153-
1f,
154-
imageProxy.width.toFloat(),
155-
imageProxy.height.toFloat()
156-
)
157-
}
158-
}
159-
160-
imageProxy.close()
161-
162-
val rotatedBitmap = Bitmap.createBitmap(
163-
bitmapBuffer,
164-
0,
165-
0,
166-
bitmapBuffer.width,
167-
bitmapBuffer.height,
168-
matrix,
169-
true
170-
)
171-
172-
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
173-
174-
imagesegmenter?.segmentAsync(mpImage, frameTime)
175-
}
176-
17782
// Runs image segmentation on single image and
17883
// returns the results asynchronously to the caller.
179-
18084
fun segmentImageFile(mpImage: MPImage): ImageSegmenterResult? {
181-
if (runningMode != RunningMode.IMAGE) {
182-
throw IllegalArgumentException(
183-
"Attempting to call segmentImageFile" + " while not using RunningMode.IMAGE"
184-
)
185-
}
18685
return imagesegmenter?.segment(mpImage)
18786
}
18887

189-
// MPImage isn't necessary for this example, but the listener requires it
190-
private fun returnSegmentationResult(
191-
result: ImageSegmenterResult, image: MPImage
192-
) {
193-
val finishTimeMs = SystemClock.uptimeMillis()
194-
195-
val inferenceTime = finishTimeMs - result.timestampMs()
196-
197-
// We only need the first mask for this sample because we are using
198-
// the OutputType CATEGORY_MASK, which only provides a single mask.
199-
val mpImage = result.categoryMask().get()
200-
201-
imageSegmenterListener?.onResults(
202-
ResultBundle(
203-
ByteBufferExtractor.extract(mpImage),
204-
mpImage.width,
205-
mpImage.height,
206-
inferenceTime
207-
)
208-
)
209-
}
210-
211-
// Return errors thrown during segmentation to this
212-
// ImageSegmenterHelper's caller
213-
private fun returnSegmentationHelperError(error: RuntimeException) {
214-
imageSegmenterListener?.onError(
215-
error.message ?: "An unknown error has occurred"
216-
)
217-
}
218-
21988
// Wraps results from inference, the time it takes for inference to be
22089
// performed.
22190
data class ResultBundle(
@@ -228,8 +97,6 @@ class ImageSegmenterHelper(
22897
companion object {
22998
const val DELEGATE_CPU = 0
23099
const val DELEGATE_GPU = 1
231-
const val OTHER_ERROR = 0
232-
const val GPU_ERROR = 1
233100

234101
const val MODEL_DEEPLABV3 = 0
235102
const val MODEL_HAIR_SEGMENTER = 1
@@ -243,36 +110,6 @@ class ImageSegmenterHelper(
243110

244111
private const val TAG = "ImageSegmenterHelper"
245112

246-
val labelColors = listOf(
247-
-16777216,
248-
-8388608,
249-
-16744448,
250-
-8355840,
251-
-16777088,
252-
-8388480,
253-
-16744320,
254-
-8355712,
255-
-12582912,
256-
-4194304,
257-
-12550144,
258-
-4161536,
259-
-12582784,
260-
-4194176,
261-
-12550016,
262-
-4161408,
263-
-16760832,
264-
-8372224,
265-
-16728064,
266-
-8339456,
267-
-16760704
268-
)
269-
270113
}
271114

272-
273-
274-
interface SegmenterListener {
275-
fun onError(error: String, errorCode: Int = OTHER_ERROR)
276-
fun onResults(resultBundle: ResultBundle)
277-
}
278115
}

0 commit comments

Comments
 (0)