Face++ 人脸检测、注册以及训练(1)

Face++ 人脸检测、注册以及训练(1)

@Author : Dolphix.J Qing


1 引言 

  • 人脸检测

检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性

    • 目前面部属性包括性别(gender), 年龄(age), 种族(race), 微笑程度(smiling), 眼镜(glass)和姿势(pose)

若结果的face_id没有被加入任何faceset/person之中,则在72小时之后过期被自动清除。

  • 人脸训练

针对verify功能对一个person进行训练。请注意:

    • 在一个person内进行verify之前,必须先对该person进行Train
    • 当一个person内的数据被修改后(例如增删Person相关的Face等),为使这些修改生效,person应当被重新Train
    • Train所花费的时间较长, 因此该调用是异步的,仅返回session_id。
    • 训练的结果可以通过/info/get_session查询。当训练完成时,返回值中将包含{"success": true}

2  系统摄像头操作

调用Android系统摄像头,对人脸进行采集。其中有以下几个地方需要注意:

  1. 开设前置摄像头
  2. 设置指定存储位置
  3. 对图片进行压缩(这样可以避免不必要的流量消耗,同时也提高响应速度)
其中,系统摄像头使用如下,主要包括调用摄像头并获取结果全过程(absPath为存储路径)。

 /**
     * 开启系统相机
     */
    private void openSysCamera(){
        if (savePrepare()){
            //开启系统相机
            Intent camera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            camera.putExtra("camerasensortype", 2); // 调用前置摄像头
            camera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(absPath,"tmp.jpg")));
            startActivityForResult(camera, EventUtil.SYS_CAMERA);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == EventUtil.SYS_CAMERA && resultCode == Activity.RESULT_OK){
            Log.i(TAG,"Camera finish!");
            //保持原图比例压缩,并保存为tmp2.jpg
            b = FileUtil.compressBySize(jpegName,500,500);
            face.setImageBitmap(b);
            FileUtil.saveBitmap(b,absPath+"tmp2.jpg");
            if (CommonUtil.isNetWorkConnected(getApplicationContext())){
                //人脸检测
                detectFace();
            }else{
                Toast.makeText(getApplicationContext(),"无法检测,网络可能存在问题!",Toast.LENGTH_SHORT).show();
            }
        }else if (requestCode == EventUtil.SYS_CAMERA && resultCode == Activity.RESULT_CANCELED){
            finish();
        }
    }

图片压缩,压缩时主要放缩比例,同时留意API平台对图片的尺寸要求。

/**
	 * 压缩图片尺寸
	 * @param pathName
	 * @param targetWidth
	 * @param targetHeight
     * @return
     */
	public static Bitmap compressBySize(String pathName, int targetWidth,int targetHeight) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inJustDecodeBounds = true;// 不去真的解析图片,只是获取图片的头部信息,包含宽高等;
		Bitmap bitmap = BitmapFactory.decodeFile(pathName, opts);
		// 得到图片的宽度、高度;
		float imgWidth = opts.outWidth;
		float imgHeight = opts.outHeight;
		// 分别计算图片宽度、高度与目标宽度、高度的比例;取大于等于该比例的最小整数;
		int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
		int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
		opts.inSampleSize = 1;
		if (widthRatio > 1 || heightRatio > 1) {
			if (widthRatio > heightRatio) {
				opts.inSampleSize = widthRatio;
			} else {
				opts.inSampleSize = heightRatio;
			}
		}
		//设置好缩放比例后,加载图片进内容;
		opts.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(pathName, opts);
		return bitmap;
	}

图片保存至SD卡,此操作时注意添加相应权限。

/**
	 * 保存Bitmap到sdcard
	 * @param b
	 * @return 图片绝对路径
	 */
	public static String saveBitmap(Bitmap b, String jpegName){
		File tmp = new File(jpegName);
		if (tmp.exists()){
			tmp.delete();
		}
		try {
			FileOutputStream fout = new FileOutputStream(jpegName);
			BufferedOutputStream bos = new BufferedOutputStream(fout);
			//压缩50%
			b.compress(Bitmap.CompressFormat.JPEG, 50, bos);
			bos.flush();
			bos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return jpegName;
	}

3 人脸检测、注册及训练

主要流程代码如下,其中缺失代码为GET/POST请求,格式构造可以参考

Face++ 人脸检测之POST[img](0)

 /**
     * 检测人脸
     */
    private void detectFace(){

        new Thread(new Runnable(){
            @Override
            public void run() {
                PlatformDetect.detect(new File(absPath+"tmp2.jpg"));
            }
        }).start();
    }

    /**
     * 人脸检测,回调
     */
    private class DetectCallback implements PlatformDetect.DetectCallback{

        @Override
        public void detectResult(JSONObject rst) {
            if (null == rst){
                return;
            }
            Log.i(TAG, "detectResult: "+rst.toString());
            try {
                if (!rst.has("error")){
                    //找出所有人脸
                    final int count = rst.getJSONArray("face").length();
                    if (count > 0){
                        Log.i(TAG, "detectResult: 存在人脸");
                        jsonObject = rst;
                        //取得face_id
                        FaceInfo.face_id = rst.getJSONArray("face").getJSONObject(0).getString("face_id");
                        if (CommonUtil.isNetWorkConnected(getApplicationContext())) {
                            //人脸识别
                            addFace();
                        }
                        //开始根据数据绘制位置、坐标
                        handler.sendEmptyMessage(EventUtil.FACE_DRAW_DETECT_DATA);
                        return;
                    }
                }
                //不存在人脸
                handler.sendEmptyMessage(EventUtil.NOT_EXIST_FACE);

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 添加人脸
     */
    private void addFace(){

        new Thread(new Runnable(){
            @Override
            public void run() {
                requestPlatform();
            }
        }).start();
    }

    /**
     * 请求Face++平台服务
     */
    private void requestPlatform(){
        Log.i(TAG, "requestPlatform: ");
        try {
            boolean b = true;
            int t = 0;
            if (null == user){
                Log.i(TAG, "requestPlatform: null == user");
                return;
            }
            while (b && t < 3) {
                if (!user.equals("vcrobot") && CommonUtil.isNetWorkConnected(getApplicationContext())) {
                    //添加人脸
                    String result = NetTask.doGet(FacePerson.addFace(FaceInfo.face_id, user));
                    Log.i(TAG, "run: addFace "+result);
                    JSONObject jsonObject = new JSONObject(result);
                    if (jsonObject.has("error") || !jsonObject.getBoolean("success")) {
                        //添加失败,创建用户
                        result = NetTask.doGet(FacePerson.create("vcrobot",user,"vcr"));
                        Log.i(TAG, "run: create person "+result);
                        jsonObject = new JSONObject(result);
                        if (jsonObject.has("error") || jsonObject.getInt("added_group") <= 0){
                            //group不存在,创建group
                            result = NetTask.doGet(FaceGroup.create("vcrobot","vcr"));
                            jsonObject = new JSONObject(result);
                            Log.i(TAG, "run: create group "+result);
                            if (!jsonObject.has("error")){
                                Log.i(TAG, "requestPlatform: Group create success!");
                            }
                        }else{
                            Log.i(TAG, "requestPlatform: Person create success!");
                        }
                    }else{
                        b = false;
                        handler.sendEmptyMessage(EventUtil.FACE_ADD_SUCCESS);
                        Log.i(TAG, "requestPlatform: Add face success!");
                    }
                }
                ++t;
            }
            if (b){
                handler.sendEmptyMessage(EventUtil.FACE_ADD_FAIL);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 针对verify功能对一个person进行训练。
     */
    private void trainFace(){
        new Thread(new Runnable(){
            @Override
            public void run() {
                if (CommonUtil.isNetWorkConnected(getApplicationContext())){
                    PlatformTrain.train(user);
                }
            }
        }).start();
    }


    /**
     * 人脸训练,回调
     */
    private class TrainCallback implements PlatformTrain.TrainCallback{
        @Override
        public void trainResult(JSONObject rst) {
            Log.i(TAG, "trainResult: "+rst);
            try{
                if (!rst.has("error")){
                    //相应请求的session标识符,可用于结果查询
                    sessionID = rst.getString("session_id");
                    handler.sendEmptyMessage(EventUtil.FACE_TRAIN_FINISH);
                }else{
                    //人脸训练出错
                    handler.sendEmptyMessage(EventUtil.FACE_TRAIN_ERR);
                }

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

最后,给出GET函数。具体URL自行构造。

/**
     * doGet发送网络请求
     * @param url
     * @return
     */
    public static String doGet(String url) {
        Log.i(TAG, "doGet: "+url);
        try{
            HttpClient httpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            HttpResponse httpResponse = httpClient.execute(httpGet);
//            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                HttpEntity httpEntity = httpResponse.getEntity();
                InputStream inputStream = httpEntity.getContent();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                String line = null;
                StringBuffer stringBuffer = new StringBuffer();
                while (null != (line = bufferedReader.readLine())) {
                    stringBuffer.append(line);
                }
                return stringBuffer.toString();
//            }
        }catch (Exception e){e.printStackTrace();}

        return null;
    }



原文作者:Dolphix.J Qing

你可能感兴趣的:(face++)