人脸识别

    虚拟人SDK-Android

    1 简介

    本文档主要介绍 虚拟人SDK-Android 的集成和使用。在使用本文档前,需要了解授权逻辑,您可以通过“合作咨询”联系我们申请应用授权。

    2 快速入门

    支持的系统和硬件版本

    • 系统:支持 Android 5.0+(API Level 21)到 Android 9(API Level 28)系统。需要开发者通过minSdkVersion来保证支持系统的检测。
    • CPU架构:armeabi-v7a。
    • 硬件要求:要求设备上有相机模块,CPU 4核及以上,内存2G及以上。
    • 网络:支持WIFI及移动网络,移动网络支持使用NET网关及WAP网关(CMWAP、CTWAP、UNIWAP、3GWAP)。

    开发包说明

    虚拟人SDK.zip
        |- face-virtual                 // demo工程
        |- face_virtual                 // 模型资源文件,push到SD卡中
        |- module_virtual-release.aar   // 包含jar包,so库及依赖

    SDK提供的demo工程以Android Studio方式提供。

    3 SDK集成步骤

    3.1 模型和资源导入

    路径位置不限制,保证不被删除即可,需要在创建new Model() 对象时候,指定对应位置即可

    adb push face_virtual/ /sdcard/

    3.2 SDK接入工程

    3.2.1 配置调入aar,参考face-virtual-demo的build.gradle文件

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 28
        buildToolsVersion "29.0.2"
    }
    
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation(name:'module_virtual-release', ext:'aar')
    }

    3.2.2 配置增加权限和组件,参考face-virtual-demo的AndroidManifest文件

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.GET_TASKS" />
        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
        <dist:module dist:instant="true" />
    
    
            <!--安全设备指纹接入 start-->
            <activity
                android:name="com.baidu.liantian.LiantianActivity"
                android:excludeFromRecents="true"
                android:exported="true"
                android:launchMode="standard"
                android:theme="@android:style/Theme.Translucent">
                <intent-filter><action android:name="com.baidu.action.Liantian.VIEW" />
    
                    <category android:name="com.baidu.category.liantian" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </activity>
            <receiver
                android:name="com.baidu.liantian.LiantianReceiver"
                android:exported="false">
                <intent-filter><action android:name="com.baidu.action.Liantian.VIEW" />
    
                    <category android:name="com.baidu.category.liantian" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
                <intent-filter android:priority="2147483647">
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                </intent-filter>
            </receiver>
            <provider
                android:name="com.baidu.liantian.LiantianProvider"
                android:authorities="应用包名+.liantian.ac.provider"
                android:exported="true" />
            <service
                android:name="com.baidu.liantian.LiantianService"
                android:exported="false">
                <intent-filter><action android:name="com.baidu.action.Liantian.VIEW" />
    
                    <category android:name="com.baidu.category.liantian" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </service>
    
            <meta-data
                android:name="seckey_avscan"
                android:value="660346260f8a841a04ec2a56815b421b" />
            <meta-data
                android:name="appkey_avscan"
                android:value="100034" />
    
            <!--安全设备指纹接入 end-->

    3.3 接口调用

    3.3.1 权限获取,参考face-virtual-demo的BaseActivity文件

    SDK 需要申请READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE、RECORD_AUDIO 权限

    3.3.2 设备ID获取,参考face-virtual-demo的MainActivity文件SetupTask 实例

    SDK 设备授权,申请需要先获取设备ID,VKAuth getDeviceId 获取String 设备ID String 字符串,提交Baidu 工作人员

    Log.v(TAG, vkAuth.getDeviceId(this.activityReference.get()));     

    3.3.3 激活授权,参考face-virtual-demo的MainActivity文件SetupTask 实例

    百度工作人员会提供新授权文件和KEY 关键密钥; 新授权文件替换face-virtual-demo asset 下的xuniren.license 文件 新的KEY替换MainActivity TEST_KEY 字段内容

    private static final String TEST_KEY = "xuniren-vivo-874ba8af";
    private static final String TEST_LICENSE_NAME = "xuniren.license_vivo-874ba8af";

    3.3.4 初始化SDK,查考face-virtual-demo的MainActivity文件SetupTask 实例

    @Override
    public void init() {
        new SetupTask(this).execute();
    }
    
            private static class SetupTask extends AsyncTask<Void, Void, Exception> {
            WeakReference<MainActivity> activityReference;
            VKAuth vkAuth;
    
            SetupTask(MainActivity activity) {
                this.activityReference = new WeakReference<>(activity);
                vkAuth = new VKAuth();
                vkAuth.setActiveLog(3, 1);
            }
    
            @Override
            protected Exception doInBackground(Void... params) {
    
                vkAuth.initLicenseBatchLine(this.activityReference.get(), TEST_KEY);
                if (vkAuth.getAuthStatus() != AndroidLicenser.ErrorCode.SUCCESS) {
                    Log.v(TAG, vkAuth.getAuthStatus()
                            + " " + vkAuth.authGetLocalInfo(this.activityReference.get()).toString());
    
                    Log.v(TAG, vkAuth.getDeviceId(this.activityReference.get()));
                    return new Exception("授权错误");
                }
    
                VirtualConfig config = new VirtualConfig();
                config.setVisualize(5);
                config.setThread(4);
                config.setModelPath("/sdcard/face_virtual_all/data");
                activityReference.get().model = new Model(config);
                activityReference.get().recognizer = new VKVirtualRecognizer(activityReference.get().model, 16000.f);
                activityReference.get().recognizer.setListener(activityReference.get());
    
                return null;
            }
    
            @Override
            protected void onPostExecute(Exception result) {
                if (result != null) {
                    activityReference.get().setErrorState(
                            String.format(activityReference.get().getString(R.string.failed), result));
                    Toast.makeText(this.activityReference.get(), String.format(activityReference.get()
                            .getString(R.string.failed), result), Toast.LENGTH_SHORT).show();
                } else {
                    activityReference.get().setUiState(STATE_READY);
                }
            }
        }

    3.3.5 语言文件识别,参考face-virtual-demo的MainActivity文件RecognizeTask实例

    findViewById(R.id.recognize_file).setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
            recognizeFile();
         }
    });
    
     public void recognizeFile() {
            setUiState(STATE_FILE);
            isActivateGuard = false;
        }

    3.3.6 空闲状态动作,参考face-virtual-demo的MainActivity GuardThread 任务

      private GuardThread guardThread;
        private static boolean isActivateGuard = true;
    
        @Override
        public void init() {
            new SetupTask(this).execute();
            guardThread = new GuardThread(this);
            guardThread.start();
        }
    
        class GuardThread extends Thread {
            WeakReference<MainActivity> activityReference;
    
            public GuardThread(MainActivity activity) {
                this.activityReference = new WeakReference<>(activity);
            }
    
            public void run() {
                while (!interrupted()) {
                    if (this.activityReference.get().recognizer != null)
                        if (isActivateGuard) {
                            int[][] actionArr = {{0, 4}};
                            this.activityReference.get().recognizer.runSilent(actionArr);
                        } else {
                            isActivateGuard = true;
                            // 关闭守护任务
                            // 新的语音输入需要重置之前状态
                            this.activityReference.get().recognizer.resetWaveAction();
    
                            // 静默接口runSilent,支持多个动作输入,第15帧1号动作;第60帧3号动作;第120帧4号动作.....
                            int[][] actionArr1 = {{1, 1}, {2, 75}};
                            // , {3, 150}, {4, 227}, {5, 300}, {6, 375}, {7, 475}, {8, 575},
                            //        {9, 675}, {10, 775}, {11, 875}, {12, 975}, {13, 1075}, {14, 1175}};
                            this.activityReference.get().recognizer.runSilent(actionArr1);
    
                            // 新的语音可以是wav或者pcm,wav需要输入头字节,pcm 头字节输入0
                            this.activityReference.get().recognizer.acceptWaveform("/sdcard/face_virtual_all/input/1_16.wav", 44 + 34);
                            // 动作设置,1表示一号动作,130表示TTS的第130字时候会触发动作,标点符合不计入
                            this.activityReference.get().recognizer.setWaveAction(1, 10);
                            this.activityReference.get().recognizer.run();
    
                            this.activityReference.get().recognizer.resetWaveAction();
                            // 静默接口runSilent,支持多个动作输入,第15帧1号动作;第60帧3号动作;第120帧4号动作.....
                            int[][] actionArr = {{1, 1}, {2, 75}};
                            // , {3, 150}, {4, 227}, {5, 300}, {6, 375}, {7, 475}, {8, 575},
                            //        {9, 675}, {10, 775}, {11, 875}, {12, 975}, {13, 1075}, {14, 1175}};
                            this.activityReference.get().recognizer.runSilent(actionArr);
                        }
                }
            }
        }

    3.3.7 语言播放,参考face-virtual-demo的MainActivity文件RecognizeTask实例

             @Override
        public void onVirtualPlayStart() {
            Toast.makeText(MainActivity.this, "播报开始", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onVirtualPlayFinish() {
            Toast.makeText(MainActivity.this, "播报完成", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onPartialSize(int size) {
            playView.setPartialSize(size);
        }
    
        @Override
        public void onPartialResult(VKVirtualData videoSlice) {
            playView.setPartialResult(videoSlice);
        }
    
        @Override
        public void onPartialFinish() {
    
        }
    
        @Override
        public void onPartialError(Exception var1) {
    
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            playView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            playView.onPause();
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            playView.onStop();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            model.delete();
        }

    4 API及回调接口、消息的详细说明

    4.1 VKAuth 鉴权类

    4.1.1 构造方法

    说明:loadLibrary 动态库

    public VKAuth()

    示例代码

    vkAuth = new VKAuth();

    4.1.2 initLicense

    说明:单次设备授权,设置licenseKey与licenseName(授权文件官网下载,存放asset目录下)

    public AndroidLicenser.ErrorCode initLicense(Context context, String licenseKey,String licenseName, boolean isRemote)
    参数名 含义
    context 上下文
    licenseKey 官网申请key
    licenseName 官网申请授权文件
    isRemote 是否启动过期自动更新,默认false

    示例代码

    vkAuth.initLicense(this.activityReference.get(), TEST_KEY, TEST_LICENSE_NAME, false);

    4.1.3 initLicenseBatchLine

    说明:批量设备授权,设置licenseKey,避免每个设备都安装一次

     public AndroidLicenser.ErrorCode initLicenseBatchLine(Context context, String licenseKey) 
    参数名 含义
    context 上下文
    licenseKey 官网申请key

    示例代码

    vkAuth.initLicenseBatchLine(this.activityReference.get(), TEST_KEY);

    4.2 VirtualConfig 配置类

    4.2.1 setModelPath

    设置配置加载路径

    public void setModelPath(String modelPath)
    参数名 含义
    modelPath 路径地址

    示例代码

    config.setModelPath("/sdcard/face_virtual/data");

    4.2.2 setVisualize

    设置形象类型

    public void setVisualize(int visualize) 
    参数名 含义
    visualize 虚拟人形象类型: 1 默认女生全屏;2 默认女生半屏;3 女生半屏;4 男生半屏

    示例代码

     config.setVisualize(0);

    4.2.3 setThread

    设置预测线程个数

    public void setThread(int thread)
    参数名 含义
    thread 线程个数,一般设置为cpu 核数1/2

    示例代码

    config.setThread(3);

    4.3 Model 模型

    4.3.1 构造方法

    说明:加载指定路径下的模型,配置文件

    public Model(VirtualConfig config)
    参数名 含义
    model_path 路径地址

    示例代码

    VirtualConfig config = new VirtualConfig();
    config.setVisualize(0);
    config.setModelPath("/sdcard/face_virtual/data");
    activityReference.get().model = new Model(config);

    4.3.2 delete方法

    说明:卸载模型对象,释放内存

    public synchronized void delete()  
    参数名 含义
    void void

    示例代码

    @Override
    protected void onDestroy() {
        super.onDestroy();
        model.delete();
     }

    4.4 VKVirtualRecognizer 语音识别类

    4.4.1 构造方法

    说明:构造方法,传递model和语言频率

    public VKVirtualRecognizer(Model model, float sampleFrequency)
    参数名 含义
    model 模型对象
    sampleFrequency 采样率默认16000

    示例代码

    rec = new VKVirtualRecognizer(activityReference.get().model, 16000.f);

    4.4.2 setListener

    设置语音识别监听方法

    public void setListener(VKVirtualRecognitionListener listener)
    参数名 含义
    listener onPartialSize(int size);语音分片个数
    onPartialResult(VKVirtualData videoSlice); 语音分片结果

    示例代码

    rec.setListener(activityReference.get());

    4.4.3 resetWaveAction

    说明:动作状态重置接口,每次新语音输入前调用 示例代码

    // 新的语音输入需要重置之前状态
    rec.resetWaveAction();

    4.4.4 acceptWaveform

    说明:语音文件输入接口,新的语音可以是wav或者pcm,wav需要输入头字节,pcm 头字节输入0

    public int acceptWaveform(String dataPath, int headSize) 
    参数名 含义
    dataPath 文件绝对路径
    headSize 头字节大小

    示例代码

    // 新的语音可以是wav或者pcm,wav需要输入头字节,pcm 头字节输入0
    rec.acceptWaveform("/sdcard/face_virtual/input/cixuanfu-16.wav", 44 + 34);

    4.4.5 acceptWaveform

    说明:语音数据流输入方法

    public int acceptWaveform(byte[] data, int len)
    参数名 含义
    data 字节数据流
    len 字节数据长度

    示例代码

    VKVirtualSpeechRecognizer.this.recognizer.acceptWaveform(buffer, nread);

    4.4.6 setWaveAction

    说明:设置动作类型和触发时机

    public int setWaveAction(int actionType, int actionStart)
    参数名 含义
    actionType 1,8个动作的类型,0表示无动作,1~8表示8种不同动作:

    1)左摊手、2)右摊手、3)手正常抬起左右摇摆(见面打招呼/离开再见)、 4)手托下颌思考、5)正常抬起比OK、 6)左手向内弯曲抬起到腹部、7)右手向内弯曲抬起到腹部、 8)双手向内弯曲抬起到腹部

    2,14个动作的类型,0表示无动作,1~14表示14种不同动作:

    1) 倾听动作、2) 眨眨眼、3) 点头、4) 表述状态-单手、5) 表述状态-双手、6) 微笑、7) 张嘴笑、8) 失落、9) 惊讶、10) 打招呼-挥手、11) 自我介绍、12) OKAY、13) 摇头、14) 思考

    actionStart 动作设置,1表示一号动作,130表示TTS的第130字时候会触发动作,标点符合不计入

    示例代码

    // 动作设置,1表示一号动作,130表示TTS的第130字时候会触发动作,标点符合不计入
    rec.setWaveAction(1, 130);

    4.4.7 run

    说明:语言识别运行接口,调用run 之后,会在setListener 设置的监听方法onPartialSize 和 onPartialResult 分别回掉数据 示例代码

    rec.run();

    4.4.8 runSilent

    说明:静默接口输入,支持多个动作输入,第15帧1号动作;第60帧3号动作;第120帧4号动作.....

    public void runSilent(int[][] actionArr)
    参数名 含义
    actionArr 具体的动作序列:(具体动作, 触发帧位置)

    示例代码

    // 静默接口runSilent,支持多个动作输入,第15帧1号动作;第60帧3号动作;第120帧4号动作.....
    int[][] actionArr = {{1, 15}, {3, 60}, {4, 120}, {4, 300}, {4, 450}};
    rec.runSilent(actionArr);

    4.5 VKVirtualPlayView 虚拟视频播放类

    4.5.1 setBackground

    说明:设置播放器背景图

    public void setBackground(Bitmap bitmap)
    参数名 含义
    bitmap 图像句柄

    示例代码

    playView.setBackground(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_default));

    4.5.2 setBackground

    说明:设置播放器背景图

    public void setBackground(Bitmap bitmap)
    参数名 含义
    bitmap 图像句柄

    示例代码

    playView.setBackground(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_default));

    4.5.3 onStart接口

    说明:启动接口,初始化音频播放,视频播放,通过listener 监听语言播放状态回掉

    public void onStart(VKVirtualPlayListener listener)
    参数名 含义
    listener onVirtualPlayStart 语言播放启动
    onVirtualPlayFinish 语言播放结束

    示例代码

    playView.onStart(this);

    4.5.4 setPartialSize

    说明:设置语言切片个数,通过 onPartialSize 方法获取切片个数,设置

    public void setPartialSize(int partialSize)
    参数名 含义
    partialSize 切片个数

    示例代码

    @Override
    public void onPartialSize(int size) {
        playView.setPartialSize(size);
    }

    4.5.5 setPartialResult

    说明:虚拟语言图像设置方法,通过onPartialResult方法获取每次切片的视频信息

    public void setPartialResult(VKVirtualData data)
    参数名 含义
    data 虚拟语音,图像数据结构体

    示例代码

    @Override
    public void onPartialResult(VKVirtualData videoSlice) {
        playView.setPartialResult(videoSlice);
    }

    4.5.6 onResume接口

    说明:虚拟视频重新开始接口,图像重新开始,语音重新播放

    public void onResume()

    示例代码

    @Override
    protected void onResume() {
        super.onResume();
        playView.onResume();
    }

    4.5.7 onPause接口

    说明:虚拟视频暂停接口,图像暂停播放,语音暂停播放

    public void onPause()

    示例代码

    @Override
    protected void onPause() {
        super.onPause();
        playView.onPause();
    }

    4.5.8 onStop接口

    说明:虚拟视频暂停接口,图像暂停播放,语音暂停播放

    public void onStop()

    示例代码

    @Override
    protected void onStop() {
       super.onStop();
       playView.onStop();
    }
    上一篇
    产品简介
    下一篇
    私有化部署