如何在 CameraX analyze() 之外提取调用 MLKit process() 的方法?
How to extract methods that call MLKit process(), outside of CameraX analyze()?
为了代码清晰和更好的可重用性,我想要这样的东西
class MyAnalyzer : ImageAnalysis.Analyzer {
private val faceDetector = FaceDetection.getClient()
@androidx.camera.core.ExperimentalGetImage
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: return
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
if (getFace(image) != null) {
// do stuff
}
imageProxy.close()
}
private fun getFace(image: InputImage): Face? {
var face: Face? = null
faceDetector.process(image).addOnSuccessListener { faces ->
face = faces.firstOrNull()
}
return face
}
}
但是当我 运行 应用程序时,它总是引发此异常
E/NativeFaceDetectorV2Imp: Native face detection v2 failed
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.nio.ByteBuffer.isDirect()' on a null object reference
at com.google.android.gms.vision.face.NativeFaceDetectorV2Impl.zza(com.google.android.gms:play-services-vision-face-contour-internal@@16.1.0:96)
at com.google.android.gms.vision.face.internal.client.zzb.zza(com.google.android.gms:play-services-vision@@20.1.3:34)
at com.google.android.gms.vision.face.FaceDetector.detect(com.google.android.gms:play-services-vision@@20.1.3:27)
at com.google.mlkit.vision.face.internal.zzg.zzc(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2:23)
at com.google.mlkit.vision.face.internal.zzg.zzd(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2:3)
at com.google.mlkit.vision.face.internal.zzg.run(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2)
at com.google.mlkit.vision.common.internal.MobileVisionBase.zza(com.google.mlkit:vision-common@@16.2.0)
at com.google.mlkit.vision.common.internal.zzc.call(com.google.mlkit:vision-common@@16.2.0)
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzn.run(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.1.0:2)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zze(com.google.mlkit:common@@17.1.0:4)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzc(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzj.run(com.google.mlkit:common@@17.1.0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzk.run(com.google.mlkit:common@@17.1.0)
at java.lang.Thread.run(Thread.java:761)
编辑: 我找到了异常的原因并修复了它(参见下面的 ),但是代码仍然有问题,因为我仍然得不到我期待的结果。
我找到了罪魁祸首。我错误地粘贴了第一个代码示例,在块调用 addOnSuccessListener { }
之后粘贴了 imageProxy.close()
,但实际上它总是在其中。目前的情况是
class MyAnalyzer : ImageAnalysis.Analyzer {
private val faceDetector = FaceDetection.getClient()
@androidx.camera.core.ExperimentalGetImage
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: return
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
if (getFace(image, imageProxy) != null) {
// do stuff
}
}
private fun getFace(image: InputImage, imageProxy: ImageProxy): Face? {
var face: Face? = null
/* old code
*
* faceDetector.process(image).addOnSuccessListener { faces ->
* face = faces.firstOrNull()
* imageProxy.close()
* }
*/
// solution code
runBlocking {
withContext(Dispatchers.IO) {
val faces = Tasks.await(faceDetector.process(image))
face = faces.firstOrNull()
imageProxy.close()
}
}
return face
}
}
现在至少它不再引发异常,如果我在侦听器块中记录人脸就没问题,但 if (getFace(image, imageProxy) != null)
中的代码不会 运行。我认为这是因为 faceDetector.process()
还没有完成,所以 getFace()
returns 立即 face
这仍然是 null
从初始化开始,当监听器被触发时它也是晚了。有什么建议吗?
编辑:又找到罪魁祸首了。和我想象的一模一样,我需要做的就是找到另一种等待faceDetector.process()
完成的方法。因为它 returns 一个 Task<T>
,在摸索了一段时间后我发现我可以只使用 Tasks.await()
并且在将它包装在一个很好的协程中之后一切似乎都很好。我已修复此答案中的代码以反映我的最新更改。
为了代码清晰和更好的可重用性,我想要这样的东西
class MyAnalyzer : ImageAnalysis.Analyzer {
private val faceDetector = FaceDetection.getClient()
@androidx.camera.core.ExperimentalGetImage
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: return
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
if (getFace(image) != null) {
// do stuff
}
imageProxy.close()
}
private fun getFace(image: InputImage): Face? {
var face: Face? = null
faceDetector.process(image).addOnSuccessListener { faces ->
face = faces.firstOrNull()
}
return face
}
}
但是当我 运行 应用程序时,它总是引发此异常
E/NativeFaceDetectorV2Imp: Native face detection v2 failed
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.nio.ByteBuffer.isDirect()' on a null object reference
at com.google.android.gms.vision.face.NativeFaceDetectorV2Impl.zza(com.google.android.gms:play-services-vision-face-contour-internal@@16.1.0:96)
at com.google.android.gms.vision.face.internal.client.zzb.zza(com.google.android.gms:play-services-vision@@20.1.3:34)
at com.google.android.gms.vision.face.FaceDetector.detect(com.google.android.gms:play-services-vision@@20.1.3:27)
at com.google.mlkit.vision.face.internal.zzg.zzc(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2:23)
at com.google.mlkit.vision.face.internal.zzg.zzd(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2:3)
at com.google.mlkit.vision.face.internal.zzg.run(com.google.android.gms:play-services-mlkit-face-detection@@16.1.2)
at com.google.mlkit.vision.common.internal.MobileVisionBase.zza(com.google.mlkit:vision-common@@16.2.0)
at com.google.mlkit.vision.common.internal.zzc.call(com.google.mlkit:vision-common@@16.2.0)
at com.google.mlkit.common.sdkinternal.ModelResource.zza(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzn.run(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzp.run(com.google.mlkit:common@@17.1.0:2)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zze(com.google.mlkit:common@@17.1.0:4)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzc(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzj.run(com.google.mlkit:common@@17.1.0)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at com.google.mlkit.common.sdkinternal.MlKitThreadPool.zzd(com.google.mlkit:common@@17.1.0)
at com.google.mlkit.common.sdkinternal.zzk.run(com.google.mlkit:common@@17.1.0)
at java.lang.Thread.run(Thread.java:761)
编辑: 我找到了异常的原因并修复了它(参见下面的
我找到了罪魁祸首。我错误地粘贴了第一个代码示例,在块调用 addOnSuccessListener { }
之后粘贴了 imageProxy.close()
,但实际上它总是在其中。目前的情况是
class MyAnalyzer : ImageAnalysis.Analyzer {
private val faceDetector = FaceDetection.getClient()
@androidx.camera.core.ExperimentalGetImage
override fun analyze(imageProxy: ImageProxy) {
val mediaImage = imageProxy.image ?: return
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
if (getFace(image, imageProxy) != null) {
// do stuff
}
}
private fun getFace(image: InputImage, imageProxy: ImageProxy): Face? {
var face: Face? = null
/* old code
*
* faceDetector.process(image).addOnSuccessListener { faces ->
* face = faces.firstOrNull()
* imageProxy.close()
* }
*/
// solution code
runBlocking {
withContext(Dispatchers.IO) {
val faces = Tasks.await(faceDetector.process(image))
face = faces.firstOrNull()
imageProxy.close()
}
}
return face
}
}
现在至少它不再引发异常,如果我在侦听器块中记录人脸就没问题,但 if (getFace(image, imageProxy) != null)
中的代码不会 运行。我认为这是因为 faceDetector.process()
还没有完成,所以 getFace()
returns 立即 face
这仍然是 null
从初始化开始,当监听器被触发时它也是晚了。有什么建议吗?
编辑:又找到罪魁祸首了。和我想象的一模一样,我需要做的就是找到另一种等待faceDetector.process()
完成的方法。因为它 returns 一个 Task<T>
,在摸索了一段时间后我发现我可以只使用 Tasks.await()
并且在将它包装在一个很好的协程中之后一切似乎都很好。我已修复此答案中的代码以反映我的最新更改。