人脸识别+采集分开处理

This commit is contained in:
2026-02-05 13:32:45 +08:00
parent 67f5d07f25
commit 2ee4d2d320
4 changed files with 1146 additions and 64 deletions
@@ -39,6 +39,9 @@ import com.sw.platecabinet.MyApp
import com.sw.platecabinet.R
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
import com.sw.platecabinet.ext.clickWithDebounce
import com.sw.platecabinet.ext.gone
import com.sw.platecabinet.ext.visible
import com.sw.platecabinet.model.response.EquipmentUserInfo
import com.sw.platecabinet.model.response.UserFaceModel
import com.sw.platecabinet.utils.BitmapSaver
@@ -148,7 +151,21 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
soundMap[COLLECT_SUCCESS] = R.raw.collect_success
soundMap[RECOGNIZE_SUCCESS] = R.raw.recognize_success
soundMap[NO_PLATE_REMIND] = R.raw.no_plate_remind
SoundPoolUtil.getInstance().loadR(this, soundMap);
SoundPoolUtil.getInstance().loadR(this, soundMap)
binding.btnCollect.clickWithDebounce {
//先重置,后采集
resetRecognizeState()
//采集数据按钮
retryFailCount = 0
isCollectFace = true
collectFace()
}
binding.btnRetry.clickWithDebounce {
//重新识别按钮
resetRecognizeState()
}
}
@@ -187,6 +204,17 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private val regDebouncer = Debouncer(3000)
private var registerHandler: RegisterCallbackHandler? = null
private fun isFitData(userFaceInfo: UserFaceInfo?): Boolean {
if (userFaceInfo == null) return false
val headBmp = userFaceInfo.headBmp
if (headBmp == null) return false
if (headBmp.width <= 200 || headBmp.height <= 200) {
loadLogInfo("collectFace,isFitData:拿到人脸提取特征数据照片过小-----------")
return false
}
return true
}
private fun initArcViewModel() {
recognizeViewModel.setLiveType(livenessType)
recognizeViewModel.prepareRegister()
@@ -195,14 +223,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
if (!isCollectFace) {
return@setCallback
}
if (this.userFaceInfo == null && userFaceInfo != null) {
if (this.userFaceInfo == null && isFitData(userFaceInfo)) {
recognizeViewModel.updateRegisterStatus(RecognizeViewModel.REGISTER_STATUS_DONE)
this.userFaceInfo = userFaceInfo
getFaceDataBlock { faceData, headBmp ->
isCollecting.set(false)
isCollectFace = false
sendFaceData(faceData, headBmp)
}
getFaceDataBlock()
}
}
}
@@ -247,11 +271,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? ->
loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
if (faceUseSwitch) {
loadFaceRecognizeResult2(result)
return@Observer
}
loadFaceRecognizeResult(result)
loadFaceRecognizeResult3(result)
})
recognizeViewModel.drawRectInfoText.observe(this, Observer { info ->
@@ -288,6 +308,81 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private val openPlateDebouncer = Debouncer(5000)
private val isCollecting = AtomicBoolean(false)
private fun loadFaceRecognizeResult3(result: CompareResult?) {
val similar = result?.similar ?: return
binding.tvSimilarValue.text = "$similar${retryFailCount}"
loadLogInfo(
"collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, " +
"fail=$faceFailThreshold, similar=$similar, retry=$retryFailCount"
)
if (similar >= faceSuccessThreshold) {
val userId = result.faceEntity?.userName
if (userId.isNullOrBlank()) {
loadLogInfo("collectFace,recognizeUserId 识别成功但 userId 为空,忽略")
return
}
loadLogInfo(
"collectFace,recognizeUserId 识别成功 userId=$userId, time=${DateTimeUtils.getDateTimeString()}"
)
// 成功后必须重置状态
retryFailCount = 0
isCollecting.set(false)
isCollectFace = false
currentUserId = userId
// 防抖,防止重复开闸
openPlateDebouncer.debounce {
openPlate(userId)
}
return
}
if (isCollectFace) {
loadLogInfo("collectFace,recognizeUserId 正在采集中,忽略失败结果 similar=$similar")
return
}
// if (similar <= faceFailThreshold || retryFailCount >= maxFailCount) {
if (retryFailCount >= maxFailCount) {
loadLogInfo(
"collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " +
"retry=$retryFailCount, time=${DateTimeUtils.getDateTimeString()}"
)
if (!isCollecting.compareAndSet(false, true)) {
loadLogInfo("collectFace 已在采集中,忽略重复触发")
return
}
recognizeFail()
return
}
retryFailCount++
loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
}
private fun recognizeFail() {
countDownTimer?.cancel()
binding.tvToInit.text = ""
binding.tvSimilarValue.text = ""
binding.llCollectButton.visible()
binding.btnCollect.run {
visible()
if (tag == "1") {
binding.btnRetry.gone()
text = "重新采集"
tag = "1"
} else {
binding.btnRetry.visible()
"新用户采集"
tag = "1"
}
}
}
/**
* 根据相似度similar>设定阈值0.8作为识别成功判断,
* 如果similar<0.3作为识别失败判断,
@@ -352,38 +447,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
loadLogInfo("collectFace,recognizeUserId 中间态重试,retryFailCount=$retryFailCount")
}
// private fun loadFaceRecognizeResult2(result: CompareResult?) {
//
// if(isCollectFace){
// return
// }
//
// val similar = result?.similar ?: 0f
// binding.tvSimilarValue.text = "$similar${retryFailCount}次"
// loadLogInfo("collectFace,recognizeUserId 人脸识别配置阈值为:${faceSuccessThreshold},失败阈值为:${faceFailThreshold},相似度为:${similar},失败次数为:${retryFailCount}")
// if (similar > faceSuccessThreshold) {
// loadLogInfo("collectFace,recognizeUserId 相似度为:${similar},识别成功时间:${DateTimeUtils.getDateTimeString()}")
// //大 于识别阈值,作为识别成功判断
// currentUserId = result?.faceEntity?.userName
// Debouncer(5000).debounce { openPlate(currentUserId) }
// return
// }
// loadLogInfo("collectFace,recognizeUserId 人脸识别相似度为:${similar},失败次数为:${retryFailCount}")
// if (similar < faceFailThreshold || retryFailCount >= maxFailCount) {
// //相似度低于识别错误阈值进行采集、识别失败次数大于等于最大失败次数,作为识别失败判断
// if (isCollectFace.not()) {
// //非采集中
// loadLogInfo("collectFace,recognizeUserId 未识别到人脸信息,相似度为:${similar},开始采集时间:${DateTimeUtils.getDateTimeString()}")
// isCollectFace = true
// collectFace()
// return
// }
// }
// //满足similar >= faceFailThreshold && similar <= successThreshold时进行重试
// retryFailCount++
// loadLogInfo("collectFace,recognizeUserId 人脸识别失败次数为:${retryFailCount}")
// }
/**
* 根据相似度similar>设定阈值0.8作为识别是否成功来加载人脸识别结果
*/
@@ -449,6 +512,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Debouncer(5000).debounce {
//打开柜子
PlateUtils.open(this, item.equipmentBoxCode, false)
countDownTimer?.cancel()
goInitActivity()
}
currentPlateInfo = item
MyApp.plateList = items
@@ -600,6 +666,9 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
currentPlateInfo = null
currentUserId = null
userFaceInfo = null
binding.btnCollect.tag = ""
binding.tvSimilarValue.text = ""
retryFailCount = 0
}
recognizeViewModel.clearLeftFace(facePreviewInfoList)
}
@@ -680,13 +749,13 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}
}
/**
* 临时用户id
*/
private var tempUserId: String = ""
override fun onResume() {
super.onResume()
registerHandler = RegisterCallbackHandler()
try {
if (isFirstOpen) {
goInitActivity()
@@ -695,26 +764,32 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}, 1000)
return
}
retryFailCount = 0
binding.tvSimilarValue.text = ""
isCollecting.set(false)
isCollectFace = false
plateEnable = true
collectCount = 0
tempUserId = "${System.currentTimeMillis()}"
resumeCamera()
userViewModel.resetUserInfo()
countDownTimer?.let {
it.cancel()
it.start()
}
// initFaceScheduler()
// checkFaceState()
resetRecognizeState()
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 重置识别状态
*/
private fun resetRecognizeState() {
binding.llCollectButton.gone()
retryFailCount = 0
binding.tvSimilarValue.text = ""
isCollecting.set(false)
isCollectFace = false
plateEnable = true
collectCount = 0
tempUserId = "${System.currentTimeMillis()}"
resumeCamera()
registerHandler = RegisterCallbackHandler()
countDownTimer?.let {
it.cancel()
it.start()
}
}
private var isFirstOpen = true
protected override fun onPause() {
@@ -742,7 +817,11 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}
override fun onFinish() {
goInitActivity()
if (facePreviewInfoList.isNullOrEmpty()) {
goInitActivity()
} else {
recognizeFail()
}
}
}
}
@@ -813,16 +892,22 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
}
}
private fun getFaceDataBlock(block: (String, Bitmap) -> Unit) {
if (userFaceInfo == null || userFaceInfo?.faceFeature?.featureData == null) {
private fun getFaceDataBlock() {
if (userFaceInfo?.faceFeature?.featureData == null) {
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据为null-----------")
return
}
val faceData: String? = Base64.encode(userFaceInfo?.faceFeature?.featureData)
if (faceData.isNullOrBlank()) {
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据Base64编码为空")
return
}
loadLogInfo("collectFace,getFaceData: ----------7,拿到人脸提取特征数据时间:${DateTimeUtils.getDateTimeString()}-----------")
block(faceData, userFaceInfo!!.headBmp)
val headBmp = userFaceInfo!!.headBmp
//block(faceData, headBmp)
isCollecting.set(false)
isCollectFace = false
sendFaceData(faceData, headBmp)
}
/**