共计 2500 个字符,预计需要花费 7 分钟才能阅读完成。
咱们应用人脸检测 sdk 进行人脸识别的过程大抵能够分为上面几个步骤:
- 加载 model 文件并初始化接口
- 获取受权
- 调用人脸检测获取关键点
- 告诉描绘关键点
- 开释接口资源
这里的步骤 3 和 4 在接管到 camera 数据后重复执行。咱们能够把这几个步骤形象成数据流来进行封装。face++ 检测人脸后一直地生成人脸坐标数据,所以整个检测过程就是人脸坐标数据生产的过程,这里与 flow 的概念对应上了。
face++ 须要通过解决 camera 数据来获取人脸关键点,所以 camera 又是 face++ 人脸检测 api 的数据提供者。下图体现了数据流动的过程:
看到这里大家也认为咱们通过 flow 实现这个过程更正当了吧!上面咱们分步来实现 detect flow 的创立.
第一步咱们通过 flow 的 builder 创立一个 flow:
private val imageChannel = Channel<FacePPImage>()
flow {while (currentCoroutineContext().isActive) {emit(imageChannel.receive())
}
}
这里应用 Channel 来接管图像数据并发射。在 detect flow 解决图像数据前咱们还须要一些初始化 face++ 的工作,这些工作在 onStart 中解决。
flow.onStart {
var ret = -1
context.assets.open("megviifacepp_model").use { ios ->
modelBuffer = ByteArray(ios.available())
ios.read(modelBuffer)
FaceppApi.getInstance().setLogLevel(4)
ret = FaceppApi.getInstance().initHandle(modelBuffer)
}
if (ret != 0) {Log.d("dragon_debug", "onStart open failed!")
throw RuntimeException("init")
}
if (requestTakeLicense && modelBuffer != null) {Log.d("dragon_debug", "onStart takeLicense")
ret = takeLicense(context, modelBuffer!!)
}
if (ret != 0) {Log.d("dragon_debug", "onStart takeLicense failed!")
throw RuntimeException("takeLicense")
}
ret = FaceDetectApi.getInstance().initFaceDetect()
DLmkDetectApi.getInstance().initDLmkDetect()
if (ret != 0) {if (requestTakeLicense) {Log.d("dragon_debug", "onStart initFaceDetect error")
throw RuntimeException("error")
}
requestTakeLicense = true
Log.d("dragon_debug", "onStart initFaceDetect retry exception")
throw RuntimeException("initFace")
}
val config = FaceDetectApi.getInstance().faceppConfig
config.face_confidence_filter = 0.6f
config.detectionMode = FaceDetectApi.FaceppConfig.DETECTION_MODE_TRACKING
FaceDetectApi.getInstance().faceppConfig = config}
face++ 初始化操作包含加载模型、检测接口受权、人脸检测接口初始化等步骤。
检测接口受权解决有些特地,face++ 的接口受权只在受权过期的时候执行。所以这里配合 flow 的 retryWhen 来解决过期受权。
flow.retryWhen { cause, attempt ->
Log.d("dragon_debug", "retryWhen $cause attempt $attempt")
if (attempt > 1) {false} else {(cause as? RuntimeException)?.message?.equals("initFace") ?: false
}
}
首先尝试初始化 face++ 接口,如果初始化失败,这里会抛出异样 RuntimeException(“init”)。retryWhen 捕捉这个异样后发动重试解决,当 onStart 再次执行时,咱们会尝试获取接口权限。
face++ 接口受权初始化胜利后,咱们能够应用 face++ 的人脸检测接口了。这里应用 map 将图像数据转换成人脸坐标数据,转换操作由 face++ 人脸检测接口实现。
flow.map { image ->
val faces = FaceDetectApi.getInstance().detectFace(image)
faces.forEach { face ->
FaceDetectApi.getInstance().getLandmark(face, FaceDetectApi.LMK_84, true)
}
block.invoke(faces)
faces
}
失去的人脸坐标数据通过 block 回调告诉画面描绘。
face++ 接口的开释操作在 onCompletion 中,
flow.onCompletion {Log.d("dragon_debug", "onCompletion")
FaceppApi.getInstance().ReleaseHandle()
DLmkDetectApi.getInstance().releaseDlmDetect()
}
残缺的代码:https://github.com/mjlong1231…
原文地址:https://blog.csdn.net/mjlong1…