背景介绍:
最近在做人脸识别的项目,我选择接入的是虹软的Arcface SDK,有个需求是比如在RGB摄像头和IR摄像头同时开启时候,如何保证两个摄像头活体检测到的是同一个人脸。
在保证RGB摄像头和IR摄像头分辨率、成像方向、焦距等一致后,接下来就是如何实现在应用层用代码判断了。
判断检测到是否是同一人脸其实有两种方案:
1.一旦人脸框相交,即判断为同一人脸,但此方案误差太大故不考虑;
2.去计算两个人脸框重叠的面积,根据设置的阈值精准判断是否为同一人脸。 本文选择第二种方案,流程图参考下图:
详细步骤:
-
在IR进行活体检测前,先通过detectFaces检测人脸信息,获取人脸框。由于rgbFaceInfo里面只有一张人脸,所以只需要通过keepMaxFace方法保留IR最大人脸,然后调用isFaceSame方法去判断RGB和IR检测到的是否是同一个人脸。
// 检测人脸信息 FaceInfo rgbFaceInfo = faceInfo; List<FaceInfo> irFaceInfoList = new ArrayList<>(); int fdCode = flEngine.detectFaces(nv21Data, width, height, format, irFaceInfoList); boolean isFaceOverlap = false; if(fdCode == ErrorInfo.MOK && irFaceInfoList .size()>0){ keepMaxFace(irFaceInfoList); isFaceOverlap = isFaceSame(irFaceInfoList.get(0),rgbFaceInfo,0.3); } -
如果是同一个人脸,则调用IR活体检测接口processIr
if (fdCode == ErrorInfo.MOK && isFaceOverlap) { flCode = flEngine.processIr(nv21Data, width, height, format, irFaceInfoList, FaceEngine.ASF_IR_LIVENESS); } else { // 错误处理 } -
getOverlapArea方法判断两个矩形框是否有重叠,如果没有重叠区域,则返回空的矩形。
public Rect getOverlapArea (Rect rect1, Rect rect2) { int left = Math.max(rect1.left, rect2.left); int right = Math.min(rect1.right, rect2.right); int top = Math.max(rect1.top, rect2.top); int bottom = Math.min(rect1.bottom, rect2.bottom); // 如果没有重叠区域,则返回空的矩形 if (left < right && top < bottom) { return new Rect(left, top, right, bottom); } return null; // 无重叠 } -
isFaceSame方法需要具体实现:计算两个矩形的重叠面积,以判断它们的重叠程度。第三个参数是阈值,这样可以通过调整阈值更精确地确定是否是同一个人脸。
// 可能并不需要两个面部框完全重叠,只需要有一定比例的重叠即可判定是同一张脸。 // 因此可以设置一个重叠阈值,当两个矩形的重叠面积超过某个阈值时,认为是同一张脸。 public boolean isFaceSame(FaceInfo rgbFaceInfo, FaceInfo irFaceInfo, double threshold) { Rect rect1 = rgbFaceInfo.getRect(); Rect rect2 = irFaceInfo.getRect(); Rect overlapRect = getOverlapArea(rect1, rect2); if (overlapRect != null) { int overlapArea = overlapRect.width() * overlapRect.height(); int face1Area = rect1.width() * rect1.height(); int face2Area = rect2.width() * rect2.height(); // 计算重叠面积占两个矩形面积的比例 double overlapRatio = (double) overlapArea / Math.min(face1Area, face2Area); Log.d(TAG, "overlapRatio:" + overlapRatio + "," + threshold); return overlapRatio > threshold; } return false; } -
当活体检测通过后,就可以获取RGB和IR的活体检测信息了
if (flCode == ErrorInfo.MOK) { if (livenessType == LivenessType.RGB) { flCode = flEngine.getLiveness(livenessInfoList); } else { flCode = flEngine.getIrLiveness(livenessInfoList); } }
Tips:
以上代码可以参考虹软 arcface demo中的FaceHelper.java文件,路径:app/src/main/java/com/arcsoft/arcfacedemo/util/face/FaceHelper.java