Closing image in ImageAnalysis makes Mlkit stop working

1.3k views Asked by At

Analyzer Class

private class Analyzer: ImageAnalysis.Analyzer {
val faceDetectObj=FaceDetectionActivity()
    @SuppressLint("UnsafeExperimentalUsageError")
    override fun analyze(image: ImageProxy) {
        val proxy=image
        val currentImage=proxy.image
        val rotDegree=  proxy.imageInfo.rotationDegrees
        if (currentImage!=null){
            val imageNew=InputImage.fromMediaImage(currentImage,rotDegree)
            faceDetectObj.detectFaces(imageNew)
         }  
        image.close()  //error because of this line
    }

FaceDetectionActivit.kt

class FaceDetectionActivity :AppCompatActivity() {
         fun detectFaces(image: InputImage) {
            // [START set_detector_options]
            val options = FaceDetectorOptions.Builder()
                .setClassificationMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
                .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
                .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
                .setMinFaceSize(0.15f)
                .enableTracking()
                .build()
            // [END set_detector_options]

            // [START get_detector]
            val detector = FaceDetection.getClient(options)
            // Or, to use the default option:
            // val detector = FaceDetection.getClient();
            // [END get_detector]

            // [START run_detector]
            val result = detector.process(image)
                .addOnSuccessListener { faces ->
                    // Task completed successfully
                    // [START_EXCLUDE]
                    // [START get_face_info]
                    for (face in faces) {
                        val bounds = face.boundingBox
                        val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees
                        val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees
                      
                        // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
                        // nose available):
                        val leftEar = face.getLandmark(FaceLandmark.LEFT_EAR)
                        leftEar?.let {
                            val leftEarPos = leftEar.position
                        }

                        // If classification was enabled:
                        if (face.smilingProbability != null) {
                            val smileProb = face.smilingProbability
                        }
                        if (face.rightEyeOpenProbability != null) {
                            val rightEyeOpenProb = face.rightEyeOpenProbability
                        }

                        // If face tracking was enabled:
                        if (face.trackingId != null) {
                            val id = face.trackingId
                        }
                    }
                    // [END get_face_info]
                    // [END_EXCLUDE]
                }
                .addOnFailureListener { e ->
                    e.printStackTrace()
                    // Task failed with an exception
                    // ...
                }
             result.addOnCompleteListener {
                 processFaceList(it.result as List<Face>)
             }.addOnFailureListener {
                 it.printStackTrace()
             }
            // [END run_detector]
        }

         fun processFaceList(faces: List<Face>) {
            // [START mlkit_face_list]
            for (face in faces) {
                val bounds = face.boundingBox
                val rotY = face.headEulerAngleY // Head is rotated to the right rotY degrees
                val rotZ = face.headEulerAngleZ // Head is tilted sideways rotZ degrees

                // If landmark detection was enabled (mouth, ears, eyes, cheeks, and
                // nose available):
                val leftEar = face.getLandmark(FaceLandmark.LEFT_EAR)
                leftEar?.let {
                    val leftEarPos = leftEar.position
                }
                // If contour detection was enabled:
                val leftEyeContour = face.getContour(FaceContour.LEFT_EYE)?.points
                val upperLipBottomContour = face.getContour(FaceContour.UPPER_LIP_BOTTOM)?.points
                Log.d("help ","Needed P2")
                // If classification was enabled:
                if (face.smilingProbability != null) {
                    val smileProb = face.smilingProbability
                }
                if (face.rightEyeOpenProbability != null) {
                    val rightEyeOpenProb = face.rightEyeOpenProbability
                }

                // If face tracking was enabled:
                if (face.trackingId != null) {
                    val id = face.trackingId
                }
            }
            // [END mlkit_face_list]
        }
}

im trying to detect face using above code(directly from documentation).ImageAnlayser needs to be closed after each frame , but if i do that mlkit throws

2020-10-13 23:38:42.121 30424-30424/? E/AndroidRuntime: FATAL EXCEPTION: main
   Process: com.airbender.camcorder, PID: 30424
   com.google.android.gms.tasks.RuntimeExecutionException: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
       at com.google.android.gms.tasks.zzu.getResult(Unknown Source:15)
       at com.airbender.camcorder.FaceDetectionActivity$detectFaces$1.onComplete(FaceDetectionActivty.kt:67)
       at com.google.android.gms.tasks.zzj.run(Unknown Source:4)
       at android.os.Handler.handleCallback(Handler.java:883)
       at android.os.Handler.dispatchMessage(Handler.java:100)
       at android.os.Looper.loop(Looper.java:214)
       at android.app.ActivityThread.main(ActivityThread.java:7398)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
    Caused by: com.google.mlkit.common.MlKitException: Internal error has occurred when executing ML Kit tasks
       at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:32)
       at com.google.mlkit.common.sdkinternal.zzl.run(Unknown Source:10)
       at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.0.0:3)
       at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.0.0:24)
       at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zza(com.google.mlkit:common@@17.0.0:30)
       at com.google.mlkit.common.sdkinternal.zzh.run(Unknown Source:2)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:919)
    Caused by: java.lang.IllegalStateException: Image is already closed
       at android.media.Image.throwISEIfImageIsInvalid(Image.java:72)
       at android.media.ImageReader$SurfaceImage$SurfacePlane.getBuffer(ImageReader.java:965)
       at com.google.android.gms.vision.Frame$Builder.setPlanes(com.google.android.gms:play-services-vision-common@@19.1.2:14)
       at com.google.mlkit.vision.face.internal.zzb.zza(com.google.android.gms:play-services-mlkit-face-detection@@16.1.1:61)
       at com.google.mlkit.vision.face.internal.zzb.zza(com.google.android.gms:play-services-mlkit-face-detection@@16.1.1:90)
       at com.google.mlkit.vision.face.internal.zzb.run(com.google.android.gms:play-services-mlkit-face-detection@@16.1.1:169)
       at com.google.mlkit.vision.common.internal.MobileVisionBase.zza(com.google.mlkit:vision-common@@16.1.0:23)
       at com.google.mlkit.vision.common.internal.zzc.call(Unknown Source:4)
       at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.0.0:29)
       at com.google.mlkit.common.sdkinternal.zzl.run(Unknown Source:10) 
       at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.0.0:3) 
       at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.0.0:24) 
       at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zza(com.google.mlkit:common@@17.0.0:30) 
       at com.google.mlkit.common.sdkinternal.zzh.run(Unknown Source:2) 
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
       at java.lang.Thread.run(Thread.java:919) 

how to close each frame so that i can process every current frame without error as the way it need to work . is there anything need to do?. Thanks.

1

There are 1 answers

1
Chenxi Song On

You should close the image in detector's onComplete listener instead since the image is used in the background thread by the ML Kit detector after the process call.