Skip to content

基于虹软人脸识别SDK V3.1,封装人脸识别方法

License

Notifications You must be signed in to change notification settings

shenbengit/ArcFace

Repository files navigation

ArcFace

基于虹软人脸识别增值版Android SDK V3.1,封装人脸识别方法。

增值版Android SDK V3.1文档
虹软人脸识别4.0封装

效果展示

限制识别区域

ArcFace

不限制识别区域

ArcFace

将JitPack存储库添加到您的项目中(项目根目录下build.gradle文件)

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

添加依赖

android {
    ...
    defaultConfig {
        ...
        ndk {
            // 设置支持的SO库架构,仅支持armeabi-v7a、arm64-v8a,若想减小APK体积,可只引用对应的SO库架构
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
    }
}

dependencies {
    implementation 'com.github.shenbengit:ArcFace:Tag'
}

项目内依赖Fotoapparat用于摄像头预览。

使用事例

布局示例

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.shencoder.arcface.view.FaceCameraView
        android:id="@+id/faceCameraView"
        android:layout_width="match_parent"
        android:layout_height="450dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

代码示例

基本使用

    val faceCameraView: FaceCameraView = findViewById(R.id.faceCameraView)
    val configuration = FaceConfiguration.builder(this, object : OnRecognizeCallback {
        /**
         * 检测到的人脸数量
         * <p>运行在子线程</p>
         *
         * @param num 人脸数量
         * @param faceIds faceId
         */
        override fun detectFaceNum(num: Int, faceIds: List<Int>) {

        }

        /**
         * 有人,仅在有变化时调用一次
         * <p>运行在子线程</p>
         */
        override fun someone() {

        }

        /**
         * 无人,仅在有变化时调用一次
         * <p>运行在子线程</p>
         */
        override fun nobody() {

        }

        /**
         * 如果不想自动比对的话,可以通过此接口返回识别到的人脸特征码,仅在[FaceConfiguration.enableCompareFace] 为false时才会回调
         * <p>运行在子线程</p>
         *
         * @param faceId 人脸Id
         * @param feature 人脸特征码
         * @param recognizeInfo 识别到的其他信息,包含活体值、年龄、性别、人脸角度等信息
         * @param camera 预览数据
         * @param width 预览数据宽度
         * @param height 预览数据高度
         */
         override fun onGetFaceFeature(
             faceId: Int,
             feature: ByteArray,
             recognizeInfo: RecognizeInfo,
             nv21: ByteArray,
             width: Int,
             height: Int
         ) {
             
         }

        /**
         * 识别成功后结果回调,仅回调一次,直到人脸离开画面
         * <p>运行在子线程</p>
         *
         * @param bean 识别的数据 [faceFeatureList] 的子项
         * @param similar 识别通过的相似度
         * @param recognizeInfo 识别到的其他信息,包含活体值、年龄、性别、人脸角度等信息
         * @param camera 预览数据
         * @param width 预览数据宽度
         * @param height 预览数据高度
         * 
         * @return 人脸绘制框上成功时绘制的文字
         */
        override fun onRecognized(
            bean: FaceFeatureDataBean,
            similar: Float,
            recognizeInfo: RecognizeInfo,
            nv21: ByteArray,
            width: Int,
            height: Int
        ): String? {
            println("人脸比对成功-相似度:" + similar + ",recognizeInfo:" + recognizeInfo.toString())
            return "识别成功"
        }

        /**
         * 识别相似度阈值,有效值范围(0.0f,1.0f)
         */
        override fun similarThreshold(): Float {
            return 0.8f
        }

        /**
         * 待比较人脸数据集合,需要自己封装传入
         */
        override fun faceFeatureList(): List<FaceFeatureDataBean> {
            return listOf()
        }

    })
        .setDetectFaceOrient(DetectFaceOrient.ASF_OP_0_ONLY)//人脸检测角度
        .enableRecognize(true)//是否需要识别
        .setDetectFaceScaleVal(30)//用于数值化表示的最小人脸尺寸,该尺寸代表人脸尺寸相对于图片长边的占比。
        .setLivenessType(LivenessType.IR)//活体检测类型
        .setRgbLivenessThreshold(0.6f)//设置RGB可见光活体阈值
        .setIrLivenessThreshold(0.7f)//设置IR红外活体阈值
        .enableImageQuality(true)//是否启用图像质量阈值
        .setImageQualityThreshold(0.35f)//图像质量阈值
        .setDetectFaceMaxNum(1)//最大需要检测的人脸个数
        .recognizeKeepMaxFace(true)//是否仅识别最大人脸
        .enableRecognizeAreaLimited(false)//是否限制识别区域
        .setRecognizeAreaLimitedRatio(0.7f)//识别区域屏占比,正方形,位置在预览画面正中间
        .setDetectInfo(
            DetectInfo(
                age = true,
                gender = true,
                angle = true
            )
         )//相关属性检测,年龄、性别、3d角度这个功能依附于 [livenessType],需要为[LivenessType.RGB]
         .setRgbCameraFcing(CameraFacing.BACK)//彩色RGB摄像头类型
         .setIrCameraFcing(CameraFacing.FRONT)//红外IR摄像头类型,目前不支持
         .setPreviewSize(PreviewSize(1280, 720))//摄像头预览分辨率,彩色摄像头和红外都支持的预览分辨率
         .setDrawFaceRect(
             DrawFaceRect(
                 isDraw = true,
                 unknownColor = Color.YELLOW,
                 failedColor = Color.RED,
                 successColor = Color.GREEN,
                 rgbOffsetX = 0,
                 rgbOffsetY = 0,
                 irOffsetX = -15,
                 irOffsetY = 0,
              )
         )//人脸识别框绘制相关
         .isRgbMirror(true)//RGB预览画面是否镜像
         .isIrMirror(false)//IR预览画面是否镜像
         .setExtractFeatureErrorRetryCount(3)//人脸特征提取出错重试次数,超过置为失败状态
         .setRecognizeFailedRetryInterval(1000)//人脸识别失败后,重试间隔,单位:毫秒
         .setLivenessErrorRetryCount(3)//体检测出错重试次数
         .setLivenessFailedRetryInterval(1000)//活体检测失败后,重试间隔,单位:毫秒
         .enableCompareFace(true)//是否启用人脸比对
         .setViewfinderText("请将人脸置于识别框内")
         .setViewfinderGravity(ViewfinderView.TextLocation.BOTTOM)
         .setOnErrorCallback(object : OnErrorCallback {
             override fun onError(type: FaceErrorType, errorCode: Int, errorMessage: String) {
                
             }
         })//识别中错误回调
         .build()
    //设置人脸相关参数,如果确认人脸已经激活且直接进行人脸识别则设备true
    faceCameraView.setConfiguration(configuration, false)
    faceCameraView.setLifecycleOwner(this)
    //摄像头开启异常监听
    faceCameraView.setOnCameraListener(object : OnCameraListener {
            override fun onRgbCameraError(exception: Exception) {

            }

            override fun onIrCameraError(exception: Exception) {
                
            }
     })
    //在合适的地方调用此方法,设置为true且人脸已激活才会提交预览数据
    faceCameraView.enableFace(true)

虹软人脸激活相关 FaceActive

  • 在线激活
FaceActive.activeOnline(context: Context, activeKey: String, appId: String, sdkKey: String, callback: OnActiveCallback?)
  • 离线激活
FaceActive.activeOffline(context: Context, filePath: String,callback: OnActiveCallback?)
  • 是否已经激活人脸
FaceActive.isActivated(context: Context): Boolean
  • 生成设备指纹信息,用于离线激活(请自行获取内存卡读写权限)
FaceActive.generateActiveDeviceInfo(context: Context, saveFilePath: String, callback: OnActiveDeviceInfoCallback?)

人脸比对和生成特征码相关 FaceServer (可以自行封装成单例模式)

  • 初始化
/**
  * 初始化人脸引擎
  * @param context 上下文
  * @param faceOrient 人脸检测角度,单一角度检测,不支持[DetectFaceOrient.ASF_OP_ALL_OUT]
  * [DetectFaceOrient.ASF_OP_0_ONLY]
  * [DetectFaceOrient.ASF_OP_90_ONLY]
  * [DetectFaceOrient.ASF_OP_180_ONLY]
  * [DetectFaceOrient.ASF_OP_270_ONLY]
  * @param detectFaceScaleVal 识别的最小人脸比例,取值范围[2,32]
  */
fun init(context: Context, faceOrient: DetectFaceOrient = DetectFaceOrient.ASF_OP_0_ONLY, @IntRange(from = 2, to = 32) detectFaceScaleVal: Int = 16) 
  • 比对人脸 1:N
/**
  * 比对人脸 1:N
  * @param faceFeature 要比对的人脸特征码
  * @param features 待比对的人脸列表
  * 
  * @return null:说明比对列表为空或者人脸引擎出错;返回相似度最大的[features]中的数据
  */
fun compareFaceFeature(faceFeature: FaceFeature, features: List<FaceFeatureDataBean>): CompareResult?
  • 比对人脸 1:1
/**
  * 比对两组特征码 1:1
  * 
  * @return 返回相似度
  */
fun compareFaceFeature(feature1: ByteArray, feature2: ByteArray): Float
  • 通过Bitmap提取特征码
/**
  * 通过Bitmap提取特征码
  * 最好在子线程运行
  * 
  * @return 特征码
  */
fun extractFaceFeature(bitmap: Bitmap?): ByteArray?
  • 通过nv21数据提取特征码
/**
  * 摄像机预览数据提取人脸特征码
  * 最好在子线程运行
  * @param nv21 摄像机数据
  * @param width 预览宽度
  * @param height 预览高度
  * 
  * @return 特征码
  */
fun extractFaceFeature(nv21: ByteArray, width: Int, height: Int): ByteArray?
  • 销毁资源
/**
  * 销毁资源
  */
fun destroy()

人脸检测 FaceDetect (可以自行封装成单例模式)

  • 初始化
/**
  * 初始化人脸引擎
  * @param context 上下文
  * @param enableImageQuality 启用图片质量检测
  * @param detectFaceMaxNum 检测人脸数量
  * @param detectFaceScaleVal 识别的最小人脸比例,取值范围[2,32]
  * @param detectFaceOrient 人脸检测角度
  * [DetectFaceOrient.ASF_OP_0_ONLY]
  * [DetectFaceOrient.ASF_OP_90_ONLY]
  * [DetectFaceOrient.ASF_OP_180_ONLY]
  * [DetectFaceOrient.ASF_OP_270_ONLY]
  * [DetectFaceOrient.ASF_OP_ALL_OUT]
  */
fun init(
    context: Context,
    enableImageQuality: Boolean = false,
    detectFaceMaxNum: Int,
    detectFaceScaleVal: Int = 16,
    detectFaceOrient: DetectFaceOrient = DetectFaceOrient.ASF_OP_0_ONLY
)
  • 人脸检测回调
/**
  * 人脸检测回调
  */
fun setFaceDetectCallback(callback: FaceDetectCallback?)
  • 销毁资源
* 传入预览数据
/**
  * 传入预览数据
  */
fun onPreviewFrame(rgbNV21: ByteArray,previewWidth: Int,previewHeight: Int)
  • 销毁资源
/**
  * 销毁资源
  */
fun destroy()

人脸特征码转换工具 FeatureCovertUtil

  • ByteArray特征码数据转为16进制字符串
FeatureCovertUtil.byteArrayToHexString(feature: ByteArray): String
  • 16进制字符串转为ByteArray特征码数据
FeatureCovertUtil.hexStringToByteArray(hexStr: String): ByteArray