Sfoglia il codice sorgente

refactor(更新)
- 优先从人脸库检查,查不到再一个个对比

周文健 4 mesi fa
parent
commit
b858d18250

+ 1 - 0
app/src/main/java/com/grkj/iscs/ISCSApplication.kt

@@ -56,6 +56,7 @@ class ISCSApplication : Application() {
         SIKCore.init(this)
         //todo 模拟器不支持
         ArcSoftUtil.checkActiveStatus(this)
+        ArcSoftUtil.initEngine(this)
         if (!EventBus.getDefault().isRegistered(this)) {
             EventBus.getDefault().register(this)
         }

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt

@@ -93,6 +93,7 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
 
     override fun initData() {
         super.initData()
+        viewModel.registerFaceFeature().observe(this){}
         //todo 测试用,直接创建管理员账号
 //        viewModel.insertAdminAccount().observe(this){}
         requestPermissionsIfNeeded(*Constants.needPermission) {
@@ -142,7 +143,6 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
 
     override fun onResume() {
         super.onResume()
-        viewModel.registerFaceFeature().observe(this){}
         MainDomainData.clear()
         FingerprintUtil.init(this)
         FingerprintUtil.start()

+ 26 - 30
app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt

@@ -128,12 +128,16 @@ class LoginDialog(
                     FingerprintUtil.start()
                     FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
                         override fun onScan(bitmap: Bitmap) {
-                            if (ISCSConfig.isNetVersion){
+                            if (ISCSConfig.isNetVersion) {
                                 LoadingEvent.sendLoadingEvent(
                                     CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
                                     true
                                 )
-                                viewModel.loginWithFingerprint(ImageConvertUtils.bitmapToBase64(bitmap).toString())
+                                viewModel.loginWithFingerprint(
+                                    ImageConvertUtils.bitmapToBase64(
+                                        bitmap
+                                    ).toString()
+                                )
                                     .observe(lifecycleOwner) { isSuccess ->
                                         LoadingEvent.sendLoadingEvent()
                                         callBack?.invoke(isSuccess)
@@ -142,7 +146,7 @@ class LoginDialog(
                         }
 
                         override fun onScan(temp: ByteArray?) {
-                            if (!ISCSConfig.isNetVersion){
+                            if (!ISCSConfig.isNetVersion) {
                                 viewModel.loginWithFingerprint(temp)
                                     .observe(lifecycleOwner) { isSuccess ->
                                         LoadingEvent.sendLoadingEvent()
@@ -183,40 +187,32 @@ class LoginDialog(
     private fun startFace() {
         ArcSoftUtil.inDetecting = false
         ActivityTracker.getCurrentActivity()?.let { context ->
-            ArcSoftUtil.initEngine(context)
-            ArcSoftUtil.initCamera(
-                context,
+            ArcSoftUtil.checkCamera(
                 context.windowManager,
                 mBinding.preview!!
-            ) { bitmap, faceSize, alive ->
-                bitmap?.let { itBitmap ->
-                    if (faceSize == 0) {
-                        inDetecting = false
-                        return@let
-                    }
-                    if (inFaceChecking) {
-                        inDetecting = false
-                        return@let
-                    }
-                    inFaceChecking = true
-                    viewModel.loginWithFace(
-                        ImageConvertUtils.bitmapToBase64(itBitmap).toString()
-                    ).observe(lifecycleOwner) {
-                        if (it == false) {
-                            ThreadUtils.runOnMainDelayed(1000) {
-                                inDetecting = false
-                                inFaceChecking = false
+            ) { bitmap,userId ->
+                viewModel.loginWithUserId(userId).observe(lifecycleOwner) {
+                    if (it == false) {
+                        viewModel.loginWithFace(ImageConvertUtils.bitmapToBase64(bitmap).toString()).observe(lifecycleOwner){
+                            if (it == false) {
+                                ThreadUtils.runOnMainDelayed(1000) {
+                                    inDetecting = false
+                                    inFaceChecking = false
+                                }
+                            } else {
+                                ArcSoftUtil.stop()
                             }
-                        } else {
-                            ArcSoftUtil.stop()
+                            callBack?.invoke(it)
                         }
+                    } else {
+                        ArcSoftUtil.stop()
                         callBack?.invoke(it)
                     }
-                    LoadingEvent.sendLoadingEvent(
-                        context.getString(com.grkj.ui_base.R.string.face_detected_do_login),
-                        true
-                    )
                 }
+                LoadingEvent.sendLoadingEvent(
+                    context.getString(com.grkj.ui_base.R.string.face_detected_do_login),
+                    true
+                )
             }
         }
     }

+ 10 - 1
app/src/main/java/com/grkj/iscs/features/login/viewmodel/LoginViewModel.kt

@@ -2,7 +2,6 @@ package com.grkj.iscs.features.login.viewmodel
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
-import com.grkj.data.repository.ISysMenuRepository
 import com.grkj.data.repository.IUserRepository
 import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.ui_base.base.BaseViewModel
@@ -90,6 +89,16 @@ class LoginViewModel @Inject constructor(
         }
     }
 
+    /**
+     * 人脸登录
+     */
+    fun loginWithUserId(userId: Long?): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            val loginSuccess = userRepository.loginWithUserId(userId)
+            emit(loginSuccess)
+        }
+    }
+
     /**
      * 退出登录
      */

+ 0 - 1
app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt

@@ -166,7 +166,6 @@ class CheckFaceDialog(
     private fun startFace() {
         ArcSoftUtil.inDetecting = false
         ActivityTracker.getCurrentActivity()?.let { context ->
-            ArcSoftUtil.initEngine(context)
             ArcSoftUtil.initCamera(
                 context, context.windowManager, mBinding.preview!!
             ) { bitmap, faceSize, alive ->

+ 6 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFaceFragment.kt

@@ -61,6 +61,8 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
             binding.faceSetLayout.isVisible = true
             binding.image.isVisible = false
             binding.previewLayout.isVisible = true
+            binding.confirm.isVisible = false
+            binding.recapture.isVisible = false
             startFace()
         }
         binding.cancel.setDebouncedClickListener {
@@ -69,11 +71,15 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
             binding.faceSetLayout.isVisible = false
             binding.image.isVisible = false
             binding.previewLayout.isVisible = true
+            binding.confirm.isVisible = false
+            binding.recapture.isVisible = false
         }
         binding.confirm.setDebouncedClickListener {
             releaseFace()
             binding.faceViewLayout.isVisible = true
             binding.faceSetLayout.isVisible = false
+            binding.confirm.isVisible = false
+            binding.recapture.isVisible = false
             val saveFileName =
                 "${MainDomainData.userInfo?.userId}_face_${TimeUtils.nowString("yyyyMMddHHmmss")}"
             val imageData =
@@ -135,7 +141,6 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
         binding.previewLayout.isVisible = true
         binding.image.isVisible = false
         ArcSoftUtil.inDetecting = false
-        ArcSoftUtil.initEngine(requireContext())
         ArcSoftUtil.initCamera(
             requireContext(),
             requireActivity().windowManager,

+ 0 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/UserInfoFragment.kt

@@ -133,7 +133,6 @@ class UserInfoFragment : BaseFragment<FragmentUserInfoBinding>() {
         ArcSoftUtil.inDetecting = false
         binding.preview.isVisible = true
         binding.image.isVisible = false
-        ArcSoftUtil.initEngine(requireContext())
         ArcSoftUtil.initCamera(
             requireContext(),
             requireActivity().windowManager,

+ 5 - 0
data/src/main/java/com/grkj/data/repository/IUserRepository.kt

@@ -148,4 +148,9 @@ interface IUserRepository {
      * 获取所有人脸数据
      */
     fun getAllFaceData(): List<SysUserCharacteristicDo>
+
+    /**
+     * userId登录
+     */
+    fun loginWithUserId(userId: Long?): Boolean
 }

+ 4 - 0
data/src/main/java/com/grkj/data/repository/impl/network/NetworkUserRepository.kt

@@ -109,6 +109,10 @@ class NetworkUserRepository @Inject constructor() : BaseRepository(), IUserRepos
         TODO("Not yet implemented")
     }
 
+    override fun loginWithUserId(userId: Long?): Boolean {
+        TODO("Not yet implemented")
+    }
+
     override fun getAllUsersWithRole(): List<SysUserVo> {
         TODO("Not yet implemented")
     }

+ 25 - 0
data/src/main/java/com/grkj/data/repository/impl/standard/UserRepository.kt

@@ -376,4 +376,29 @@ class UserRepository @Inject constructor(
     override fun getAllFaceData() : List<SysUserCharacteristicDo>{
         return userDao.getFaceData()
     }
+
+    override fun loginWithUserId(userId: Long?): Boolean {
+       return if (userId != null) {
+            val sysUserDo = userDao.getUserInfoByUserId(userId.toString())
+            if (sysUserDo != null) {
+                MainDomainData.userInfo = sysUserDo
+                val userCardList = hardwareDao.getIsJobCardByUserId(sysUserDo.userId)
+                val roleDatas = roleDao.getRoleDataByUserId(sysUserDo.userId)
+                val userBiometricDataVo = userDao.getUserBiometricData(sysUserDo.userId)
+                MainDomainData.userBiometricDataVo = userBiometricDataVo
+                MainDomainData.userCardList = userCardList
+                MainDomainData.roleKeys = roleDatas.joinToString(",") { it.roleKey }
+                MainDomainData.permissions =
+                    sysMenuDao.getPermissionsByRoleIds(roleDatas.map { it.roleId })
+                logger.info("用户信息:{}", MainDomainData.userInfo.toString())
+                logger.info("用户角色:{}", MainDomainData.roleKeys)
+                logger.info("用户权限:{}", MainDomainData.permissions)
+                true
+            } else {
+                false
+            }
+        } else {
+            false
+        }
+    }
 }

+ 80 - 81
shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt

@@ -47,7 +47,6 @@ object ArcSoftUtil {
     private var previewSize: Camera.Size? = null
     private val rgbCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
     private var faceEngine: FaceEngine? = null
-    private var checkFaceEngine: FaceEngine? = null
     private val cameraWidth: Int = 640
     private val cameraHeight: Int = 480
     private var afCode = -1
@@ -56,7 +55,6 @@ object ArcSoftUtil {
 
     private const val ACTION_REQUEST_PERMISSIONS: Int = 0x001
     var isActivated = false
-    private var isInit = false
     var inDetecting = false
 
     /**
@@ -94,11 +92,7 @@ object ArcSoftUtil {
     }
 
     fun initEngine(context: Context) {
-        if (isInit) {
-            return
-        }
         faceEngine = FaceEngine()
-        checkFaceEngine = FaceEngine()
         afCode = faceEngine!!.init(
             context,
             DetectMode.ASF_DETECT_MODE_VIDEO,
@@ -110,18 +104,6 @@ object ArcSoftUtil {
         if (afCode != ErrorInfo.MOK) {
             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() {
@@ -185,17 +167,12 @@ object ArcSoftUtil {
                     return
                 }
 
-                val ageInfoList: List<AgeInfo> = ArrayList()
-                val genderInfoList: List<GenderInfo> = ArrayList()
-                val face3DAngleList: List<Face3DAngle> = ArrayList()
                 val faceLivenessInfoList: List<LivenessInfo> = ArrayList()
-                val ageCode = faceEngine!!.getAge(ageInfoList)
-                val genderCode = faceEngine!!.getGender(genderInfoList)
                 val livenessCode = faceEngine!!.getLiveness(faceLivenessInfoList)
 
                 // 有其中一个的错误码不为ErrorInfo.MOK,return
-                if ((ageCode or genderCode or livenessCode) != ErrorInfo.MOK) {
-                    logger.debug("人脸检测结果:年龄、性别、角度、获取验证失败")
+                if ((livenessCode) != ErrorInfo.MOK) {
+                    logger.debug("人脸检测结果:${livenessCode}")
                     inDetecting = false
                     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(
-        context: Context,
         windowManager: WindowManager,
         preview: View,
-        needCheckCenter: Boolean = false,
-        callBack: (Long?) -> Unit
+        callBack: (Bitmap?, Long?) -> Unit
     ) {
         val metrics = DisplayMetrics()
         windowManager.defaultDisplay.getMetrics(metrics)
@@ -311,21 +249,13 @@ object ArcSoftUtil {
                 }
                 inDetecting = true
                 val faceInfoList: List<FaceInfo> = ArrayList()
-                var code = checkFaceEngine!!.detectFaces(
+                var code = faceEngine!!.detectFaces(
                     nv21,
                     previewSize!!.width,
                     previewSize!!.height,
                     FaceEngine.CP_PAF_NV21,
                     faceInfoList
                 )
-
-                if (needCheckCenter && !faceInfoList[0].rect.isInCenterArea(
-                        previewSize!!.width, previewSize!!.height
-                    )
-                ) {
-                    inDetecting = false
-                    return
-                }
                 if (code == ErrorInfo.MOK && faceInfoList.isNotEmpty()) {
                     code = faceEngine!!.process(
                         nv21,
@@ -349,19 +279,19 @@ object ArcSoftUtil {
 
                 // 有其中一个的错误码不为ErrorInfo.MOK,return
                 if ((livenessCode) != ErrorInfo.MOK) {
-                    logger.debug("人脸检测结果:年龄、性别、角度、获取验证失败")
+                    logger.debug("人脸检测结果:${livenessCode}")
                     inDetecting = false
                     return
                 }
 
                 // 自己加的,必须有活体检测
                 if (faceLivenessInfoList.none { it.liveness == LivenessInfo.ALIVE }) {
-                    callBack(null)
+                    callBack(null, null)
                     inDetecting = false
                     return
                 }
                 val faceFeature = FaceFeature()
-                checkFaceEngine?.extractFaceFeature(
+                faceEngine?.extractFaceFeature(
                     nv21,
                     previewSize!!.width,
                     previewSize!!.height,
@@ -371,9 +301,21 @@ object ArcSoftUtil {
                     0,
                     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")
-                callBack(searchResult?.faceFeatureInfo?.searchId?.toLong())
+                val bitmap =
+                    ImageConvertUtils.nv21ToBitmap(nv21, previewSize!!.width, previewSize!!.height)
+
+                callBack(bitmap, searchResult?.faceFeatureInfo?.searchId?.toLong())
             }
 
             override fun onCameraClosed() {
@@ -414,6 +356,63 @@ object ArcSoftUtil {
 //        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 人脸,返回是否同人
      * @param threshold 阈值,一般设置 0.7f 左右
@@ -437,7 +436,7 @@ object ArcSoftUtil {
         val imgBDetectResultCode = faceEngine?.detectFaces(
             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}")
         if (facesA.isEmpty() || facesB.isEmpty()) {
             return false

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt

@@ -229,7 +229,7 @@ object BleConnectionManager {
     private fun connectKey() {
         if (connectListeners.isEmpty()) return
         if (isPreparing || BleManager.getInstance().allConnectedDevice.size >= maxStandbyCount) {
-            logger.info("暂时不能连接:${isPreparing},${BleManager.getInstance().allConnectedDevice.size >= maxStandbyCount}")
+            logger.debug("暂时不能连接:${isPreparing},${BleManager.getInstance().allConnectedDevice.size >= maxStandbyCount}")
             ThreadUtils.runOnMainDelayed(1000) { connectKey() }
             return
         }