Android初学----自己封装集成讯飞语音和人脸识别

人脸识别 -- 活体检测(张嘴摇头识别) 最近项目在做了身份证银行卡识别之后,开始实现人脸识别和活体识别,其中人脸识别包括人脸入库、人脸查找、人脸1:N对比、人脸N:N对比,另外活体识别运用在安全登录功能。大家都熟知的支付宝使用face++ 的服务来实现人脸识别,在实际项目中使用了讯飞的人脸识别SDK进行二次封装来实现活体识别。主要实现了张嘴和摇头两个活体动作的识别。据我所知,讯飞的服务是基于face++,识别率还是很高,并且iOS和Android都对应有封装好的SDK。 阅读详情

讯飞语音,对于程序员来说,听到这个名字并不陌生,很多APP项目都集成了它的SDK,最近公司的项目需要语音识别、合成及人脸识别的功能。由此将所学所用做一下笔记。

集成环境:集成讯飞语音相对来说比较简单,按着官方给的集成文档(http://doc.xfyun.cn/msc_android/299548)一步一步操作就行,导入下载好的jar包和jniLibs文件夹的.so包即可。

项目中记得添加权限和初始化SpeechUtility

在工程 AndroidManifest.xml 文件中添加如下权限

<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--读取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--获取当前wifi状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--读取手机信息权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取联系人权限,上传联系人需要用到此权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务-->
<!--定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!--如需使用人脸识别,还要添加:摄相头权限,拍照需要用到 -->
<uses-permission android:name="android.permission.CAMERA" />
封装语音识别与合成,代码如下:
package com.face.speech;

import android.content.Context;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.SynthesizerListener;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by AA on 2018/1/2.
 */

public class XunfeiSpeech extends Speech {
    private Context context;
    private String result = "";
    private List<String> jsonResoult;
    // 语音合成对象
    private SpeechSynthesizer mTts;
    // 语音听写对象
    private SpeechRecognizer mIat;
    // 引擎类型 云端
    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    // 默认发音人
    private String voicer = "xiaoqi";
    RecognizerListener listener;
    private boolean isListeningNow = false;
    MediaRecorder mMediaRecorder = null;
    private static XunfeiSpeech speech;
    public static XunfeiSpeech getInstance(Context context,String appId){
        if (speech==null){
            synchronized (XunfeiSpeech.class){
                if (speech==null){
                    speech = new XunfeiSpeech(context,appId);
                }
            }
        }
        return speech;
    }
    /**
     * 讯飞语音对象初始化构造方法
     * @param context 上下文对象
     * @param appId APPID
     */
    private  XunfeiSpeech(Context context,String appId) {
        this.context = context;
        //初始化语音识别
        SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + appId);
        initSpeech(context);
        initSpeechSynthesizer(context);
        jsonResoult = new ArrayList<>();
    }
    /**
     * 初始化语音合成对象
     * @param context
     */
    private void initSpeechSynthesizer(Context context) {
        // 初始化合成对象
        mTts = SpeechSynthesizer.createSynthesizer(context, mTtsInitListener);
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);
        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置在线合成发音人
        mTts.setParameter(SpeechConstant.VOICE_NAME, voicer);
        //设置合成语速
        mTts.setParameter(SpeechConstant.SPEED,  "50");
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, "50");
        //设置合成音量
        mTts.setParameter(SpeechConstant.VOLUME, "50");
    }
    /**
     * 初始化语音识别对象
     * @param context
     */
    void initSpeech(Context context) {
        // 使用SpeechRecognizer对象,可根据回调消息自定义界面;
        mIat = SpeechRecognizer.createRecognizer(context, mInitListener);
        // 清空参数
        mIat.setParameter(SpeechConstant.PARAMS, null);
        // 设置听写引擎
        mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);
        // 设置返回结果格式
        mIat.setParameter(SpeechConstant.RESULT_TYPE, "json");
        // 设置语音前端点:静音超时时间,即用户多长时间不说话则当做超时处理
        mIat.setParameter(SpeechConstant.VAD_BOS, "4000");
        // 设置语音后端点:后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, 自动停止录音
        mIat.setParameter(SpeechConstant.VAD_EOS, "1500");
        // 设置标点符号,设置为"0"返回结果无标点,设置为"1"返回结果有标点
        mIat.setParameter(SpeechConstant.ASR_PTT, "1");
        // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注:AUDIO_FORMAT参数语记需要更新版本才能生效
        mIat.setParameter(SpeechConstant.AUDIO_FORMAT,"wav");
        mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/iat.wav");
    }





    /**
     * 初始化语音合成监听。
     */
    private InitListener mTtsInitListener = new InitListener() {
        @Override
        public void onInit(int code) {
//            Log.d(TAG, "InitListener init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
//                showTip("初始化失败,错误码:"+code);
            } else {
                // 初始化成功,之后可以调用startSpeaking方法
                // 注:有的开发者在onCreate方法中创建完合成对象之后马上就调用startSpeaking进行合成,
                // 正确的做法是将onCreate中的startSpeaking调用移至这里
            }
        }
    };
    /**
     * 初始化语音识别监听器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            Log.d("msg", "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
//                showTip("初始化失败,错误码:" + code);
            }
        }
    };
    /**
     * 开始识别语音
     * @param callback 识别结果回调接口
     */
    @Override
    public void startListening(final ListenResultCallback callback) {
       listener  = new RecognizerListener() {
            @Override
            public void onVolumeChanged(int i, byte[] bytes) {
                callback.onVolumeChanged(i,bytes);
            }

            @Override
            public void onBeginOfSpeech() {

            }

            @Override
            public void onEndOfSpeech() {

            }

            @Override
            public void onResult(RecognizerResult recognizerResult, boolean b) {
//                Log.i("mic",recognizerResult.getResultString());
//解析结果  这里返回的结果是json字符串
                XunfeiResult re = XunfeiResult.getResult(recognizerResult.getResultString());
                if (!re.isLs()){//是否是最后一句话
                    //默认只取第一条结果
                    List<XunfeiResult.WsBean> ws = re.getWs();
                    for (XunfeiResult.WsBean w:
                            ws) {
                        result += w.getCw().get(0).getW();
                    }
                    jsonResoult.add(recognizerResult.getResultString());
                }else {
                    if (!TextUtils.isEmpty(result)){
                        callback.result(result,jsonResoult);
                    }
                    result = "";
                    jsonResoult.clear();
                    //设置开启连续语音识别
                    try {
                        mIat.cancel();
                        Thread.sleep(100);
                        mIat.startListening(this);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onError(SpeechError speechError) {
                callback.error(speechError.getErrorCode()+"");
                if (speechError.getErrorCode()==10118){
                    Log.i("mic","getErrorCode="+speechError.getErrorCode());
                    mIat.cancel();
                    mIat.startListening(this);
                }

            }

            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {

            }
        };
        mIat.startListening(listener);
        if (listenSpeechTimer!=null){
            listenSpeechTimer = new Timer();
            listenSpeechTimer.schedule(listenSpeechTimertask,3000,1000*60*60);
        }
    }

    /**
     * 开始语音合成
     * @param speakContent 合成语音内容
     * @param callback 合成回调接口
     */
    @Override
    public void startSpeaking(String speakContent, final SpeakResultCallback callback) {
        if (TextUtils.isEmpty(speakContent)) return;
        mTts.startSpeaking(speakContent, new SynthesizerListener() {
            /**
             * 开始说话
             */
            @Override
            public void onSpeakBegin() {
                if (mIat!=null){
                    mIat.cancel();
                }
            }
            /**
             * @param i
             * @param i1
             * @param i2
             * @param s
             */
            @Override
            public void onBufferProgress(int i, int i1, int i2, String s) {

            }

            @Override
            public void onSpeakPaused() {

            }

            @Override
            public void onSpeakResumed() {

            }

            @Override
            public void onSpeakProgress(int i, int i1, int i2) {

            }

            /**
             * 语音合成结束
             * @param speechError 错误码
             */
            @Override
            public void onCompleted(SpeechError speechError) {

                if (listener!=null){
//                    mIat.cancel();
//                    mIat.startListening(listener);//重新开启语音识别
                }
                callback.onCompleted(speechError.getErrorCode()+"");
            }

            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {

            }
        });
    }

    /**
     * 关闭语音
     */
    @Override
    public void cancel() {
        if (mTts!=null){
            mTts.destroy();
        }
        if (mIat!=null){
            mIat.cancel();
            mIat.destroy();
        }
        if (listenSpeechTimer!=null){
            listenSpeechTimer.cancel();
            listenSpeechTimer = null;
        }
    }
}

用于解析语音识别的bean类:
package com.face.speech;

import com.google.gson.Gson;

import java.util.List;

/**
 * Created by AA on 2018/1/3.
 */

public class XunfeiResult {
    public static XunfeiResult getResult(String json){
        return new Gson().fromJson(json,XunfeiResult.class);
    }
    /**
     * sn : 1
     * ls : true
     * bg : 0
     * ed : 0
     * ws : [{"bg":0,"cw":[{"w":"今天","sc":0}]},{"bg":0,"cw":[{"w":"的","sc":0}]},{"bg":0,"cw":[{"w":"天气","sc":0}]},{"bg":0,"cw":[{"w":"怎么样","sc":0}]},{"bg":0,"cw":[{"w":"。","sc":0}]}]
     */

    private int sn;
    private boolean ls;
    private int bg;
    private int ed;
    private List<WsBean> ws;

    public int getSn() {
        return sn;
    }

    public void setSn(int sn) {
        this.sn = sn;
    }

    public boolean isLs() {
        return ls;
    }

    public void setLs(boolean ls) {
        this.ls = ls;
    }

    public int getBg() {
        return bg;
    }

    public void setBg(int bg) {
        this.bg = bg;
    }

    public int getEd() {
        return ed;
    }

    public void setEd(int ed) {
        this.ed = ed;
    }

    public List<WsBean> getWs() {
        return ws;
    }

    public void setWs(List<WsBean> ws) {
        this.ws = ws;
    }

    public static class WsBean {
        /**
         * bg : 0
         * cw : [{"w":"今天","sc":0}]
         */

        private int bg;
        private List<CwBean> cw;

        public int getBg() {
            return bg;
        }

        public void setBg(int bg) {
            this.bg = bg;
        }

        public List<CwBean> getCw() {
            return cw;
        }

        public void setCw(List<CwBean> cw) {
            this.cw = cw;
        }

        public static class CwBean {
            /**
             * w : 今天
             * sc : 0
             */

            private String w;
            private int sc;

            public String getW() {
                return w;
            }

            public void setW(String w) {
                this.w = w;
            }

            public int getSc() {
                return sc;
            }

            public void setSc(int sc) {
                this.sc = sc;
            }
        }
    }
}

这里用到的是gson解析,在build.gradle文件中添加
compile 'com.google.code.gson:gson:2.2.4'
即可。

封装人脸识别,包括组操作创建和删除等等,因为要加入人脸搜索功能,只有将识别注册的人脸加入到已创建的组中,才能根据组id对人脸信息进行搜索,代码如下:
package com.face.facerecognition;

import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import com.iflytek.cloud.IdentityListener;
import com.iflytek.cloud.IdentityResult;
import com.iflytek.cloud.IdentityVerifier;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechUtility;

import java.util.List;

/**
 * Created by AA on 2018/1/9.
 */

public class XunfeiFaceRecognition extends FaceRecognition {
    private Context context;
    private String appId;
    private IdentityVerifier verifier;
    private IdentityListener identityListener;
    private int ActionType = -1;//当前执行的操作类型
    private static XunfeiFaceRecognition recognition;

    /**
     * 单例模式
     * @param context
     * @param appId
     * @return
     */
    public static XunfeiFaceRecognition getInstance(Context context, String appId) {
        if (recognition == null) {
            synchronized (XunfeiFaceRecognition.class) {
                if (recognition == null) {
                    recognition = new XunfeiFaceRecognition(context,appId);
                }
            }
        }
        return recognition;
    }

    /**
     * 构造方法(私有化)
     * @param context
     * @param appId
     */
    private XunfeiFaceRecognition(Context context, String appId) {
        this.context = context;
        this.appId = appId;
        init();
    }

    private void init() {
        SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + appId);
        if (verifier == null) {
            verifier = IdentityVerifier.createVerifier(context, new InitListener() {
                @Override
                public void onInit(int i) {
                    Log.i("verifier", "i==" + i);
                }
            });
        }
    }


    public void setParams() {

    }

    /**
     * 组操作
     * @param groupId 组id  在创建时作为组名
     * @param userId 用户id
     * @param type 操作类型
     * @param callback 回调
     */
    @Override
    public void groupSetting(String groupId, String userId, int type,RecognitionCallback callback) {
        ActionType = type;
        initListener(callback);
        verifier.setParameter(SpeechConstant.MFV_SCENES, "ipt");
        // 设置用户id
        verifier.setParameter(SpeechConstant.AUTH_ID, userId);
        String params = "";
        String cmd = "";
        switch (type){
            case FaceRecognition.GROUP_CREATE:
                //创建组
                params="scope=group,group_name=" + groupId;
                cmd = "add";
                break;
            case FaceRecognition.GROUP_DELETE:
                //删除组
                params="scope=group,group_id=" + groupId;
                cmd = "delete";
                break;
            case FaceRecognition.GROUP_ADD_PERSON:
                //加入组员
                params = "scope=person,group_id=" + groupId+",auth_id=" + userId;
                cmd = "add";
                break;
            case FaceRecognition.GROUP_DELETE_PERSON:
                //删除组员
                params = "scope=person,group_id=" + groupId+",auth_id=" + userId;
                cmd = "delete";
                break;
            case FaceRecognition.GROUP_FIND_ALL://查询所有组员
                params = "scope=group,group_id=" + groupId;
                cmd = "query";
                break;
                default:
                    break;
        }
        verifier.execute("ipt",cmd,params, identityListener);
    }

    /**
     * 人脸注册
     * @param groupId 用户组id
     * @param userId 用户id
     * @param imageData 图片二进制数据
     * @param callback 回调
     */
    @Override
    public void registerFace(String groupId, String userId, byte[] imageData, RecognitionCallback callback) {
        ActionType = FaceRecognition.RECOGNITION_REGISTER;
        initListener(callback);
        // 设置会话场景
        verifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
        // 设置会话类型
        verifier.setParameter(SpeechConstant.MFV_SST, "enroll");
        // 设置用户id
        verifier.setParameter(SpeechConstant.AUTH_ID, userId);
        verifier.startWorking(identityListener);
        String params = "";
//        String params = "scope=person,group_id=" + groupId + ",auth_id="+userId;
        verifier.writeData("ifr", params, imageData, 0, imageData.length);
        verifier.stopWrite("ifr");
    }

    /**
     * 人脸搜索
     * @param groupId 组id
     * @param imageData 图片二进制数据
     * @param callback 回调
     */
    @Override
    public void findFace(String groupId, byte[] imageData, RecognitionCallback callback) {
        ActionType = FaceRecognition.RECOGNITION_FIND;
        initListener(callback);
        // 设置会话场景
        verifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
        // 设置会话类型
        verifier.setParameter(SpeechConstant.MFV_SST, "identify");
        verifier.startWorking(identityListener);
        String params = "scope=person,group_id=" + groupId;
        verifier.writeData("ifr", params, imageData, 0, imageData.length);
        verifier.stopWrite("ifr");
    }

    /**
     * 人脸验证
     * @param groupId 组id
     * @param userId 用户id
     * @param imageData 图片二进制数据
     * @param callback 回调
     */
    @Override
    public void validationFace(String groupId, String userId, byte[] imageData, RecognitionCallback callback) {
        ActionType = FaceRecognition.RECOGNITION_IDENTIFY;
        initListener(callback);
        // 设置会话场景
        verifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
        // 设置会话类型
        verifier.setParameter(SpeechConstant.MFV_SST, "verify");
        // 设置验证模式,单一验证模式:sin
        verifier.setParameter(SpeechConstant.MFV_VCM, "sin");
        // 用户id
        verifier.setParameter(SpeechConstant.AUTH_ID, userId);
        verifier.startWorking(identityListener);
        String params = "group_id=" + groupId+ ",auth_id="+userId;;
        verifier.writeData("ifr", params, imageData, 0, imageData.length);
        verifier.stopWrite("ifr");
    }

    /**
     * 删除人脸
     * @param userId 用户id
     * @param callback 回调
     */
    @Override
    public void deleteFace(String userId, RecognitionCallback callback) {
        ActionType = FaceRecognition.RECOGNITION_DELETE;
        initListener(callback);
        // 设置会话场景
        verifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
        // 用户id
        verifier.setParameter(SpeechConstant.AUTH_ID, userId);
        verifier.execute("ifr","delete","",identityListener);
    }

    /**
     * 关闭人脸识别
     */
    @Override
    public void cancel() {
        if (verifier!=null){
            verifier.cancel();
            verifier.destroy();
            verifier = null;
        }
    }

    /**
     * 初始化监听器
     * @param callback 回调
     */
    public void initListener(final RecognitionCallback callback) {
        if (identityListener == null) {
            identityListener = new IdentityListener() {
                @Override
                public void onResult(IdentityResult identityResult, boolean b) {
                    Log.i("new--",identityResult.getResultString());
                    if (TextUtils.isEmpty(identityResult.getResultString())) return;
                    XunfeiFaceResult result = XunfeiFaceResult.getResult(identityResult.getResultString());
                    if (result==null){return;}
                    if (result.getSsub().equalsIgnoreCase("ipt")){//组操作
                        if (result.getSst().equalsIgnoreCase("query")){//查询所有组员
                            findAllPerson(result,callback);
                        }else if (result.getSst().equalsIgnoreCase("add")){
                            if (TextUtils.isEmpty(result.getUser())){//创建组
                                if (result.getRet()==0){
                                    callback.createGroup(true,result.getGroup_id());
                                }else {
                                    callback.createGroup(false,result.getGroup_id());
                                }
                            }else {//添加组用户
                                if (result.getRet()==0){
                                    callback.addPersonToGroup(true,result.getUser(),result.getGroup_id());
                                }else {
                                    callback.addPersonToGroup(false,result.getUser(),result.getGroup_id());
                                }
                            }
                        } else if (result.getSst().equalsIgnoreCase("delete")){
                            if (!TextUtils.isEmpty(result.getUser()) && !TextUtils.isEmpty(result.getGroup_id())){//删除组用户
                                if (result.getRet()==0){
                                    callback.deletePersonFromGroup(true,result.getUser(),result.getGroup_id());
                                }else {
                                    callback.deletePersonFromGroup(false,result.getUser(),result.getGroup_id());
                                }
                            }else if (!TextUtils.isEmpty(result.getGroup_id()) && TextUtils.isEmpty(result.getUser())){//删除组
                                if (result.getRet()==0){
                                    callback.deleteGroup(true,result.getGroup_id());
                                }else {
                                    callback.deleteGroup(false,result.getGroup_id());
                                }
                            }
                        }
                    }
                    else if (result.getSsub().equalsIgnoreCase("ifr")){//人脸操作
                        if (result.getSst().equalsIgnoreCase("verify")){//人脸验证
                            if (result.getDecision().equalsIgnoreCase("accepted")){
                                callback.identify(true,result.getFace_score());
                            }else {
                                callback.identify(false,result.getFace_score());
                            }
                        }else if (result.getSst().equalsIgnoreCase("enroll")){//人脸注册
                            if (result.getRet()==0){
                                callback.register(true);
                            }else {
                                callback.register(false);
                            }
                        }else if (result.getSst().equalsIgnoreCase("identify")){//人脸搜索
                            findFaceNext(result,callback);
                        }else if (result.getSst().equalsIgnoreCase("delete")){//删除用户
                            if (result.getRet()==0){
                                callback.deleteFace(true);
                            }else {
                                callback.deleteFace(false);
                            }
                        }
                    }
                }

                @Override
                public void onError(SpeechError speechError) {
                    Log.i("new--",speechError.getErrorCode() + ":" + speechError.getErrorDescription());
                    callback.fail(speechError.getErrorCode() + ":" + speechError.getErrorDescription(),ActionType);
                }

                @Override
                public void onEvent(int i, int i1, int i2, Bundle bundle) {

                }
            };
        }
    }

    private void findAllPerson(XunfeiFaceResult result, RecognitionCallback callback) {
        String ss = "";
        for (XunfeiFaceResult.PersonBean b:
             result.getPerson()) {
            ss += "用户:"+b.getUser()+", ";
        }
        Log.i("new--",ss);
    }

    private void findFaceNext(
                              XunfeiFaceResult result,
                              RecognitionCallback callback) {
        List<XunfeiFaceResult.IfvResultBean.CandidatesBean> candidatesBean = result.getIfv_result().getCandidates();
        if (candidatesBean == null || candidatesBean.size() == 0) {
            callback.findFace(false, null,0);
        } else {
            Person person = new Person();
            for (XunfeiFaceResult.IfvResultBean.CandidatesBean bb :
                    candidatesBean) {
                if (!bb.getDecision().equalsIgnoreCase("accepted")) {
                    candidatesBean.remove(bb);
                }
            }
            if (candidatesBean.size() == 0) {
                callback.findFace(false, null,0);
                return;
            }
            double score = 0;
            int index = 0;
            for (int i = 0; i < candidatesBean.size(); i++) {
                if (candidatesBean.get(i).getScore() > score) {
                    index = i;
                    score = candidatesBean.get(i).getScore();
                }
            }
            person.setGorupId(result.getGroup_id() + "");
            person.setUserId(candidatesBean.get(index).getUser());
            callback.findFace(true, person,candidatesBean.get(index).getScore());
        }
    }
}

这里需要注意的是,人脸识别都是上传图片的二进制文件,官方有大小限制要求在200k以内,此时大图片就要压缩以后在上传:
/**
     * 压缩图片
     * @param imgPath 图片路径
     * @return byte[]
     */
    private byte[] getImgData(String imgPath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(imgPath, options);
        // 压缩图片
        options.inSampleSize = Math.max(1, (int) Math.ceil(Math.max(
                (double) options.outWidth / 1024f,
                (double) options.outHeight / 1024f)));
        options.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(imgPath, options);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
        byte data[] = baos.toByteArray();
        return data;
    }

ok,第一篇文章完成!

移动端AI加速实战:TFLite模型量化与部署全解析 本文全面解析了移动端AI加速中TFLite模型量化与部署的实战技巧。通过对比动态量化、float16量化和int8量化三种方法,结合具体案例展示如何将模型大小缩减至1/4,推理速度提升2-3倍。文章还详细介绍了Android端集成流程、性能优化三板斧以及量化失败常见原因,帮助开发者高效实现移动端AI部署。 阅读详情

相关推荐

【科普周】入坑须知—机器学习扫盲篇(二)

欢迎关注哈希大数据微信公众号《哈希大数据》上一篇给大家介绍了有监督学习、无监督学习、和强化学习的含义和例子,这些可能还不够具体,机器学习博大精深本期咱们继续看看机器学习还有哪些好玩的点?想要入门机器学习你该怎么做?有哪些好的资料可以帮助大家尽快入门?废话不多说咱们开始吧!01 机器学习的应用目前机器学习在以下场景应用非常火热:1.推荐系统网易云音乐每日推荐、每个人淘宝APP的首页都不一样这就是它对...

HashData2018的博客 904

讯飞AIUI智能机器人6-----人脸识别技术

想要给你的项目加上人脸识别的亮点吗,那就来看看这篇文章吧。本次实验通过使用讯飞开放平台上MSC人脸识别能力,介绍了人脸验证与人脸检索的使用,结合服务机器人的相机能力,开发一个简单的人脸识别应用程序,了解人脸识别技术如何在机器人上使用,同时对人脸识别技术的使用途径和步骤进行详细讲解.........

qq_46906413的博客 4794

STM32毕业设计选题指南:10大方向100个题目与完整实现方案

嵌入式系统开发是电子信息、自动化等专业的核心实践领域,其关键在于微控制器选型、外设驱动与系统集成。STM32作为基于ARM Cortex-M内核的主流微控制器,凭借其丰富生态与高性价比,成为工程实践与毕业设计的理想平台。理解其工作原理,如通过HAL库进行外设配置、利用PWM控制电机、通过ADC采集传感器数据,是实现各类智能设备的基础。在物联网和智能硬件浪潮下,这些技术价值凸显,广泛应用于智能家居、工业控制、机器人等场景。本文聚焦STM32在毕业设计中的应用,结合PID控制算法、FreeRTOS等热词,提供了

weixin_30621711的博客 394

讯飞人脸识别

基于Android的讯飞的人脸识别的 Demo.

Tcoy.Lin 1万+

从零构建全栈美食订餐App:Android+Java+MySQL架构与实战复盘

移动应用开发的核心在于构建稳定、可扩展的系统架构,以满足用户与商户的双向需求。其基本原理通常遵循客户端-服务器模式,通过API进行数据交互,并利用关系型数据库如MySQL进行结构化数据存储。这种架构的技术价值在于实现了业务逻辑与数据管理的解耦,提升了系统的可维护性和可扩展性。在应用场景上,电商、本地生活服务等领域广泛采用此类模式,以支持商品浏览、购物车、订单和支付等核心流程。本文以美食订餐App为例,深入探讨了如何结合Android原生开发、Java后端服务与MySQL数据库,并集成人脸识别支付等前沿功能,

weixin_42571280的博客 273

ROS智能家居机器人实战:导航、视觉与混合编程深度解析

ROS(Robot Operating System)作为机器人开发的事实标准,其核心价值在于构建可复用、可协同的模块化系统架构;深度学习与视觉识别则赋予机器人环境理解与任务执行能力,尤其在YOLOv8目标检测、FaceNet人脸识别等轻量化模型落地中,需兼顾精度、延迟与嵌入式部署约束;Python与C混合编程并非语言偏好,而是实时性(C处理传感器融合、电机控制)与开发效率(Python实现状态机、语音交互逻辑)的工程权衡。本文聚焦真实家庭场景下的ROS机器人系统集成——从Cartographer建图优化、

weixin_29194693的博客 355

Android 手机的高级终端 Termux 安装使用、busybox、安卓 手机 web

手机已经 root安装 tsu,这是一个 su 的 Termux 版本,是一个真正的 root 权限,用来在 Termux上替代su,操作不慎可能对手机有安全风险,因为官方封装了,所以安装也很简单:安装 tsu:pkg install tsu -y切换到 root:tsu退出 root:exittsu切换 root 用户时会弹出 root 授权提示,给予其 root 权限即可。在管理员身份下输入 exit 可回到普通用户身份。

freeking101的博客 10万+

科大讯飞SDK语言人脸识别Demo,Android Studio可用

Android Studio可用,语音识别,人脸识别,语音合成 ,,测评,声纹等等

2024年面向初学者的25大Java项目创意

欢迎来到!我们致力于为广大IT从业者、学生和爱好者提供全面、实用的资源和服务。加入我们的聊天群,这里有专业大佬为你提供有价值的建议和指导!Java是IT行业的领先编程语言,几乎所有类型的软件开发都使用Java。从手机到大型机,Java无处不在。如果您是初学者或有软件开发抱负的人,我们强烈建议您开始从事实时和成熟的实时Java项目。这篇“Java项目”文章完全基于相同的计划,即帮助其他开发人员提供实时Java项目的想法,这将帮助您更接近您的梦想角色。

技术分享 6744

人脸识别Demo(讯飞)

基于讯飞人脸识别API开发的人脸识别Demo,欢迎下载学习

Android开发集成科大讯飞语音识别+语音合成Demo

一个Android开发集成科大讯飞语音识别+语音合成功能的小Demo

深入浅出安卓,怎样从零学好移动开发

因为近几年来互联网的飞速发展,安卓和iOS平台的大量普及推广。移动开发在当前是很热门的一个方向。 有不少同学问我怎样学习安卓。要学些什么,难不难学。之前一直没有想好应该怎么回答这个问题,仅仅是简单的说安卓自身门槛不高。并不难学。由于我认为准确回答一个类似这种问题往往须要灵感。如今依据我的学习体验,做个大概的总结。 1、我为什么学安卓 我从刚開始接触安卓开发到如...

weixin_30478923的博客 284

科大讯飞人脸识别SDK

科大讯飞人脸识别SDK,包含说明文件PDF,Java库文件jar,一个demo 分为联网模式和离线模式

探索终端智能新纪元 —— AoE:您的移动设备上的AI赋能者

探索终端智能新纪元 —— AoE:您的移动设备上的AI赋能者 在万物互联的时代,终端设备正逐渐成为人工智能(AI)应用的重要载体。面对海量算法和跨平台的复杂性,开发人员急需一套统一且高效的解决方案来加速深度学习模型在终端侧的落地。这就是为什么我们要向您推荐 AoE ,由滴滴出行研发并开源的一款革命性的集成运行时环境(IRE),它致力于简化AI模型在移动端的部署过程,让每个开发者都能享受到边缘计算带...

gitblog_01166的博客 847

讯飞人脸识别登陆

讯飞人脸识别登陆

告别卡顿!手把手教你用北鲲云超算平台图形化提交COMSOL仿真任务(附RDP连接技巧)

本文详细介绍了如何利用北鲲云超算平台图形化提交COMSOL仿真任务,解决本地计算资源不足导致的卡顿问题。通过云端高性能计算,用户可轻松配置多核CPU和大内存资源,实现高效仿真计算,并附有RDP连接优化技巧,提升远程操作体验。

weixin_42519781的博客 381

3分钟掌握跨平台AI集成:MediaPipe Tasks终极指南

还在为复杂的AI模型部署而头疼吗?想要在Android、iOS、Web和桌面应用中快速集成专业级AI功能,却不知从何下手?今天我要为你介绍一个改变游戏规则的工具——MediaPipe Tasks!这是一个跨平台、可定制的机器学习解决方案,专为实时和流媒体应用设计,让你在几分钟内就能实现从摄像头输入到AI结果输出的全流程。 ## 为什么选择MediaPipe Tasks?🤔 你是否曾经遇到过这

gitblog_00326的博客 742

SRE校招面试全攻略:从基础理论到实战场景解析

本文为SRE(站点可靠性工程)校招面试提供全面攻略,涵盖计算机基础、运维核心技能、场景设计与系统架构等关键模块。文章结合真实面试真题,解析了从Linux原理、网络协议到容器化、监控告警等实战考点,并分享了高可用设计、故障排查等工程思维,旨在帮助应届生夯实基础、理清思路,从容应对SRE校招挑战。

bush的博客 644

芯片界的‘公司组织架构图’:一张图看懂CPU、GPU、NPU、MCU与SoC

芯片界的‘公司组织架构图’:一张图看懂CPU、GPU、NPU、MCU与SoC

钡铼技术工业物联网 181

开源AI数字人DUIX:从零构建你的智能交互助手

本文详细介绍了如何利用开源AI数字人DUIX从零构建智能交互助手。文章阐述了DUIX作为开源项目的核心优势,包括低成本启动、低网络依赖和高度可定制性,并提供了从开发环境搭建、核心模块(AI模型、语音、形象)配置到个性化业务逻辑开发与最终部署的完整实践指南,帮助开发者快速掌握构建专属AI数字人的全流程。

weixin_29051811的博客 505

【网络安全 | 渗透工具】密码字典生成工具crunch、cupp安装使用教程

Crunch是一个常用的密码破解工具,它可以根据指定的字符集、长度和模式生成各种可能的密码并进行暴力破解。同时,Crunch可以将生成的密码保存到文件中,以便在破解工具中使用。在进行渗透测试时,手动收集密码字典是十分耗时的,利用密码字典生成工具可以大幅缩短时间,提高爆破宽度。

等风来 8424

MediaPipe实战指南:5分钟搭建跨平台AI视觉应用

想要为你的应用快速添加人脸识别、手势控制或姿态跟踪功能吗?MediaPipe正是你需要的跨平台机器学习框架!MediaPipe是Google开源的一套实时媒体处理工具,它让计算机视觉应用开发变得前所未有的简单。无论你是移动开发者、Web开发者还是桌面应用开发者,MediaPipe都能提供统一的解决方案。 ## 🎯 MediaPipe的核心优势:为什么选择这个框架? MediaPipe最大的魅

gitblog_00167的博客 232

【同等学力】01-逻辑符号表达

F(x): x是确诊者,G(x):x有症状F(x): x是老人,G(x):x是宠物,L(x,y): x喜欢y。

super_mochi1 1880
上一篇: 得分大作战
下一篇: Ionic初学之Ionic3(Cordova)插件制作与添加
DearLC
博客等级 码龄10年 18粉丝 27原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值