|
@ -39,6 +39,8 @@ import com.baidu.idl.main.facesdk.FaceInfo; |
|
|
import com.baidu.idl.main.facesdk.model.BDFaceImageInstance; |
|
|
import com.baidu.idl.main.facesdk.model.BDFaceImageInstance; |
|
|
import com.ouxuan.oxface.utils.LogManager; |
|
|
import com.ouxuan.oxface.utils.LogManager; |
|
|
|
|
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 简化版人脸识别界面 - 只显示视频流 |
|
|
* 简化版人脸识别界面 - 只显示视频流 |
|
|
*/ |
|
|
*/ |
|
@ -51,6 +53,27 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
// 图片越大,性能消耗越大,也可以选择640*480, 1280*720 |
|
|
// 图片越大,性能消耗越大,也可以选择640*480, 1280*720 |
|
|
private static final int PREFER_WIDTH = SingleBaseConfig.getBaseConfig().getRgbAndNirWidth(); |
|
|
private static final int PREFER_WIDTH = SingleBaseConfig.getBaseConfig().getRgbAndNirWidth(); |
|
|
private static final int PERFER_HEIGH = SingleBaseConfig.getBaseConfig().getRgbAndNirHeight(); |
|
|
private static final int PERFER_HEIGH = SingleBaseConfig.getBaseConfig().getRgbAndNirHeight(); |
|
|
|
|
|
|
|
|
|
|
|
// 新增控制变量 |
|
|
|
|
|
private static int PROCESS_FRAME_INTERVAL = 10; // 降低处理频率,每隔10帧处理一次 |
|
|
|
|
|
private int frameCounter = 0; |
|
|
|
|
|
private boolean needSendFaceImage = false; // 是否需要将人脸图片转为base64发送 |
|
|
|
|
|
private long lastProcessTime = 0; |
|
|
|
|
|
private long lastBackgroundProcessTime = 0; // 应用在后台时的最后处理时间 |
|
|
|
|
|
private static long MIN_PROCESS_INTERVAL = 1000; // 增加最小处理间隔至1秒 |
|
|
|
|
|
|
|
|
|
|
|
// 智能调节处理频率的控制变量 |
|
|
|
|
|
private static final int FAST_PROCESS_FRAME_INTERVAL = 3; // 快速处理频率:每3帧处理一次 |
|
|
|
|
|
private static final long FAST_MIN_PROCESS_INTERVAL = 300; // 快速处理间隔:300ms |
|
|
|
|
|
private static final int SLOW_PROCESS_FRAME_INTERVAL = 30; // 慢速处理频率:每30帧处理一次 |
|
|
|
|
|
private static final long SLOW_MIN_PROCESS_INTERVAL = 3000; // 慢速处理间隔:3000ms |
|
|
|
|
|
private static final long FACE_DETECTION_TIMEOUT = 5000; // 人脸检测超时时间:5秒 |
|
|
|
|
|
|
|
|
|
|
|
private long lastFaceDetectedTime = 0; // 上次检测到人脸的时间 |
|
|
|
|
|
private boolean isFaceDetected = false; // 当前是否检测到人脸 |
|
|
|
|
|
private int consecutiveNoFaceCount = 0; // 连续未检测到人脸的次数 |
|
|
|
|
|
private static final int CONSECUTIVE_NO_FACE_THRESHOLD = 20; // 连续未检测到人脸的阈值 |
|
|
|
|
|
|
|
|
private Context mContext; |
|
|
private Context mContext; |
|
|
private AutoTexturePreviewView mAutoCameraPreviewView; |
|
|
private AutoTexturePreviewView mAutoCameraPreviewView; |
|
|
private TextureView mDrawDetectFaceView; |
|
|
private TextureView mDrawDetectFaceView; |
|
@ -133,6 +156,11 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
mContext = this; |
|
|
mContext = this; |
|
|
initView(); |
|
|
initView(); |
|
|
|
|
|
|
|
|
|
|
|
// 初始化人脸检测状态 |
|
|
|
|
|
lastFaceDetectedTime = System.currentTimeMillis(); |
|
|
|
|
|
isFaceDetected = false; |
|
|
|
|
|
consecutiveNoFaceCount = 0; |
|
|
|
|
|
|
|
|
// 检查并请求相机权限 |
|
|
// 检查并请求相机权限 |
|
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) |
|
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) |
|
|
!= PackageManager.PERMISSION_GRANTED) { |
|
|
!= PackageManager.PERMISSION_GRANTED) { |
|
@ -143,6 +171,9 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
LogManager.logInfo(TAG, "相机权限已授予"); |
|
|
LogManager.logInfo(TAG, "相机权限已授予"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 启动内存优化周期性任务 |
|
|
|
|
|
startMemoryOptimizationTask(); |
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onCreate"); |
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onCreate"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -320,41 +351,164 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
|
|
|
|
|
|
private void startTestOpenDebugRegisterFunction() { |
|
|
private void startTestOpenDebugRegisterFunction() { |
|
|
LogManager.logInfo(TAG, "启动摄像头预览"); |
|
|
LogManager.logInfo(TAG, "启动摄像头预览"); |
|
|
// 设置摄像头方向 |
|
|
|
|
|
if (SingleBaseConfig.getBaseConfig().getRBGCameraId() != -1){ |
|
|
|
|
|
CameraPreviewManager.getInstance().setCameraFacing(SingleBaseConfig.getBaseConfig().getRBGCameraId()); |
|
|
|
|
|
} else { |
|
|
|
|
|
CameraPreviewManager.getInstance().setCameraFacing(CameraPreviewManager.CAMERA_FACING_FRONT); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CameraPreviewManager.getInstance().startPreview(mContext, mAutoCameraPreviewView, |
|
|
|
|
|
PREFER_WIDTH, PERFER_HEIGH, new CameraDataCallback() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void onGetCameraData(byte[] data, Camera camera, int width, int height) { |
|
|
|
|
|
// 摄像头预览数据进行人脸检测 |
|
|
|
|
|
if (isNeedCamera) { |
|
|
|
|
|
FaceSDKManager.getInstance().onDetectCheck(data, null, null, |
|
|
|
|
|
height, width, 1, new FaceDetectCallBack() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void onFaceDetectCallback(LivenessModel livenessModel) { |
|
|
|
|
|
// 开发模式结果输出 |
|
|
|
|
|
checkOpenDebugResult(livenessModel); |
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 设置摄像头方向 |
|
|
|
|
|
if (SingleBaseConfig.getBaseConfig().getRBGCameraId() != -1){ |
|
|
|
|
|
CameraPreviewManager.getInstance().setCameraFacing(SingleBaseConfig.getBaseConfig().getRBGCameraId()); |
|
|
|
|
|
} else { |
|
|
|
|
|
CameraPreviewManager.getInstance().setCameraFacing(CameraPreviewManager.CAMERA_FACING_FRONT); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CameraPreviewManager.getInstance().startPreview(mContext, mAutoCameraPreviewView, |
|
|
|
|
|
PREFER_WIDTH, PERFER_HEIGH, new CameraDataCallback() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void onGetCameraData(byte[] data, Camera camera, int width, int height) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 摄像头预览数据进行人脸检测 |
|
|
|
|
|
if (isNeedCamera) { |
|
|
|
|
|
// 增加帧计数器和时间间隔控制 |
|
|
|
|
|
frameCounter++; |
|
|
|
|
|
long currentTime = System.currentTimeMillis(); |
|
|
|
|
|
|
|
|
|
|
|
// 智能调节处理频率 |
|
|
|
|
|
adjustProcessFrequency(currentTime); |
|
|
|
|
|
|
|
|
|
|
|
// 只有当满足处理条件时才进行人脸检测 |
|
|
|
|
|
if (frameCounter % PROCESS_FRAME_INTERVAL == 0 && |
|
|
|
|
|
(currentTime - lastProcessTime) > MIN_PROCESS_INTERVAL) { |
|
|
|
|
|
lastProcessTime = currentTime; |
|
|
|
|
|
|
|
|
|
|
|
// 检查应用是否处于前台 |
|
|
|
|
|
if (!isApplicationInForeground()) { |
|
|
|
|
|
// 如果应用在后台,减少处理频率,每隔10秒处理一次 |
|
|
|
|
|
if ((currentTime - lastBackgroundProcessTime) < 10000) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
lastBackgroundProcessTime = currentTime; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
FaceSDKManager.getInstance().onDetectCheck(data, null, null, |
|
|
|
|
|
height, width, 1, new FaceDetectCallBack() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void onFaceDetectCallback(LivenessModel livenessModel) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 更新人脸检测状态 |
|
|
|
|
|
updateFaceDetectionStatus(livenessModel); |
|
|
|
|
|
|
|
|
|
|
|
// 开发模式结果输出 |
|
|
|
|
|
checkOpenDebugResult(livenessModel); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "人脸检测回调处理异常", e); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void onTip(int code, String msg) { |
|
|
|
|
|
LogManager.logInfo(TAG, "人脸检测提示 - 代码: " + code + ", 消息: " + msg); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void onTip(int code, String msg) { |
|
|
|
|
|
try { |
|
|
|
|
|
if(!msg.equals("未检测到人脸")){ |
|
|
|
|
|
LogManager.logInfo(TAG, "人脸检测提示onTip - 代码: " + code + ", 消息: " + msg); |
|
|
|
|
|
} |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "人脸检测提示处理异常", e); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void onFaceDetectDarwCallback(LivenessModel livenessModel) { |
|
|
|
|
|
// 绘制人脸框 |
|
|
|
|
|
showFrame(livenessModel); |
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
public void onFaceDetectDarwCallback(LivenessModel livenessModel) { |
|
|
|
|
|
try { |
|
|
|
|
|
// 绘制人脸框 |
|
|
|
|
|
showFrame(livenessModel); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "人脸框绘制回调处理异常", e); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} else if (frameCounter % 30 == 0) { |
|
|
|
|
|
// 对于跳过处理的帧,每30帧清空一次画布,确保无人脸时画面干净 |
|
|
|
|
|
try { |
|
|
|
|
|
LivenessModel emptyModel = new LivenessModel(); |
|
|
|
|
|
emptyModel.setTrackFaceInfo(null); |
|
|
|
|
|
showFrame(emptyModel); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "清空画布时发生异常", e); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "摄像头数据处理异常", e); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
LogManager.logError(TAG, "启动摄像头预览失败", e); |
|
|
|
|
|
// 尝试重新初始化摄像头 |
|
|
|
|
|
new Handler().postDelayed(new Runnable() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void run() { |
|
|
|
|
|
if (!isFinishing()) { |
|
|
|
|
|
LogManager.logInfo(TAG, "尝试重新启动摄像头预览"); |
|
|
|
|
|
startTestOpenDebugRegisterFunction(); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
}, 5000); // 5秒后重试 |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 智能调节处理频率 |
|
|
|
|
|
* @param currentTime 当前时间 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void adjustProcessFrequency(long currentTime) { |
|
|
|
|
|
// 如果检测到人脸,加速处理 |
|
|
|
|
|
if (isFaceDetected) { |
|
|
|
|
|
if (PROCESS_FRAME_INTERVAL != FAST_PROCESS_FRAME_INTERVAL || |
|
|
|
|
|
MIN_PROCESS_INTERVAL != FAST_MIN_PROCESS_INTERVAL) { |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL; |
|
|
|
|
|
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL; |
|
|
|
|
|
LogManager.logInfo(TAG, "检测到人脸,加速处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// 如果长时间未检测到人脸,降低处理频率以节省资源 |
|
|
|
|
|
else if (currentTime - lastFaceDetectedTime > FACE_DETECTION_TIMEOUT) { |
|
|
|
|
|
// 检查是否已经处于慢速处理模式 |
|
|
|
|
|
if (PROCESS_FRAME_INTERVAL != SLOW_PROCESS_FRAME_INTERVAL || |
|
|
|
|
|
MIN_PROCESS_INTERVAL != SLOW_MIN_PROCESS_INTERVAL) { |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = SLOW_PROCESS_FRAME_INTERVAL; |
|
|
|
|
|
MIN_PROCESS_INTERVAL = SLOW_MIN_PROCESS_INTERVAL; |
|
|
|
|
|
LogManager.logInfo(TAG, "长时间未检测到人脸,降低处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 更新人脸检测状态 |
|
|
|
|
|
* @param livenessModel 活体检测模型 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void updateFaceDetectionStatus(LivenessModel livenessModel) { |
|
|
|
|
|
long currentTime = System.currentTimeMillis(); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否检测到人脸 |
|
|
|
|
|
boolean faceDetected = (livenessModel != null && |
|
|
|
|
|
livenessModel.getTrackFaceInfo() != null && |
|
|
|
|
|
livenessModel.getTrackFaceInfo().length > 0); |
|
|
|
|
|
|
|
|
|
|
|
if (faceDetected) { |
|
|
|
|
|
// 检测到人脸 |
|
|
|
|
|
isFaceDetected = true; |
|
|
|
|
|
lastFaceDetectedTime = currentTime; |
|
|
|
|
|
consecutiveNoFaceCount = 0; // 重置连续未检测到人脸计数器 |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logDebug(TAG, "检测到人脸"); |
|
|
|
|
|
} else { |
|
|
|
|
|
// 未检测到人脸 |
|
|
|
|
|
consecutiveNoFaceCount++; |
|
|
|
|
|
|
|
|
|
|
|
// 如果连续多次未检测到人脸,标记为未检测到人脸状态 |
|
|
|
|
|
if (consecutiveNoFaceCount >= CONSECUTIVE_NO_FACE_THRESHOLD) { |
|
|
|
|
|
isFaceDetected = false; |
|
|
|
|
|
LogManager.logDebug(TAG, "连续未检测到人脸,当前计数: " + consecutiveNoFaceCount); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@ -366,26 +520,35 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
public void run() { |
|
|
public void run() { |
|
|
Canvas canvas = mDrawDetectFaceView.lockCanvas(); |
|
|
Canvas canvas = mDrawDetectFaceView.lockCanvas(); |
|
|
if (canvas == null) { |
|
|
if (canvas == null) { |
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 始终清空canvas |
|
|
|
|
|
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); |
|
|
|
|
|
|
|
|
|
|
|
// 如果没有模型数据,直接返回清空的画布 |
|
|
if (model == null) { |
|
|
if (model == null) { |
|
|
// 清空canvas |
|
|
|
|
|
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); |
|
|
|
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取人脸信息 |
|
|
FaceInfo[] faceInfos = model.getTrackFaceInfo(); |
|
|
FaceInfo[] faceInfos = model.getTrackFaceInfo(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有检测到人脸,直接返回清空的画布 |
|
|
if (faceInfos == null || faceInfos.length == 0) { |
|
|
if (faceInfos == null || faceInfos.length == 0) { |
|
|
// 清空canvas |
|
|
|
|
|
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); |
|
|
|
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); |
|
|
|
|
|
for (int i = 0 ; i < faceInfos.length;i++) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 只在检测到人脸时绘制人脸框 |
|
|
|
|
|
for (int i = 0; i < faceInfos.length; i++) { |
|
|
FaceInfo faceInfo = faceInfos[i]; |
|
|
FaceInfo faceInfo = faceInfos[i]; |
|
|
|
|
|
|
|
|
|
|
|
// 如果人脸置信度太低,不绘制 |
|
|
|
|
|
if (faceInfo.score < 0.6) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
rectF.set(FaceOnDrawTexturViewUtil.getFaceRectTwo(faceInfo)); |
|
|
rectF.set(FaceOnDrawTexturViewUtil.getFaceRectTwo(faceInfo)); |
|
|
// 检测图片的坐标和显示的坐标不一样,需要转换。 |
|
|
// 检测图片的坐标和显示的坐标不一样,需要转换。 |
|
@ -397,7 +560,8 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
FaceOnDrawTexturViewUtil.drawRect(canvas, |
|
|
FaceOnDrawTexturViewUtil.drawRect(canvas, |
|
|
rectF, paint, 5f, 50f, 25f); |
|
|
rectF, paint, 5f, 50f, 25f); |
|
|
} |
|
|
} |
|
|
// 清空canvas |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 提交canvas |
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
mDrawDetectFaceView.unlockCanvasAndPost(canvas); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
@ -649,7 +813,61 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
@Override |
|
|
@Override |
|
|
protected void onDestroy() { |
|
|
protected void onDestroy() { |
|
|
super.onDestroy(); |
|
|
super.onDestroy(); |
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onDestroy"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 停止摄像头预览 |
|
|
|
|
|
if (CameraPreviewManager.getInstance() != null) { |
|
|
|
|
|
CameraPreviewManager.getInstance().stopPreview(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 释放当前的LivenessModel资源 |
|
|
|
|
|
if (currentLivenessModel != null) { |
|
|
|
|
|
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance(); |
|
|
|
|
|
if (image != null) { |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
} |
|
|
|
|
|
// 清空引用 |
|
|
|
|
|
currentLivenessModel = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 释放绘图资源 |
|
|
|
|
|
if (rectF != null) { |
|
|
|
|
|
rectF = null; |
|
|
|
|
|
} |
|
|
|
|
|
if (paint != null) { |
|
|
|
|
|
paint = null; |
|
|
|
|
|
} |
|
|
|
|
|
if (paintBg != null) { |
|
|
|
|
|
paintBg = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 清除其他相关资源 |
|
|
|
|
|
System.gc(); |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onDestroy - 资源已释放"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
protected void onStop() { |
|
|
|
|
|
super.onStop(); |
|
|
|
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStop - 应用进入后台"); |
|
|
|
|
|
|
|
|
|
|
|
// 应用进入后台时,进一步降低处理频率以节省资源 |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = 30; // 后台时每30帧处理一次 |
|
|
|
|
|
MIN_PROCESS_INTERVAL = 3000; // 后台时最小间隔3秒 |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "后台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
protected void onStart() { |
|
|
|
|
|
super.onStart(); |
|
|
|
|
|
LogManager.logInfo(TAG, "OXFaceOnlineActivity onStart - 应用回到前台"); |
|
|
|
|
|
|
|
|
|
|
|
// 应用回到前台时,恢复正常的处理频率 |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = FAST_PROCESS_FRAME_INTERVAL; // 前台时使用快速处理频率 |
|
|
|
|
|
MIN_PROCESS_INTERVAL = FAST_MIN_PROCESS_INTERVAL; // 前台时使用快速处理间隔 |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "前台模式处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// ***************开发模式结果输出************* |
|
|
// ***************开发模式结果输出************* |
|
@ -743,16 +961,27 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
if (livenessModel == null) { |
|
|
if (livenessModel == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
String base64img = getFaceImageBase64(currentLivenessModel); |
|
|
|
|
|
|
|
|
|
|
|
if (base64img != null) { |
|
|
|
|
|
// Log.i(TAG, "checkResultOnline: " + base64img); |
|
|
|
|
|
Log.i(TAG, "checkResultOnline: Yes! Got a base64img!" ); |
|
|
|
|
|
} else { |
|
|
|
|
|
Log.i(TAG, "run:checkResultOnline base64img score too low "); |
|
|
|
|
|
layoutCompareStatus.setVisibility(View.VISIBLE); |
|
|
|
|
|
textCompareStatus.setTextColor(Color.parseColor("#fec133")); |
|
|
|
|
|
textCompareStatus.setText("请重新识别"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 减少base64转换频率,只有在特定条件下才进行转换 |
|
|
|
|
|
// 例如:每3秒检查一次是否需要发送人脸图像 |
|
|
|
|
|
long currentTime = System.currentTimeMillis(); |
|
|
|
|
|
if (currentTime - searshTime > 3000) { |
|
|
|
|
|
searshTime = currentTime; |
|
|
|
|
|
needSendFaceImage = true; |
|
|
|
|
|
|
|
|
|
|
|
String base64img = getFaceImageBase64(currentLivenessModel); |
|
|
|
|
|
if (base64img != null) { |
|
|
|
|
|
// 这里可以处理base64数据,如上传到服务器等 |
|
|
|
|
|
Log.i(TAG, "checkResultOnline: 获取到人脸base64数据"); |
|
|
|
|
|
|
|
|
|
|
|
// 处理完成后重置标志 |
|
|
|
|
|
needSendFaceImage = false; |
|
|
|
|
|
} else { |
|
|
|
|
|
Log.i(TAG, "run:checkResultOnline base64img score too low "); |
|
|
|
|
|
layoutCompareStatus.setVisibility(View.VISIBLE); |
|
|
|
|
|
textCompareStatus.setTextColor(Color.parseColor("#fec133")); |
|
|
|
|
|
textCompareStatus.setText("请重新识别"); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
@ -762,15 +991,134 @@ public class OXFaceOnlineActivity extends BaseActivity implements View.OnClickLi |
|
|
if (livenessModel == null) return null; |
|
|
if (livenessModel == null) return null; |
|
|
FaceInfo faceInfo = livenessModel.getFaceInfo(); |
|
|
FaceInfo faceInfo = livenessModel.getFaceInfo(); |
|
|
|
|
|
|
|
|
if (true) { //判定条件 |
|
|
|
|
|
|
|
|
// 添加判断条件,减少不必要的base64转换 |
|
|
|
|
|
if (faceInfo != null && faceInfo.bestImageScore > SingleBaseConfig.getBaseConfig().getBestImageScore()) { |
|
|
BDFaceImageInstance image = livenessModel.getBdFaceImageInstance(); |
|
|
BDFaceImageInstance image = livenessModel.getBdFaceImageInstance(); |
|
|
Bitmap bitmap = BitmapUtils.getInstaceBmp(image); |
|
|
|
|
|
|
|
|
|
|
|
String bitmap_str = BitmapUtils.bitmapToBase64(bitmap); |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
return bitmap_str; // 简化实现,实际项目中需要实现 bitmap 转 base64 的功能 |
|
|
|
|
|
} else { |
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
|
if (image != null) { |
|
|
|
|
|
Bitmap bitmap = BitmapUtils.getInstaceBmp(image); |
|
|
|
|
|
|
|
|
|
|
|
// 仅在确实需要使用base64数据时才进行转换 |
|
|
|
|
|
if (needSendFaceImage) { |
|
|
|
|
|
String bitmap_str = BitmapUtils.bitmapToBase64(bitmap); |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
return bitmap_str; |
|
|
|
|
|
} else { |
|
|
|
|
|
// 如果不需要发送,则不进行base64转换,直接释放资源 |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
if (bitmap != null && !bitmap.isRecycled()) { |
|
|
|
|
|
bitmap.recycle(); |
|
|
|
|
|
} |
|
|
|
|
|
return "dummy_base64_placeholder"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 检查应用是否在前台 |
|
|
|
|
|
* @return 如果应用在前台,则返回true;否则返回false |
|
|
|
|
|
*/ |
|
|
|
|
|
private boolean isApplicationInForeground() { |
|
|
|
|
|
android.app.ActivityManager activityManager = (android.app.ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); |
|
|
|
|
|
List<android.app.ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses(); |
|
|
|
|
|
if (appProcesses == null) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
String packageName = getPackageName(); |
|
|
|
|
|
for (android.app.ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { |
|
|
|
|
|
if (appProcess.importance == android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND |
|
|
|
|
|
&& appProcess.processName.equals(packageName)) { |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 低内存时的处理 |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public void onLowMemory() { |
|
|
|
|
|
super.onLowMemory(); |
|
|
|
|
|
LogManager.logInfo(TAG, "系统内存不足,触发onLowMemory"); |
|
|
|
|
|
|
|
|
|
|
|
// 清理不必要的缓存 |
|
|
|
|
|
clearMemoryCache(); |
|
|
|
|
|
|
|
|
|
|
|
// 强制GC |
|
|
|
|
|
System.gc(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 清理内存缓存 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void clearMemoryCache() { |
|
|
|
|
|
// 如果当前不在人脸检测状态,释放当前的LivenessModel |
|
|
|
|
|
if (currentLivenessModel != null && !isNeedCamera) { |
|
|
|
|
|
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance(); |
|
|
|
|
|
if (image != null) { |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
} |
|
|
|
|
|
currentLivenessModel = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果设备内存不足,考虑调整处理频率 |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = Math.min(30, PROCESS_FRAME_INTERVAL + 5); |
|
|
|
|
|
MIN_PROCESS_INTERVAL = Math.min(3000, MIN_PROCESS_INTERVAL + 500); |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "内存不足,调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 优化内存的周期性任务 |
|
|
|
|
|
*/ |
|
|
|
|
|
private void startMemoryOptimizationTask() { |
|
|
|
|
|
new Handler().postDelayed(new Runnable() { |
|
|
|
|
|
@Override |
|
|
|
|
|
public void run() { |
|
|
|
|
|
// 获取当前应用内存使用情况 |
|
|
|
|
|
Runtime runtime = Runtime.getRuntime(); |
|
|
|
|
|
long usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024); |
|
|
|
|
|
long totalMemory = runtime.maxMemory() / (1024 * 1024); |
|
|
|
|
|
float memoryUsageRatio = (float) usedMemory / totalMemory; |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "内存使用情况:" + usedMemory + "MB/" + totalMemory + |
|
|
|
|
|
"MB,使用率:" + (int)(memoryUsageRatio * 100) + "%"); |
|
|
|
|
|
|
|
|
|
|
|
// 如果内存使用率超过70%,主动清理内存 |
|
|
|
|
|
if (memoryUsageRatio > 0.7f) { |
|
|
|
|
|
LogManager.logInfo(TAG, "内存使用率超过70%,主动清理内存"); |
|
|
|
|
|
clearMemoryCache(); |
|
|
|
|
|
System.gc(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果内存使用率超过85%,进行更积极的清理 |
|
|
|
|
|
if (memoryUsageRatio > 0.85f) { |
|
|
|
|
|
LogManager.logWarning(TAG, "内存使用率超过85%,进行积极清理"); |
|
|
|
|
|
// 进一步降低处理频率 |
|
|
|
|
|
PROCESS_FRAME_INTERVAL = Math.min(50, PROCESS_FRAME_INTERVAL + 10); |
|
|
|
|
|
MIN_PROCESS_INTERVAL = Math.min(5000, MIN_PROCESS_INTERVAL + 1000); |
|
|
|
|
|
|
|
|
|
|
|
// 清理更多资源 |
|
|
|
|
|
if (currentLivenessModel != null) { |
|
|
|
|
|
BDFaceImageInstance image = currentLivenessModel.getBdFaceImageInstance(); |
|
|
|
|
|
if (image != null) { |
|
|
|
|
|
image.destory(); |
|
|
|
|
|
} |
|
|
|
|
|
currentLivenessModel = null; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LogManager.logInfo(TAG, "积极清理后调整处理频率:每" + PROCESS_FRAME_INTERVAL + "帧,最小间隔" + MIN_PROCESS_INTERVAL + "ms"); |
|
|
|
|
|
System.gc(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 每30秒执行一次 |
|
|
|
|
|
if (!isFinishing()) { |
|
|
|
|
|
new Handler().postDelayed(this, 30000); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}, 30000); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |