|
@@ -47,7 +47,6 @@ object ArcSoftUtil {
|
|
|
private var previewSize: Camera.Size? = null
|
|
private var previewSize: Camera.Size? = null
|
|
|
private val rgbCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
|
|
private val rgbCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
|
|
|
private var faceEngine: FaceEngine? = null
|
|
private var faceEngine: FaceEngine? = null
|
|
|
- private var checkFaceEngine: FaceEngine? = null
|
|
|
|
|
private val cameraWidth: Int = 640
|
|
private val cameraWidth: Int = 640
|
|
|
private val cameraHeight: Int = 480
|
|
private val cameraHeight: Int = 480
|
|
|
private var afCode = -1
|
|
private var afCode = -1
|
|
@@ -56,7 +55,6 @@ object ArcSoftUtil {
|
|
|
|
|
|
|
|
private const val ACTION_REQUEST_PERMISSIONS: Int = 0x001
|
|
private const val ACTION_REQUEST_PERMISSIONS: Int = 0x001
|
|
|
var isActivated = false
|
|
var isActivated = false
|
|
|
- private var isInit = false
|
|
|
|
|
var inDetecting = false
|
|
var inDetecting = false
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -94,11 +92,7 @@ object ArcSoftUtil {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fun initEngine(context: Context) {
|
|
fun initEngine(context: Context) {
|
|
|
- if (isInit) {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
faceEngine = FaceEngine()
|
|
faceEngine = FaceEngine()
|
|
|
- checkFaceEngine = FaceEngine()
|
|
|
|
|
afCode = faceEngine!!.init(
|
|
afCode = faceEngine!!.init(
|
|
|
context,
|
|
context,
|
|
|
DetectMode.ASF_DETECT_MODE_VIDEO,
|
|
DetectMode.ASF_DETECT_MODE_VIDEO,
|
|
@@ -110,18 +104,6 @@ object ArcSoftUtil {
|
|
|
if (afCode != ErrorInfo.MOK) {
|
|
if (afCode != ErrorInfo.MOK) {
|
|
|
logger.info("初始化失败")
|
|
logger.info("初始化失败")
|
|
|
}
|
|
}
|
|
|
- afCode = checkFaceEngine!!.init(
|
|
|
|
|
- context,
|
|
|
|
|
- DetectMode.ASF_DETECT_MODE_IMAGE,
|
|
|
|
|
- DetectFaceOrientPriority.ASF_OP_0_ONLY,
|
|
|
|
|
- 1,
|
|
|
|
|
- FaceEngine.ASF_FACE_DETECT or FaceEngine.ASF_MASK_DETECT or FaceEngine.ASF_LIVENESS or FaceEngine.ASF_FACE_RECOGNITION
|
|
|
|
|
- )
|
|
|
|
|
- logger.info("initEngine: init: $afCode")
|
|
|
|
|
- isInit = afCode == ErrorInfo.MOK
|
|
|
|
|
- if (afCode != ErrorInfo.MOK) {
|
|
|
|
|
- logger.info("初始化失败")
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fun unInitEngine() {
|
|
fun unInitEngine() {
|
|
@@ -185,17 +167,12 @@ object ArcSoftUtil {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- val ageInfoList: List<AgeInfo> = ArrayList()
|
|
|
|
|
- val genderInfoList: List<GenderInfo> = ArrayList()
|
|
|
|
|
- val face3DAngleList: List<Face3DAngle> = ArrayList()
|
|
|
|
|
val faceLivenessInfoList: List<LivenessInfo> = ArrayList()
|
|
val faceLivenessInfoList: List<LivenessInfo> = ArrayList()
|
|
|
- val ageCode = faceEngine!!.getAge(ageInfoList)
|
|
|
|
|
- val genderCode = faceEngine!!.getGender(genderInfoList)
|
|
|
|
|
val livenessCode = faceEngine!!.getLiveness(faceLivenessInfoList)
|
|
val livenessCode = faceEngine!!.getLiveness(faceLivenessInfoList)
|
|
|
|
|
|
|
|
// 有其中一个的错误码不为ErrorInfo.MOK,return
|
|
// 有其中一个的错误码不为ErrorInfo.MOK,return
|
|
|
- if ((ageCode or genderCode or livenessCode) != ErrorInfo.MOK) {
|
|
|
|
|
- logger.debug("人脸检测结果:年龄、性别、角度、获取验证失败")
|
|
|
|
|
|
|
+ if ((livenessCode) != ErrorInfo.MOK) {
|
|
|
|
|
+ logger.debug("人脸检测结果:${livenessCode}")
|
|
|
inDetecting = false
|
|
inDetecting = false
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
@@ -247,51 +224,12 @@ object ArcSoftUtil {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 注册人脸
|
|
|
|
|
|
|
+ * 登录用
|
|
|
*/
|
|
*/
|
|
|
- fun registerFace(faceData: List<Pair<Long, String>>) {
|
|
|
|
|
- faceData.forEachIndexed { index, userFace ->
|
|
|
|
|
- registerFaceFeatureJob.launch {
|
|
|
|
|
- val faceBitmap = decodeBase64ToBitmap(userFace.second)
|
|
|
|
|
- val imageData =
|
|
|
|
|
- ImageConvertUtils.bitmapToNv21(faceBitmap, faceBitmap.width, faceBitmap.height)
|
|
|
|
|
- val faceInfoList = mutableListOf<FaceInfo>()
|
|
|
|
|
- checkFaceEngine?.detectFaces(
|
|
|
|
|
- imageData,
|
|
|
|
|
- faceBitmap.width,
|
|
|
|
|
- faceBitmap.height,
|
|
|
|
|
- FaceEngine.CP_PAF_NV21,
|
|
|
|
|
- faceInfoList
|
|
|
|
|
- )
|
|
|
|
|
- val faceFeature = FaceFeature()
|
|
|
|
|
- checkFaceEngine?.extractFaceFeature(
|
|
|
|
|
- imageData,
|
|
|
|
|
- faceBitmap.width,
|
|
|
|
|
- faceBitmap.height,
|
|
|
|
|
- FaceEngine.CP_PAF_NV21,
|
|
|
|
|
- faceInfoList[0],
|
|
|
|
|
- ExtractType.REGISTER,
|
|
|
|
|
- 0,
|
|
|
|
|
- faceFeature
|
|
|
|
|
- )
|
|
|
|
|
- val faceFeatureInfo =
|
|
|
|
|
- FaceFeatureInfo(userFace.first.toInt(), faceFeature.featureData)
|
|
|
|
|
- if (checkFaceEngine?.getFaceFeature(userFace.first.toInt()) == null) {
|
|
|
|
|
- checkFaceEngine?.registerFaceFeature(faceFeatureInfo)
|
|
|
|
|
- } else {
|
|
|
|
|
- checkFaceEngine?.updateFaceFeature(faceFeatureInfo)
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @JvmOverloads
|
|
|
|
|
fun checkCamera(
|
|
fun checkCamera(
|
|
|
- context: Context,
|
|
|
|
|
windowManager: WindowManager,
|
|
windowManager: WindowManager,
|
|
|
preview: View,
|
|
preview: View,
|
|
|
- needCheckCenter: Boolean = false,
|
|
|
|
|
- callBack: (Long?) -> Unit
|
|
|
|
|
|
|
+ callBack: (Bitmap?, Long?) -> Unit
|
|
|
) {
|
|
) {
|
|
|
val metrics = DisplayMetrics()
|
|
val metrics = DisplayMetrics()
|
|
|
windowManager.defaultDisplay.getMetrics(metrics)
|
|
windowManager.defaultDisplay.getMetrics(metrics)
|
|
@@ -311,21 +249,13 @@ object ArcSoftUtil {
|
|
|
}
|
|
}
|
|
|
inDetecting = true
|
|
inDetecting = true
|
|
|
val faceInfoList: List<FaceInfo> = ArrayList()
|
|
val faceInfoList: List<FaceInfo> = ArrayList()
|
|
|
- var code = checkFaceEngine!!.detectFaces(
|
|
|
|
|
|
|
+ var code = faceEngine!!.detectFaces(
|
|
|
nv21,
|
|
nv21,
|
|
|
previewSize!!.width,
|
|
previewSize!!.width,
|
|
|
previewSize!!.height,
|
|
previewSize!!.height,
|
|
|
FaceEngine.CP_PAF_NV21,
|
|
FaceEngine.CP_PAF_NV21,
|
|
|
faceInfoList
|
|
faceInfoList
|
|
|
)
|
|
)
|
|
|
-
|
|
|
|
|
- if (needCheckCenter && !faceInfoList[0].rect.isInCenterArea(
|
|
|
|
|
- previewSize!!.width, previewSize!!.height
|
|
|
|
|
- )
|
|
|
|
|
- ) {
|
|
|
|
|
- inDetecting = false
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
if (code == ErrorInfo.MOK && faceInfoList.isNotEmpty()) {
|
|
if (code == ErrorInfo.MOK && faceInfoList.isNotEmpty()) {
|
|
|
code = faceEngine!!.process(
|
|
code = faceEngine!!.process(
|
|
|
nv21,
|
|
nv21,
|
|
@@ -349,19 +279,19 @@ object ArcSoftUtil {
|
|
|
|
|
|
|
|
// 有其中一个的错误码不为ErrorInfo.MOK,return
|
|
// 有其中一个的错误码不为ErrorInfo.MOK,return
|
|
|
if ((livenessCode) != ErrorInfo.MOK) {
|
|
if ((livenessCode) != ErrorInfo.MOK) {
|
|
|
- logger.debug("人脸检测结果:年龄、性别、角度、获取验证失败")
|
|
|
|
|
|
|
+ logger.debug("人脸检测结果:${livenessCode}")
|
|
|
inDetecting = false
|
|
inDetecting = false
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 自己加的,必须有活体检测
|
|
// 自己加的,必须有活体检测
|
|
|
if (faceLivenessInfoList.none { it.liveness == LivenessInfo.ALIVE }) {
|
|
if (faceLivenessInfoList.none { it.liveness == LivenessInfo.ALIVE }) {
|
|
|
- callBack(null)
|
|
|
|
|
|
|
+ callBack(null, null)
|
|
|
inDetecting = false
|
|
inDetecting = false
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
val faceFeature = FaceFeature()
|
|
val faceFeature = FaceFeature()
|
|
|
- checkFaceEngine?.extractFaceFeature(
|
|
|
|
|
|
|
+ faceEngine?.extractFaceFeature(
|
|
|
nv21,
|
|
nv21,
|
|
|
previewSize!!.width,
|
|
previewSize!!.width,
|
|
|
previewSize!!.height,
|
|
previewSize!!.height,
|
|
@@ -371,9 +301,21 @@ object ArcSoftUtil {
|
|
|
0,
|
|
0,
|
|
|
faceFeature
|
|
faceFeature
|
|
|
)
|
|
)
|
|
|
- val searchResult = checkFaceEngine?.searchFaceFeature(faceFeature)
|
|
|
|
|
|
|
+ val searchResult = try {
|
|
|
|
|
+ if ((faceEngine?.faceCount ?: 0) > 0) {
|
|
|
|
|
+ faceEngine?.searchFaceFeature(faceFeature)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ null
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
|
+ logger.info("搜索人脸异常")
|
|
|
|
|
+ null
|
|
|
|
|
+ }
|
|
|
logger.debug("人脸检测结果-识别结果 : ${searchResult?.faceFeatureInfo} - $faceInfoList")
|
|
logger.debug("人脸检测结果-识别结果 : ${searchResult?.faceFeatureInfo} - $faceInfoList")
|
|
|
- callBack(searchResult?.faceFeatureInfo?.searchId?.toLong())
|
|
|
|
|
|
|
+ val bitmap =
|
|
|
|
|
+ ImageConvertUtils.nv21ToBitmap(nv21, previewSize!!.width, previewSize!!.height)
|
|
|
|
|
+
|
|
|
|
|
+ callBack(bitmap, searchResult?.faceFeatureInfo?.searchId?.toLong())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
override fun onCameraClosed() {
|
|
override fun onCameraClosed() {
|
|
@@ -414,6 +356,63 @@ object ArcSoftUtil {
|
|
|
// unInitEngine()
|
|
// unInitEngine()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 注册人脸
|
|
|
|
|
+ */
|
|
|
|
|
+ fun registerFace(faceData: List<Pair<Long, String>>) {
|
|
|
|
|
+ faceData.forEachIndexed { index, userFace ->
|
|
|
|
|
+ val faceBitmap = decodeBase64ToBitmap(userFace.second)
|
|
|
|
|
+ val imageData = bitmapToBgr24(faceBitmap)
|
|
|
|
|
+ val faceInfoList = mutableListOf<FaceInfo>()
|
|
|
|
|
+ val code = faceEngine?.detectFaces(
|
|
|
|
|
+ imageData,
|
|
|
|
|
+ faceBitmap.width,
|
|
|
|
|
+ faceBitmap.height,
|
|
|
|
|
+ FaceEngine.CP_PAF_BGR24,
|
|
|
|
|
+ faceInfoList
|
|
|
|
|
+ )
|
|
|
|
|
+// val code = checkFaceEngine?.detectFaces(
|
|
|
|
|
+// imageData,
|
|
|
|
|
+// faceBitmap.width,
|
|
|
|
|
+// faceBitmap.height,
|
|
|
|
|
+// FaceEngine.CP_PAF_BGR24,
|
|
|
|
|
+// faceInfoList
|
|
|
|
|
+// )
|
|
|
|
|
+ logger.info("人脸检测结果:${code}")
|
|
|
|
|
+ if (faceInfoList.isEmpty()) {
|
|
|
|
|
+ logger.info("没有检测出人脸")
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ val faceFeature = FaceFeature()
|
|
|
|
|
+ faceEngine?.extractFaceFeature(
|
|
|
|
|
+ imageData,
|
|
|
|
|
+ faceBitmap.width,
|
|
|
|
|
+ faceBitmap.height,
|
|
|
|
|
+ FaceEngine.CP_PAF_BGR24,
|
|
|
|
|
+ faceInfoList[0],
|
|
|
|
|
+ ExtractType.REGISTER,
|
|
|
|
|
+ 0,
|
|
|
|
|
+ faceFeature
|
|
|
|
|
+ )
|
|
|
|
|
+ val faceFeatureInfo =
|
|
|
|
|
+ FaceFeatureInfo(userFace.first.toInt(), faceFeature.featureData)
|
|
|
|
|
+ try {
|
|
|
|
|
+ if ((faceEngine?.searchFaceFeature(faceFeature)?.maxSimilar ?: 0f) > 0.5) {
|
|
|
|
|
+ val code = faceEngine?.updateFaceFeature(faceFeatureInfo)
|
|
|
|
|
+ logger.info("特征更新:${code}")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ val code = faceEngine?.registerFaceFeature(faceFeatureInfo)
|
|
|
|
|
+ logger.info("特征注册:${code}")
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e: Exception) {
|
|
|
|
|
+ logger.info("找不到人脸,直接注册")
|
|
|
|
|
+ val code = faceEngine?.registerFaceFeature(faceFeatureInfo)
|
|
|
|
|
+ logger.info("特征注册:${code}")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 比对两张 Base64 人脸,返回是否同人
|
|
* 比对两张 Base64 人脸,返回是否同人
|
|
|
* @param threshold 阈值,一般设置 0.7f 左右
|
|
* @param threshold 阈值,一般设置 0.7f 左右
|
|
@@ -437,7 +436,7 @@ object ArcSoftUtil {
|
|
|
val imgBDetectResultCode = faceEngine?.detectFaces(
|
|
val imgBDetectResultCode = faceEngine?.detectFaces(
|
|
|
imgB, bmpB.width, bmpB.height, FaceEngine.CP_PAF_BGR24, facesB
|
|
imgB, bmpB.width, bmpB.height, FaceEngine.CP_PAF_BGR24, facesB
|
|
|
)
|
|
)
|
|
|
- logger.info("人脸检测结果1:${facesA.size},${facesA.size}")
|
|
|
|
|
|
|
+ logger.info("人脸检测结果1:${facesA.size},${facesB.size}")
|
|
|
logger.info("人脸检测结果2:${imgADetectResultCode},${imgBDetectResultCode}")
|
|
logger.info("人脸检测结果2:${imgADetectResultCode},${imgBDetectResultCode}")
|
|
|
if (facesA.isEmpty() || facesB.isEmpty()) {
|
|
if (facesA.isEmpty() || facesB.isEmpty()) {
|
|
|
return false
|
|
return false
|