讯飞人脸识别

今天做了一套二级Java题,直接就绝望了。选择题就得了25分,错了将近一半,大后天就考了,忐忑。。


前天晚上和大前天晚上加班写了一个讯飞的一个人脸识别,结果昨天电脑系统让我安装Linux按的系统炸了。去他的,按了一下午系统昨天晚上干到十二点又写了一遍,不仅写的时间缩短了,而且更加清楚套路了。


整体来看,大约分以下步骤进行写。

1.从官网上申请服务,会给你个id也就是访问的key。吧这个记下来,下载人脸识别的SDK包括两个jar,和几个二进制文件。SDk里面有例程,导入Eclipce中运行无误后就可以看结构仿写了。


2.因为是用Android Studio写的所以较麻烦,需要将jar文件和so文件放入正确的位置。


3.主要分为两个类写的,第一个类就是进行照完的人脸进行裁剪类,这个是使用android自带的裁剪器,进行相应的配置,这个类里面主要是裁剪,对摄影的角度的判断,旋转图片,保存图片这几个方法。


4.第二个类就是通过SDK类进行识别了,首先需要将自己的申请的key在初始化SDK的时候添加进去,作为App唯一的标志允许访问服务,这个类主要是分三大块:Button的监听、对返回的数据进行Json解析判断、对Intent的监听(主要是照完相后对图片进行裁剪)。


一、下载的jar so文件的处理


新建jniLibs文件夹放入so文件    将Msc.jar Sunflower.jar文件放入libs文件夹中并添加进编译路径。


    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

二、裁剪类

package com.example.hejingzhou.facerecognition;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by Hejingzhou on 2016/3/22.
 */
public class HeadTrim {
    public final static int REQUEST_PICTURE_CHOOSE = 1;
    public final static int REQUEST_CAMERA_IMAGE = 2;
    public final static int REQUEST_CROP_IMAGE = 3;

    /**
     * 裁剪图片  android自带的裁剪
     * @param activity
     * @param uri
     */
    public static void corpPicture(Activity activity,Uri uri){
        Intent innerIntent = new Intent("com.android.camera.action.CROP");//启用自带裁剪
        innerIntent.setDataAndType(uri, "image/*");
        innerIntent.putExtra("crop", "ture");//裁剪小正方形,不然没有裁剪功能,只能选取
        innerIntent.putExtra("aspectX", 1);//放大缩小缩放比例
        innerIntent.putExtra("aspectY", 1);//缩放比例 1  :1
        innerIntent.putExtra("outputX", 320);
        innerIntent.putExtra("outputY", 320);//限制图片大小
        innerIntent.putExtra("return-data",true);

        //切图大小不足 320 会出现黑框,防止出现黑框并输出
        innerIntent.putExtra("scale",true);
        innerIntent.putExtra("scaleUpIfNeeded",true);
        File imageFile = new File(getImagePath(activity.getApplicationContext()));//从这个文件路径创建文件
        innerIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(imageFile));
        //MediaStore.EXTRA_OUTPUT  表示内容解析器被用来存储请求的Uri的图像或视频
        innerIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//带上裁剪好的图片传递出去
        activity.startActivityForResult(innerIntent,REQUEST_CROP_IMAGE);
    }

    /**
     * 获取裁剪的图片路径
     * @param context
     * @return
     */
    public static String getImagePath(Context context){
        String path;
        if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
        //如果当前存储的状态 是 不能挂载和读写的
            path = context.getFilesDir().getAbsolutePath();//路径就等于这个文件的绝对路径(从根开始)
        }else {
            path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/msc/";
        }
        if(!path.endsWith("/")){ //与路径的最后一个字符进行比较如果不是“/”那么就添加“/”
            path += "/";
        }
        File folder = new File(path);
        if(folder != null && !folder.exists()){//如果文件不为空 或者不存在,创建这个文件的文件夹
            folder.mkdirs();
        }
        path += "ifd.jpg";
        return path;
    }

    /**
     * 读取图片的属性   :的角度
     * @param path
     * @return
     */
    public static int readPictureDegree(String path){
        int degree = 0;//度
        try {
            ExifInterface exifInterface = new ExifInterface(path);//阅读和写作在JPEG文件的Exif标记类
            int orientation  = exifInterface.getAttributeInt(
            //ExifInterface.getAttributeInt 返回指定标记的整数值
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);//方向常规
            switch (orientation){
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋转图片
     * @param angle  旋转角度
     * @param bitmap  原图
     * @return 旋转后的  bitmap
     */
    public static Bitmap rotateImage(int angle,Bitmap bitmap){
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);   //postconcats与指定的旋转矩阵
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
        /**
         * createBitmap  返回一个不可变的位图从源位图的子集
         * @param source   The bitmap we are subsetting
         * @param x        The x coordinate of the first pixel in source
         * @param y        The y coordinate of the first pixel in source
         * @param width    The number of pixels in each row
         * @param height   The number of rows
         * @param m        Optional matrix to be applied to the pixels   可选的矩阵应用到像素
         * @param filter   true if the source should be filtered.        如果源应筛选,true
         *                   Only applies if the matrix contains more than just
         *                   translation.
         */
        return resizedBitmap;
    }

    /**
     * 保存图片
     * @param context
     * @param bitmap
     */
    public static void saveBitmapToFile(Context context, Bitmap bitmap) {
        String file_path = getImagePath(context);
        File file = new File(file_path);
        FileOutputStream fileOutputStream;
        try {
            fileOutputStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG,85,fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}


这个类中的裁剪方法挺好的,记住在别处也会用的着。


三、校验登陆(千万不能忘了初始化SDK并加入自己的key和实例化FaceRequest)

<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">package com.example.hejingzhou.facerecognition;</span>

<span style="font-family: Arial, Helvetica, sans-serif;">import android.app.ProgressDialog;</span>
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.FaceRequest;
import com.iflytek.cloud.RequestListener;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechUtility;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Currency;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private String TAG = getClass().getCanonicalName();
    private final int REQUEST_PICTURE_CHOOSE = 1;
    private final int REQUEST_CAMERA_IMAGES = 2;
    private FaceRequest faceRequest;
    private Toast toast;
    private byte[] imageData = null;
    private Bitmap image = null;
    private EditText editTextUserPassword;
    private String UserPassword;
    private ProgressDialog progressDialog;
    private File pictureFile;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }

    private void init() {
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        SpeechUtility.createUtility(this, "appid=" + getString(R.string.app_key));//初始化SDK 千万不能忘记写appid后边的等号  id是自己其官网上申请的
        //忘记会报 10274无效 key
        faceRequest = new FaceRequest(this);
        findViewById();
        toast = Toast.makeText(this,"",Toast.LENGTH_SHORT);
        progressDialog = new ProgressDialog(this);
        progressDialog.setCancelable(true);//设置是否可取消
        progressDialog.setTitle("请稍等...");
        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                if (null != faceRequest) {
                    faceRequest.cancel();
                }
            }
        });
    }

    private void findViewById() {
        editTextUserPassword = (EditText)findViewById(R.id.editTextUserPassword);
        findViewById(R.id.buttonRegister).setOnClickListener(MainActivity.this);
        findViewById(R.id.buttonPicture).setOnClickListener(MainActivity.this);
        findViewById(R.id.buttonVerification).setOnClickListener(MainActivity.this);
        findViewById(R.id.imageViewHead).setOnClickListener(MainActivity.this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.buttonPicture:
                pictureFile = new File(Environment.getExternalStorageDirectory(),
                        "picture"+System.currentTimeMillis()/1000+".jpg");
                Intent picIntent = new Intent();
                picIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
                picIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(pictureFile));
                picIntent.putExtra(MediaStore.Images.Media.ORIENTATION,0);
                startActivityForResult(picIntent,REQUEST_CAMERA_IMAGES);
                break;
            case R.id.buttonRegister:
                UserPassword = ((EditText)findViewById(R.id.editTextUserPassword)).getText().toString();
                if(TextUtils.isEmpty(UserPassword)){
                    showToast("请输入您的密钥");
                    return;
                }else if(null != imageData){
                    progressDialog.setMessage("注册中...");
                    progressDialog.show();
                    faceRequest.setParameter(SpeechConstant.AUTH_ID, UserPassword);//将授权标识和密码上传服务器记录
                    faceRequest.setParameter(SpeechConstant.WFR_SST,"reg");//业务类型train Or verify
                    faceRequest.sendRequest(imageData,requestListener);
                }else showToast("请先进行图像拍摄...");
                break;
            case R.id.buttonVerification:
                UserPassword = ((EditText)findViewById(R.id.editTextUserPassword)).getText().toString();
                if(TextUtils.isEmpty(UserPassword)){
                    showToast("密钥不能为空哦...");
                }else if(imageData != null){
                    progressDialog.setMessage("验证中,请稍等...");
                    progressDialog.show();//6--12字符 不能以数字开头
                    faceRequest.setParameter(SpeechConstant.AUTH_ID, UserPassword);
                    faceRequest.setParameter(SpeechConstant.WFR_SST,"verify");
                    faceRequest.sendRequest(imageData,requestListener);
                }else showToast("请先捕捉头像...");
                break;
        }
    }

    /**
     * 处理拍完照后,跳转到裁剪界面
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i(TAG, "运行到了onActivityResult");
        if(resultCode != RESULT_OK){
            Log.i(TAG,"requestCode未成功");
            return;
        }
        String fileSrc = null;
        if(requestCode == REQUEST_PICTURE_CHOOSE){
            if("file".equals(data.getData().getScheme())){
                fileSrc = data.getData().getPath();
                Log.i(TAG,"file "+fileSrc);
            }else {
                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();
            }
            HeadTrim.corpPicture(this, Uri.fromFile(new File(fileSrc)));
        }else if(requestCode == REQUEST_CAMERA_IMAGES){
            if(null == pictureFile){
                showToast("拍照失败,请重试...");
                return;
            }
            fileSrc = pictureFile.getAbsolutePath();
            updataGallery(fileSrc);
            HeadTrim.corpPicture(this,Uri.fromFile(new File(fileSrc)));
        }else if(requestCode == HeadTrim.REQUEST_CROP_IMAGE){
            Bitmap bitmap = data.getParcelableExtra("data");
            Log.i(TAG,"bitmp是否为空");
            if(null != bitmap){
                HeadTrim.saveBitmapToFile(MainActivity.this,bitmap);
            }
            fileSrc = HeadTrim.getImagePath(MainActivity.this);//获取图片保存路径
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            image = 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;
            image = BitmapFactory.decodeFile(fileSrc,options);
            //如果imageBitmap 为空图片不能正常获取
            if(null == image){
                showToast("图片信息无法正常获取");
                return;
            }
            int degree = HeadTrim.readPictureDegree(fileSrc);
            if(degree != 0){
                image = HeadTrim.rotateImage(degree,image);
            }
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            image.compress(Bitmap.CompressFormat.JPEG,80,byteArrayOutputStream);
            imageData = byteArrayOutputStream.toByteArray();
            ((ImageView)findViewById(R.id.imageViewHead)).setImageBitmap(image);
        }
    }

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

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

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

                    }
                });
    }

    /**
     * 请求对象监听  , 对服务器返回来的数据进行解析  JSON格式
     */
    private RequestListener requestListener = new RequestListener() {
        @Override
        public void onEvent(int i, Bundle bundle) {

        }

        @Override
        public void onBufferReceived(byte[] bytes) {
            if(null != progressDialog){
                progressDialog.dismiss();
            }
            try {
                String result = new String(bytes,"utf-8");
                Log.i(TAG,result);
                JSONObject object = new JSONObject(result);
                String type = object.optString("sst");//获取业务类型
                if("reg".equals(type)){//注册
                    register(object);
                }else if("verify".equals(type)){//校验
                    verify(object);
                }else if("detect".equals(type)){
                    detect(object);
                }else if("aligm".equals(type)){
                  //align(object);
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onCompleted(SpeechError speechError) {//完成后
            if(null != progressDialog){
                progressDialog.dismiss();
            }
            if(speechError != null ){
                switch (speechError.getErrorCode()){
                    case ErrorCode.MSP_ERROR_ALREADY_EXIST:
                        showToast("密钥已被注册,请更换后再试...");
                        break;
                    default:showToast(speechError.getPlainDescription(true));
                        break;
                }
            }
        }
    };
    //检测
    private void detect(JSONObject object) throws JSONException{
        int ret = object.getInt("ret");
        if(ret != 0){
            showToast("检测失败");
        }else if("success".equals(object.get("rst"))){
            JSONArray jsonArray = object.getJSONArray("face");
            Paint paint = new Paint();
            paint.setColor(Color.RED);
            paint.setStrokeWidth(Math.max(image.getWidth(), image.getHeight()) / 100f);

            Bitmap bitmap = Bitmap.createBitmap(image.getWidth(),image.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            canvas.drawBitmap(image,new Matrix(),null);
            for(int i = 0;i<jsonArray.length();i++){
                float x1 = (float) jsonArray.getJSONObject(i).getJSONObject("position").getDouble("left");
                float y1 = (float) jsonArray.getJSONObject(i).getJSONObject("position").getDouble("top");
                float x2 = (float) jsonArray.getJSONObject(i).getJSONObject("position").getDouble("right");
                float y2 = (float) jsonArray.getJSONObject(i).getJSONObject("position").getDouble("bottom");
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawRect(new Rect((int)x1,(int)x2,(int)x2,(int)y2),paint);
            }
            image = bitmap;
            ((ImageView)findViewById(R.id.imageViewHead)).setImageBitmap(image);
        }else {
            showToast("检测失败");
        }
    }

    /**
     * 校验
      * @param object
     */
    private void verify(JSONObject object) throws JSONException{
        int ret = object.getInt("ret");
        Log.i(TAG,"ret校验"+ret);
        if(ret != 0){
            showToast("校验失败..."+ret);
        }else if("success".equals(object.get("rst"))){
            if(object.getBoolean("verf")){
                showToast("验证通过");
                editTextUserPassword.setText(null);
                startActivity(new Intent(MainActivity.this,JumpActivity.class));
            }else if(!object.getBoolean("verg")){
                showToast("验证不通过");
            }else showToast("验证失败");
        }
    }

    /**
     * 如果收回的数据类型是注册 进行一下处理
      * @param object
     */
    private void register(JSONObject object) throws JSONException{
        int ret = object.getInt("ret");//解析ret返回值  0代表成功 -1失败  或者其他的错误异常代码
        if(ret != 0){
            showToast("注册失败");
            return;
        }else if("success".equals(object.get("rst"))){
            showToast("注册成功");
            editTextUserPassword.setText(null);
        }else showToast("注册失败,错误");

    }

    //土司对话框
    private void showToast(final String s){
        toast.setText(s);
        toast.show();
    }
}

Ok 就这个简单。

效果:



评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值