使用以下 Kotlin 循环,我们显示摄像头源、检测源中的人脸并在屏幕上的视频源上绘制人脸边界框。
使用 workReducer 计数器,我们在图像馈送中每 0.5 秒检查一次面部可用性。
问题是我们第一次激活摄像头几秒钟后,如果我们使用屏幕上的某些按钮重新启动摄像头,视频输入会在大约 20 秒后冻结。
我已经有一段时间一直在寻找解决方案但没有成功。
Ps:如果没有检测到人脸,它永远不会冻结。 另外:当我删除
android.graphics.Rect( face.boundingBox.left,
face.boundingBox.top,
face.boundingBox.right,
face.boundingBox.bottom
) by commenting it freezes les often
imageReader.setOnImageAvailableListener({ reader ->
val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener
val bitImage = recordJpeg( image, cx)
bitImage?.let { bitmapCallback.onBitmapUpdated(it) }
if (workReducer > workReducerLimit) {
workReducer = 0
val inputImage = InputImage.fromMediaImage(image, 270)
faceDetector.process(inputImage).addOnSuccessListener { faces ->
val rects = faces.map { face ->
android.graphics.Rect(
face.boundingBox.left,
face.boundingBox.top,
face.boundingBox.right,
face.boundingBox.bottom
)
}
faceRectsCallback.onFaceRectsUpdated(rects)
}
.addOnFailureListener { e ->
image.close()
}
.addOnCompleteListener {
image.close()
}
} else {
image.close()
}
workReducer += 1
// Camera image read loop
}, Handler(context.mainLooper))
嗯,冻结的事情发生是因为常量类型,而不是因为人脸检测功能或 API。
几个小时后我偶然发现冻结的原因是inputImage常量。
我将其声明为 private var imageReader : ImageReader? = null 在类之外我的函数在内部运行。
它显示来自相机的实时反馈,在其上绘制面部边界框并显示我用来录制并稍后顺利转换视频文件的位图图像。
当我尝试找出问题原因时,我必须升级许多与 Kotlin 和 Java 相关的东西。现在,在完成所有这些之后,Xcode 看起来非常漂亮。
override fun onOpened(camera : CameraDevice) {
Log.d("my", "onOpened")
currentCameraDevice = camera
val surfaceTexture = textureView.surfaceTexture?.apply {
setDefaultBufferSize(previewSize.width, previewSize.height)
}
val previewSurface = Surface(surfaceTexture)
imageReader = ImageReader.newInstance(
previewSize.width,
previewSize.height,
ImageFormat.YUV_420_888,
2
)!!
val imageReaderSurface = imageReader!!.surface
val captureRequestBuilder =
camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
addTarget(previewSurface)
addTarget(imageReader!!.surface)
}
val faceDetector = FaceDetection.getClient(
FaceDetectorOptions.Builder()
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
.build()
)
val sessionConfig = SessionConfiguration(
SessionConfiguration.SESSION_REGULAR,
listOf(
OutputConfiguration(previewSurface),
OutputConfiguration(imageReaderSurface)
),
Executors.newSingleThreadExecutor(),
object : CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
currentCaptureSession = session
session.setRepeatingRequest(captureRequestBuilder.build(), null, null)
callback.onPreviewSizeAvailable(previewSize)
}
override fun onConfigureFailed(session: CameraCaptureSession) {
Log.e("my", "Failed to configure camera capture session")
}
}
)
camera.createCaptureSession(sessionConfig)
imageReader!!.setOnImageAvailableListener(
{ reader ->
val image = reader.acquireLatestImage()
?: return@setOnImageAvailableListener
try {
// To check if can produce bitmap.
val bitImage = recordJpeg(image, cx)
bitImage?.let { bitmapCallback.onBitmapUpdated(it) }
if(workReducer > workReducerLimit) {
workReducer = 0
val inputimage = InputImage.fromMediaImage(image, 270)
faceDetector.process(inputimage)
.addOnSuccessListener { faces ->
val rects = faces.map { face ->
if(!faceDetected && setup.recOn == 1) {
afterBitmapArray.clear()
preRecSize = bitmapArray.size
afterBitmapArray =
bitmapArray.toMutableList()
faceDetected = true
}
android.graphics.Rect(
face.boundingBox.left,
face.boundingBox.top,
face.boundingBox.right,
face.boundingBox.bottom
)
}
faceRectsCallback.onFaceRectsUpdated(rects)
}
.addOnFailureListener { e ->
Log.d("my", "Face detection failed: ${e.message}", e)
}
.addOnCompleteListener { image.close() }
} else {
image.close()
}
workReducer += 1
} catch (e : Exception) {
Log.d("my", "Error processing image: ${e.message}")
}
}, Handler(context.mainLooper)
)
}