訊飛SDK圖文使用說明 語音聽寫、語音合成、聲紋密碼、人臉識別(適配Android7.0)

關於訊飛,他們關於語音做的AI功能SDK特別好,我經過使用有了深刻的體驗,這次講一講語音聽寫、語音合成、聲紋密碼、人臉識別這三種的功能的體驗。


1.首先到訊飛開放平臺註冊賬號,然後到右上角點擊我的應用創建應用,並給應用添加新功能
http://www.xfyun.cn/


2.然後在我的應用界面點擊對應應用的欄目的SDK下載按鈕跳轉頁面,這裏我可以看到語音聽寫、人臉識別、語音合成、聲紋識別都是免費的,然後其他的幾個有體驗標識的功能,每天也也可以使用500。



3.我們點擊SDK下載按鈕就會下載一個壓縮包,解壓後我們把sample文件夾下speechDemo文件夾的代碼都移植到Android Studio上,因爲這些代碼原本都是Android Studio上創建的,所以不用改什麼。我這裏是直接創建一個包名一樣的project,然後把speechDemo文件夾的代碼直接移植過去。移植完後,還需要將根目錄的assets、libs、res文件直接複製過去,選擇全部覆蓋。


4.適配Android6.0權限申請

在MainActivity的onCreate函數里加入以下代碼

		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
			requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_FINE_LOCATION
					, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_CONTACTS,
					Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
					Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.CAMERA}, 1001);
		}

5.適配Android7.0

首先在AndroidManifest裏添加一個相機權限,因爲有的手機調用系統相機需要這個權限

<uses-permission android:name="android.permission.CAMERA"/>

然後修改OnlineFaceDemo這個類,

public class OnlineFaceDemo extends Activity implements View.OnClickListener {
    private final String TAG = "OnlineFaceDemo";
    private final int REQUEST_PICTURE_CHOOSE = 1;
    private final int REQUEST_CAMERA_IMAGE = 2;

    private Bitmap mImage = null;
    private byte[] mImageData = null;
    // authid爲6-18個字符長度,用於唯一標識用戶
    private String mAuthid = null;
    private Toast mToast;
    // 進度對話框
    private ProgressDialog mProDialog;
    private EditText online_authid;
    // 拍照得到的照片文件
    private File mPictureFile;
    // FaceRequest對象,集成了人臉識別的各種功能
    //private FaceRequest mFaceRequest;

    //採用身份識別接口進行在線人臉識別
    private IdentityVerifier mIdVerifier;

    // 模型操作
    private int mModelCmd;
    // 刪除模型
    private final static int MODEL_DEL = 1;



    private static final int CODE_GALLERY_REQUEST = 0xa0;
    private static final int CODE_CAMERA_REQUEST = 0xa1;
    private static final int CODE_RESULT_REQUEST = 0xa2;
    private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
    private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;
    private File fileUri = new File(Environment.getExternalStorageDirectory().getPath() + "/photo.jpg");
    private File fileCropUri = new File(Environment.getExternalStorageDirectory().getPath() + "/crop_photo.jpg");
    private Uri imageUri;
    private Uri cropImageUri;

    @SuppressLint("ShowToast")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.online_facedemo);
        findViewById(R.id.online_pick).setOnClickListener(OnlineFaceDemo.this);
        findViewById(R.id.online_reg).setOnClickListener(OnlineFaceDemo.this);
        findViewById(R.id.online_verify).setOnClickListener(OnlineFaceDemo.this);
        findViewById(R.id.online_camera).setOnClickListener(OnlineFaceDemo.this);
        findViewById(R.id.btn_modle_delete).setOnClickListener(OnlineFaceDemo.this);
        findViewById(R.id.btn_identity).setOnClickListener(OnlineFaceDemo.this);
        online_authid = (EditText) findViewById(R.id.online_authid);
        mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);

        mProDialog = new ProgressDialog(this);
        mProDialog.setCancelable(true);
        mProDialog.setTitle("請稍後");

        mProDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                // cancel進度框時,取消正在進行的操作
                if (null != mIdVerifier) {
                    mIdVerifier.cancel();
                }
            }
        });

        mIdVerifier = IdentityVerifier.createVerifier(OnlineFaceDemo.this, new InitListener() {
            @Override
            public void onInit(int errorCode) {
                if (ErrorCode.SUCCESS == errorCode) {
                    showTip("引擎初始化成功");
                } else {
                    showTip("引擎初始化失敗,錯誤碼:" + errorCode);
                }
            }
        });
    }

    private void register(JSONObject obj) throws JSONException {
        int ret = obj.getInt("ret");
        if (ret != 0) {
            showTip("註冊失敗");
            return;
        }
        if ("success".equals(obj.get("rst"))) {
            showTip("註冊成功");
        } else {
            showTip("註冊失敗");
        }
    }

    private void verify(JSONObject obj) throws JSONException {
        int ret = obj.getInt("ret");
        if (ret != 0) {
            showTip("驗證失敗");
            return;
        }
        if ("success".equals(obj.get("rst"))) {
            if (obj.getBoolean("verf")) {
                showTip("通過驗證,歡迎回來!");
            } else {
                showTip("驗證不通過");
            }
        } else {
            showTip("驗證失敗");
        }
    }




    /**
     * 人臉註冊監聽器
     */
    private IdentityListener mEnrollListener = new IdentityListener() {

        @Override
        public void onResult(IdentityResult result, boolean islast) {
            Log.d(TAG, result.getResultString());

            if (null != mProDialog) {
                mProDialog.dismiss();
            }

            try {
                JSONObject object = new JSONObject(result.getResultString());
                int ret = object.getInt("ret");

                if (ErrorCode.SUCCESS == ret) {
                    showTip("註冊成功");
                }else {
                    showTip(new SpeechError(ret).getPlainDescription(true));
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
        }

        @Override
        public void onError(SpeechError error) {
            if (null != mProDialog) {
                mProDialog.dismiss();
            }

            showTip(error.getPlainDescription(true));
        }

    };

    /**
     * 人臉驗證監聽器
     */
    private IdentityListener mVerifyListener = new IdentityListener() {

        @Override
        public void onResult(IdentityResult result, boolean islast) {
            Log.d(TAG, result.getResultString());

            if (null != mProDialog) {
                mProDialog.dismiss();
            }

            try {
                JSONObject object = new JSONObject(result.getResultString());
                Log.d(TAG,"object is: "+object.toString());
                String decision = object.getString("decision");

                if ("accepted".equalsIgnoreCase(decision)) {
                    showTip("通過驗證");
                } else {
                    showTip("驗證失敗");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
        }

        @Override
        public void onError(SpeechError error) {
            if (null != mProDialog) {
                mProDialog.dismiss();
            }

            showTip(error.getPlainDescription(true));
        }

    };

    /**
     * 人臉模型操作監聽器
     */
    private IdentityListener mModelListener = new IdentityListener() {

        @Override
        public void onResult(IdentityResult result, boolean islast) {
            Log.d(TAG, result.getResultString());

            JSONObject jsonResult = null;
            int ret = ErrorCode.SUCCESS;
            try {
                jsonResult = new JSONObject(result.getResultString());
                ret = jsonResult.getInt("ret");
            } catch (JSONException e) {
                e.printStackTrace();
            }
            // 根據操作類型判斷結果類型
            switch (mModelCmd) {
                case MODEL_DEL:
                    if (ErrorCode.SUCCESS == ret) {
                        online_authid.setEnabled(true);
                        showTip("刪除成功");
                    } else {
                        showTip("刪除失敗");
                    }
                    break;
                default:
                    break;
            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
        }

        @Override
        public void onError(SpeechError error) {
            // 彈出錯誤信息
            showTip(error.getPlainDescription(true));
        }

    };



    private void executeModelCommand(String cmd) {
        // 設置人臉模型操作參數
        // 清空參數
        mIdVerifier.setParameter(SpeechConstant.PARAMS, null);
        // 設置會話場景
        mIdVerifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
        // 用戶id
        mIdVerifier.setParameter(SpeechConstant.AUTH_ID, mAuthid);

        // 設置模型參數,若無可以傳空字符傳
        StringBuffer params = new StringBuffer();
        // 執行模型操作
        mIdVerifier.execute("ifr", cmd, params.toString(), mModelListener);
    }

    @Override
    public void onClick(View view) {
        int ret = ErrorCode.SUCCESS;
        mAuthid = online_authid.getText().toString();
        if(TextUtils.isEmpty(mAuthid)) {
            showTip("請輸入用戶ID");
            return;
        }else {
            online_authid.setEnabled(false);
        }

        switch (view.getId()) {
            case R.id.online_pick:

                PhotoUtils.openPic(this, CODE_GALLERY_REQUEST);

/*                Intent intent = new Intent();
                intent.setType("image*//*");
                intent.setAction(Intent.ACTION_PICK);
                startActivityForResult(intent, REQUEST_PICTURE_CHOOSE);*/
                break;
            case R.id.online_reg:
                if (TextUtils.isEmpty(mAuthid)) {
                    showTip("authid不能爲空");
                    return;
                }

                if (null != mImageData) {
                    mProDialog.setMessage("註冊中...");
                    mProDialog.show();
                    // 設置用戶標識,格式爲6-18個字符(由字母、數字、下劃線組成,不得以數字開頭,不能包含空格)。
                    // 當不設置時,雲端將使用用戶設備的設備ID來標識終端用戶。
                    // 設置人臉註冊參數
                    // 清空參數
                    mIdVerifier.setParameter(SpeechConstant.PARAMS, null);
                    // 設置會話場景
                    mIdVerifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
                    // 設置會話類型
                    mIdVerifier.setParameter(SpeechConstant.MFV_SST, "enroll");
                    // 設置用戶id
                    mIdVerifier.setParameter(SpeechConstant.AUTH_ID, mAuthid);
                    // 設置監聽器,開始會話
                    mIdVerifier.startWorking(mEnrollListener);

                    // 子業務執行參數,若無可以傳空字符傳
                    StringBuffer params = new StringBuffer();
                    // 向子業務寫入數據,人臉數據可以一次寫入
                    mIdVerifier.writeData("ifr", params.toString(), mImageData, 0, mImageData.length);
                    // 停止寫入
                    mIdVerifier.stopWrite("ifr");
                } else {
                    showTip("請選擇圖片後再註冊");
                }
                break;
            case R.id.online_verify:
                mAuthid = ((EditText) findViewById(R.id.online_authid)).getText().toString();
                if (TextUtils.isEmpty(mAuthid)) {
                    showTip("authid不能爲空");
                    return;
                }

                if (null != mImageData) {
                    mProDialog.setMessage("驗證中...");
                    mProDialog.show();
                    // 設置人臉驗證參數
                    // 清空參數
                    mIdVerifier.setParameter(SpeechConstant.PARAMS, null);
                    // 設置會話場景
                    mIdVerifier.setParameter(SpeechConstant.MFV_SCENES, "ifr");
                    // 設置會話類型
                    mIdVerifier.setParameter(SpeechConstant.MFV_SST, "verify");
                    // 設置驗證模式,單一驗證模式:sin
                    mIdVerifier.setParameter(SpeechConstant.MFV_VCM, "sin");
                    // 用戶id
                    mIdVerifier.setParameter(SpeechConstant.AUTH_ID, mAuthid);
                    // 設置監聽器,開始會話
                    mIdVerifier.startWorking(mVerifyListener);

                    // 子業務執行參數,若無可以傳空字符傳
                    StringBuffer params = new StringBuffer();
                    // 向子業務寫入數據,人臉數據可以一次寫入
                    mIdVerifier.writeData("ifr", params.toString(), mImageData, 0, mImageData.length);
                    // 停止寫入
                    mIdVerifier.stopWrite("ifr");
                } else {
                    showTip("請選擇圖片後再驗證");
                }
                break;

            case R.id.online_camera:
                // 設置相機拍照後照片保存路徑

                imageUri = Uri.fromFile(fileUri);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                    imageUri = FileProvider.getUriForFile(OnlineFaceDemo.this, "com.zz.fileprovider", fileUri);//通過FileProvider創建一個content類型的Uri
                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_REQUEST);

                break;
            case R.id.btn_modle_delete:
                // 人臉模型刪除
                mModelCmd = MODEL_DEL;
                executeModelCommand("delete");
                break;
            case R.id.btn_identity:
                Intent init  = new Intent(OnlineFaceDemo.this, GroupManagerActivity.class);
                init.putExtra("auth_id",mAuthid);
                init.putExtra("mfv_scenes","ifr");
                startActivity(init);
                break;
            default:
                break;
        }//end of switch

        if( ErrorCode.SUCCESS != ret ){
            mProDialog.dismiss();
            showTip( "出現錯誤:"+ret );
        }
    }

    private static final int OUTPUT_X = 480;
    private static final int OUTPUT_Y = 480;

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != RESULT_OK) {
            return;
        }

        String fileSrc = null;
        if (requestCode == REQUEST_PICTURE_CHOOSE) {
            if ("file".equals(data.getData().getScheme())) {
                // 有些低版本機型返回的Uri模式爲file
                fileSrc = data.getData().getPath();
            } else {
                // Uri模型爲content
                String[] proj = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(data.getData(), proj,
                        null, null, null);
                cursor.moveToFirst();
                int idx = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                fileSrc = cursor.getString(idx);
                cursor.close();
            }
            // 跳轉到圖片裁剪頁面
            FaceUtil.cropPicture(this,Uri.fromFile(new File(fileSrc)));
        } else if (requestCode == REQUEST_CAMERA_IMAGE) {
            if (null == mPictureFile) {
                showTip("拍照失敗,請重試");
                return;
            }

/*            fileSrc = mPictureFile.getAbsolutePath();
            updateGallery(fileSrc);*/
            // 跳轉到圖片裁剪頁面

           // FaceUtil.cropPicture(this, FileProvider.getUriForFile(OnlineFaceDemo.this, "com.zz.fileprovider", new File(fileSrc)));

            cropImageUri = Uri.fromFile(fileCropUri);
            PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);
        } else if (requestCode == FaceUtil.REQUEST_CROP_IMAGE) {
            // 獲取返回數據
            Bitmap bmp = data.getParcelableExtra("data");
            // 若返回數據不爲null,保存至本地,防止裁剪時未能正常保存
            if(null != bmp){
                FaceUtil.saveBitmapToFile(OnlineFaceDemo.this, bmp);
            }
            // 獲取圖片保存路徑
            fileSrc = FaceUtil.getImagePath(OnlineFaceDemo.this);
            // 獲取圖片的寬和高
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            mImage = BitmapFactory.decodeFile(fileSrc, options);

            // 壓縮圖片
            options.inSampleSize = Math.max(1, (int) Math.ceil(Math.max(
                    (double) options.outWidth / 1024f,
                    (double) options.outHeight / 1024f)));
            options.inJustDecodeBounds = false;
            mImage = BitmapFactory.decodeFile(fileSrc, options);


            // 若mImageBitmap爲空則圖片信息不能正常獲取
            if(null == mImage) {
                showTip("圖片信息無法正常獲取!");
                return;
            }

            // 部分手機會對圖片做旋轉,這裏檢測旋轉角度
            int degree = FaceUtil.readPictureDegree(fileSrc);
            if (degree != 0) {
                // 把圖片旋轉爲正的方向
                mImage = FaceUtil.rotateImage(degree, mImage);
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            //可根據流量及網絡狀況對圖片進行壓縮
            mImage.compress(Bitmap.CompressFormat.JPEG, 80, baos);
            mImageData = baos.toByteArray();

            ((ImageView) findViewById(R.id.online_img)).setImageBitmap(mImage);
        }





        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                //拍照完成回調
                case CODE_CAMERA_REQUEST:
                    cropImageUri = Uri.fromFile(fileCropUri);
                    PhotoUtils.cropImageUri(this, imageUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);
                    break;
                //訪問相冊完成回調
                case CODE_GALLERY_REQUEST:

                        cropImageUri = Uri.fromFile(fileCropUri);
                        Uri newUri = Uri.parse(PhotoUtils.getPath(this, data.getData()));
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            newUri = FileProvider.getUriForFile(this, "com.zz.fileprovider", new File(newUri.getPath()));
                        }
                        PhotoUtils.cropImageUri(this, newUri, cropImageUri, 1, 1, OUTPUT_X, OUTPUT_Y, CODE_RESULT_REQUEST);

                    break;
                case CODE_RESULT_REQUEST:
                    Bitmap bitmap = PhotoUtils.getBitmapFromUri(cropImageUri, this);
                    if (bitmap != null) {
                        ((ImageView) findViewById(R.id.online_img)).setImageBitmap(bitmap);
                        mImage = bitmap;
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();

                        //可根據流量及網絡狀況對圖片進行壓縮
                        mImage.compress(Bitmap.CompressFormat.JPEG, 80, baos);
                        mImageData = baos.toByteArray();
                    }
                    break;
                default:
            }
        }

    }

    @Override
    public void finish() {
        if (null != mProDialog) {
            mProDialog.dismiss();
        }
        super.finish();
    }

    private void updateGallery(String filename) {
        MediaScannerConnection.scanFile(this, new String[] {filename}, null,
                new MediaScannerConnection.OnScanCompletedListener() {

                    @Override
                    public void onScanCompleted(String path, Uri uri) {

                    }
                });
    }

    private void showTip(final String str) {
        mToast.setText(str);
        mToast.show();
    }
}

其中需要我們新建一個類,爲了專門完成調用系統相機和相冊,也是爲了替代項目中FaceUtil類,因爲他不適配Android7.0

public class PhotoUtils {
    private static final String TAG = "PhotoUtils";

    /**
     * @param activity    當前activity
     * @param imageUri    拍照後照片存儲路徑
     * @param requestCode 調用系統相機請求碼
     */
    public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //調用系統相機
        Intent intentCamera = new Intent();
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //將拍照結果保存至photo_file的Uri中,不保留在相冊中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        activity.startActivityForResult(intentCamera, requestCode);
    }

    /**
     * @param activity    當前activity
     * @param requestCode 打開相冊的請求碼
     */
    public static void openPic(Activity activity, int requestCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, requestCode);
    }

    /**
     * @param activity    當前activity
     * @param orgUri      剪裁原圖的Uri
     * @param desUri      剪裁後的圖片的Uri
     * @param aspectX     X方向的比例
     * @param aspectY     Y方向的比例
     * @param width       剪裁圖片的寬度
     * @param height      剪裁圖片高度
     * @param requestCode 剪裁圖片的請求碼
     */
    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        //發送裁剪信號
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        //將剪切的圖片保存到目標Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
        //1-false用uri返回圖片
        //2-true直接用bitmap返回圖片(此種只適用於小圖片,返回圖片過大會報錯)
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        activity.startActivityForResult(intent, requestCode);
    }

    /**
     * 讀取uri所在的圖片
     *
     * @param uri      圖片對應的Uri
     * @param mContext 上下文對象
     * @return 獲取圖像的Bitmap
     */
    public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
        try {
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param context 上下文對象
     * @param uri     當前相冊照片的Uri
     * @return 解析後的Uri對應的String
     */
    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        String pathHead = "file:///";
        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("primary".equalsIgnoreCase(type)) {
                    return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);

                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return pathHead + getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};

                return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + uri.getPath();
        }
        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

}

運行項目安裝app,

首先是語音聽寫,點擊開始我們就可以說話了,他也會彈出一個對話框顯示正在錄音,你也可以再點擊一下屏幕,它會停止錄音。這個聽寫的準確度,一般還可以,但是對於聲音相似的單詞就容易錯。然後使用這個聽寫是不需要流量的。


然後是在線語音合成,其實就是把文字語音播放出來,與語音聽寫相對立。這個功能需要流量,然後我們可以選擇發音人。


最後一個是聲紋密碼,首先輸入authId,這個其實就是相當於用戶名,你就隨便輸入幾個字母,然後點擊獲取密碼,然後點擊聲紋註冊再點擊開始錄音,他會讓你讀一段數字,這個錄音要進行五次。然後點擊1:1驗證,再點擊開始錄音,這個時候他會讓你讀一段數字,然後他判斷你是否是這個authId所代表的用戶。

最後是人臉識別,首先是填寫authid,然後是選圖(調用系統相冊)或者拍照(調用系統相機),註冊。註冊成功後,你就可以通過再次選圖或者拍照,點擊1:1驗證,可以通過兩次圖片判斷是否是同一個人。他還有人臉模型刪除,和1:N驗證





發佈了125 篇原創文章 · 獲贊 159 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章