Android 刷脸神器,颜值价更高

转载请标明出处:http://blog.csdn.net/u011546655/article/details/46608995

背景

最近在市场中出现了一个特牛逼的功能,那就是刷脸,当然并不是老马的刷脸支付功能,而是how-old的刷脸神器,刷出自己的真实年龄和性别,看起来很牛叉,当然face++中也是实现了这个功能,当然既然是Android的刷脸神器,那么其实在红米和小米手机上,其实你也可以看到更更加强大的刷脸,照相功能自带刷脸识别,只刷神器,好了不吹牛逼了。


一:接下来看效果图

二:how-old和face++简介

how-old地址:http://www.how-old.net/

face++地址:http://www.faceplusplus.com.cn/

上面分别是how-old和face++的地址,我们这里呢,可以直接去用他们的api进行快速开发,首先我想我们都避免不了需要去注册什么账号等,反正跟着做就好了,这里呢,我推荐大家使用face++,关于how-old呢,并不是说不能用,因为它是微软开发的,需要什么微软账号,注册起来,相当的蛋疼,反正我觉得麻烦,虽然我是不怕麻烦的人,但是呢,我还是很闲麻烦找上门。


这里呢,我们会获取两个值分别为:API_KEY    和   API_SECRET

Android 刷脸神器,颜值价更高_第1张图片



不多说,接下来看看face++开发的详解,我们身为开发者,那么一定是看开发者文档咯,不用多说,直蹦主题

Android 刷脸神器,颜值价更高_第2张图片




其实,我们可以看到,在face++给我们提供的api中有很多接口,功能说明,其中有检测脸,两张脸相似,脸的分类啊等等,看起来face++还是非常牛逼的,说明都为我们准备好了,我们呢,只是做一个简单的刷刷脸,所以,那么就看看第一个接口,检测脸,这个接口。戳进去看看:

首先是:参数介绍,不详细说,自己看看

Android 刷脸神器,颜值价更高_第3张图片



接下来就是调用示例:需要什么参数,组件什么url等等。

http://apicn.faceplusplus.com/v2/detection/detect?api_key=YOUR_API_KEY&api_secret=YOUR_API_SECRET&url=http%3A%2F%2Ffaceplusplus.com%2Fstatic%2Fimg%2Fdemo%2F1.jpg&attribute=glass,pose,gender,age,race,smiling

 

Gson数据格式

{
    "face": [
        {
            "attribute": {
                "age": {
                    "range": 5, 
                    "value": 23
                }, 
                "gender": {
                    "confidence": 99.9999, 
                    "value": "Female"
                }, 
                "glass": {
                    "confidence": 99.945, 
                    "value": "None"
                }, 
                "pose": {
                    "pitch_angle": {
                        "value": 17
                    }, 
                    "roll_angle": {
                        "value": 0.735735
                    }, 
                    "yaw_angle": {
                        "value": -2
                    }
                }, 
                "race": {
                    "confidence": 99.6121, 
                    "value": "Asian"
                }, 
                "smiling": {
                    "value": 4.86501
                }
            }, 
            "face_id": "17233b4b1b51ac91e391e5afe130eb78", 
            "position": {
                "center": {
                    "x": 49.4, 
                    "y": 37.6
                }, 
                "eye_left": {
                    "x": 43.3692, 
                    "y": 30.8192
                }, 
                "eye_right": {
                    "x": 56.5606, 
                    "y": 30.9886
                }, 
                "height": 26.8, 
                "mouth_left": {
                    "x": 46.1326, 
                    "y": 44.9468
                }, 
                "mouth_right": {
                    "x": 54.2592, 
                    "y": 44.6282
                }, 
                "nose": {
                    "x": 49.9404, 
                    "y": 38.8484
                }, 
                "width": 26.8
            }, 
            "tag": ""
        }
    ], 
    "img_height": 500, 
    "img_id": "22fd9efc64c87e00224c33dd8718eec7", 
    "img_width": 500, 
    "session_id": "38047ad0f0b34c7e8c6efb6ba39ed355", 
    "url": "http://www.faceplusplus.com.cn/wp-content/themes/faceplusplus/assets/img/demo/1.jpg?v=4"
}

三:具体实施

①下载face++sdk

下载地址:http://www.faceplusplus.com.cn/dev-tools-sdks/


②完成配置文件的编写 

package com.how_old.tools;

/**
 * 配置类
 * 
 * @author zengtao 2015年5月25日 下午9:30:22
 *
 */
public class Config {
	// face++
	public static final String APP_KEY = "66324964c66934cb35a1eb6f1dfc1db8";
	public static final String API_SECRET = "dSe2p0Vn39O8MEQGXd1bSRuaZ-VqXYa2";
	
}


③完成网络请求的编写

package com.how_old.utils;

import java.io.ByteArrayOutputStream;

import org.json.JSONObject;

import android.graphics.Bitmap;

import com.facepp.error.FaceppParseException;
import com.facepp.http.HttpRequests;
import com.facepp.http.PostParameters;
import com.how_old.tools.Config;

/**
 * 网络请求
 * 
 * @author zengtao 2015年5月25日 下午9:29:54
 *
 */
public class Https {

	/**
	 * 将图片转换成二进制:发送请求
	 * 
	 * @param bitmap
	 */
	public static void detect(final Bitmap bitmap, final CallBack callBack) {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					HttpRequests requests = new HttpRequests(Config.APP_KEY,
							Config.API_SECRET, true, true);

					Bitmap b = Bitmap.createBitmap(bitmap, 0, 0,
							bitmap.getWidth(), bitmap.getHeight());
					ByteArrayOutputStream stream = new ByteArrayOutputStream();
					b.compress(Bitmap.CompressFormat.JPEG, 100, stream);
					byte[] arrays = stream.toByteArray();

					// 这里面封装好了key-value的键值对
					PostParameters parameters = new PostParameters();
					parameters.setImg(arrays);

					JSONObject jsonObject = requests
							.detectionDetect(parameters);

					if (callBack != null) {
						callBack.success(jsonObject);
						System.out.println("Return Success : \n" + jsonObject);
					}
				} catch (FaceppParseException e) {
					e.printStackTrace();
					if (callBack != null) {
						callBack.faile(e);
						System.out.println("Return Fail : \n" + e);
					}
				}
			}
		}).start();
	}

	// 设置回调
	public interface CallBack {
		void success(JSONObject jsonObject);

		void faile(FaceppParseException e);
	}
}

④布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/t4" />

    <!-- 底部 -->

    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/display_photomessage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="photo info"
            android:textSize="12sp" />

        <Button
            android:id="@+id/check_photo"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="check photo"
            android:textSize="12sp" />

        <Button
            android:id="@+id/open_grally"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:gravity="center"
            android:text="open grally"
            android:textSize="12sp" />
    </LinearLayout>

    <!-- 进度 -->

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" >

        <ProgressBar
            android:id="@+id/waitProgressBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone" />

        <TextView
            android:id="@+id/topview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="#EEAD0E"
            android:drawableLeft="@drawable/male"
            android:gravity="center"
            android:text="123"
            android:textColor="#ff0000"
            android:textSize="18sp"
            android:visibility="invisible" />
    </FrameLayout>

</RelativeLayout>

⑤添加权限

  <!-- 权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />



⑥主界面的调用

1.初始化视图
	/**
	 * 初始化
	 */
	private void initView() {
		mImageView = (ImageView) findViewById(R.id.photo);
		find_message = (TextView) findViewById(R.id.display_photomessage);
		check_photo = (Button) findViewById(R.id.check_photo);
		open_grally = (Button) findViewById(R.id.open_grally);
		mProgressBar = (ProgressBar) findViewById(R.id.waitProgressBar);
		topview = (TextView) findViewById(R.id.topview);

		open_grally.setOnClickListener(listener);
		check_photo.setOnClickListener(listener);

		mPaint = new Paint();
		mPaint.setColor(0xffffffff);
		mPaint.setStrokeWidth(3);
		mPaint.setAntiAlias(true);
	}


2.监听事件
	/**
	 * 点击事件
	 */
	OnClickListener listener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			case R.id.check_photo:
				mProgressBar.setVisibility(View.VISIBLE);
				if (photoPath != null && !photoPath.trim().equals("")) {
					compressPhoto();
				} else {
					bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.t4);
				}
				checkPhoto();
				break;
			case R.id.open_grally:
				openGrally();
				break;
			}
		}
	};


3. 打开本地图库,选择图片,压缩图片,返回图片
	/**
	 * 打开本地相册
	 */
	private void openGrally() {
		Intent intent = new Intent();
		intent.setAction(Intent.ACTION_PICK);
		intent.setType("image/*");
		startActivityForResult(intent, 1);
	}

	/**
	 * 压缩图片大小:防止图片太大出现异常
	 */
	private void compressPhoto() {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(photoPath, options);
		// 获取最大的比例
		double scale = Math.max(options.outWidth * 1.0 / 1024f, options.outHeight * 1.0 / 2014f);
		options.inSampleSize = (int) Math.ceil(scale);
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(photoPath, options);
	}

	/**
	 * 打开之后点击照片,显示在自己的app中
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == 1) {
			if (resultCode == RESULT_OK) {
				if (data != null) {
					// 1.获取路劲
					Uri uri = data.getData();
					Cursor cursor = getContentResolver().query(uri, null, null, null, null);
					cursor.moveToFirst();
					int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
					photoPath = cursor.getString(index);
					cursor.close();
					// 2.压缩图片
					compressPhoto();
					// 3.设置图片
					mImageView.setImageBitmap(bitmap);
				}
			}
		}
		super.onActivityResult(requestCode, resultCode, data);
	}


4. 检测图片,绘制脸框,年龄和性别
	/**
	 * 解析json文件
	 * 
	 * @param jsonObject
	 */
	protected void parperJsonBitmap(JSONObject jsonObject) {

		Bitmap bit = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
		Canvas canvas = new Canvas(bit);
		canvas.drawBitmap(bitmap, 0, 0, null);
		try {
			JSONArray faces = jsonObject.getJSONArray("face");
			// System.out.println("Return faces : " + faces);

			int facecount = faces.length(); // 找到了几张脸
			find_message.setText("find : " + facecount);

			for (int i = 0; i < facecount; i++) {

				JSONObject face = faces.getJSONObject(i); // 当前的那张脸
				// System.out.println("Return face : " + face);

				JSONObject pos = face.getJSONObject("position"); // 单张脸下的postion对象
				// System.out.println("Return pos : " + pos);

				float x = (float) pos.getJSONObject("center").getDouble("x");
				float y = (float) pos.getJSONObject("center").getDouble("y");
				float w = (float) pos.getDouble("width");
				float h = (float) pos.getDouble("height");

				x = x / 100 * bit.getWidth();
				y = y / 100 * bit.getHeight();
				w = w / 100 * bit.getWidth();
				h = h / 100 * bit.getHeight();

				// 画box
				canvas.drawLine(x - w / 2, y - h / 2, x - w / 2, y + h / 2, mPaint);
				canvas.drawLine(x - w / 2, y - h / 2, x + w / 2, y - h / 2, mPaint);
				canvas.drawLine(x + w / 2, y - h / 2, x + w / 2, y + h / 2, mPaint);
				canvas.drawLine(x - w / 2, y + h / 2, x + w / 2, y + h / 2, mPaint);

				// --------------------------------------------------------
				// --------------------------------------------------------
				// --------------------------------------------------------
				// 获取头部要显示的信息:年龄和性别
				String gender = face.getJSONObject("attribute").getJSONObject("gender").getString("value");
				int age = face.getJSONObject("attribute").getJSONObject("age").getInt("value");

				Bitmap ageBitmap = buildBitmap(age, "Male".endsWith(gender));
				int ageWidth = ageBitmap.getWidth();
				int ageHeight = ageBitmap.getHeight();

				if (bit.getWidth() < mImageView.getWidth() && bit.getHeight() < mImageView.getHeight()) {

					float scale = Math.max(bit.getWidth() * 1.0f / mImageView.getWidth(), bit.getHeight() * 1.0f / mImageView.getHeight());

					ageBitmap = Bitmap.createScaledBitmap(ageBitmap, (int) (ageWidth * scale), (int) (ageHeight * scale), false);
				}

				canvas.drawBitmap(ageBitmap, x - ageBitmap.getWidth() / 2, y - h / 2 - ageBitmap.getHeight(), null);

				// 将绘制好的图片返回给要设置的图片
				bitmap = bit;
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 显示年龄和性别的view
	 * 
	 * @param age
	 * @param endsWith
	 * @return
	 */
	private Bitmap buildBitmap(int age, boolean isMale) {
		topview.setText(age + "");
		if (isMale) {
			topview.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.male), null, null, null);
		} else {
			topview.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.female), null, null, null);
		}
		topview.setDrawingCacheEnabled(true);
		Bitmap bitmap = Bitmap.createBitmap(topview.getDrawingCache());
		topview.destroyDrawingCache();
		return bitmap;
	}

	/**
	 * 检测照片
	 */
	private void checkPhoto() {
		Https.detect(bitmap, new CallBack() {

			@Override
			public void success(JSONObject jsonObject) {
				Message msg = new Message();
				msg.what = SUCCESS;
				msg.obj = jsonObject;
				handler.sendMessage(msg);
			}

			@Override
			public void faile(FaceppParseException e) {
				Message msg = new Message();
				msg.what = FAIL;
				msg.obj = e.getMessage();
				handler.sendMessage(msg);
			}
		});
	}

四:示例源码

package com.how_old.ui;

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

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.facepp.error.FaceppParseException;
import com.how_old.utils.Https;
import com.how_old.utils.Https.CallBack;

/**
 * 主界面
 * 
 * @author zengtao 2015年5月25日 下午9:30:11
 *
 */
public class MainActivity extends Activity {
	private Button check_photo, open_grally;
	private ImageView mImageView;
	private TextView find_message, topview;

	private String photoPath;
	private Bitmap bitmap;
	private ProgressBar mProgressBar;
	private Paint mPaint;

	private static final int SUCCESS = 0x111;
	private static final int FAIL = 0x112;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
	}

	@SuppressLint("HandlerLeak")
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case SUCCESS:
				mProgressBar.setVisibility(View.GONE);
				JSONObject jsonObject = (JSONObject) msg.obj;
				parperJsonBitmap(jsonObject);
				mImageView.setImageBitmap(bitmap);
				break;
			case FAIL:
				mProgressBar.setVisibility(View.GONE);
				String err = (String) msg.obj;
				if (TextUtils.isEmpty(err)) {
					find_message.setText(err);
				}
				break;
			}
		};
	};

	/**
	 * 初始化
	 */
	private void initView() {
		mImageView = (ImageView) findViewById(R.id.photo);
		find_message = (TextView) findViewById(R.id.display_photomessage);
		check_photo = (Button) findViewById(R.id.check_photo);
		open_grally = (Button) findViewById(R.id.open_grally);
		mProgressBar = (ProgressBar) findViewById(R.id.waitProgressBar);
		topview = (TextView) findViewById(R.id.topview);

		open_grally.setOnClickListener(listener);
		check_photo.setOnClickListener(listener);

		mPaint = new Paint();
		mPaint.setColor(0xffffffff);
		mPaint.setStrokeWidth(3);
		mPaint.setAntiAlias(true);
	}

	/**
	 * 解析json文件
	 * 
	 * @param jsonObject
	 */
	protected void parperJsonBitmap(JSONObject jsonObject) {

		Bitmap bit = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
		Canvas canvas = new Canvas(bit);
		canvas.drawBitmap(bitmap, 0, 0, null);
		try {
			JSONArray faces = jsonObject.getJSONArray("face");
			// System.out.println("Return faces : " + faces);

			int facecount = faces.length(); // 找到了几张脸
			find_message.setText("find : " + facecount);

			for (int i = 0; i < facecount; i++) {

				JSONObject face = faces.getJSONObject(i); // 当前的那张脸
				// System.out.println("Return face : " + face);

				JSONObject pos = face.getJSONObject("position"); // 单张脸下的postion对象
				// System.out.println("Return pos : " + pos);

				float x = (float) pos.getJSONObject("center").getDouble("x");
				float y = (float) pos.getJSONObject("center").getDouble("y");
				float w = (float) pos.getDouble("width");
				float h = (float) pos.getDouble("height");

				x = x / 100 * bit.getWidth();
				y = y / 100 * bit.getHeight();
				w = w / 100 * bit.getWidth();
				h = h / 100 * bit.getHeight();

				// 画box
				canvas.drawLine(x - w / 2, y - h / 2, x - w / 2, y + h / 2, mPaint);
				canvas.drawLine(x - w / 2, y - h / 2, x + w / 2, y - h / 2, mPaint);
				canvas.drawLine(x + w / 2, y - h / 2, x + w / 2, y + h / 2, mPaint);
				canvas.drawLine(x - w / 2, y + h / 2, x + w / 2, y + h / 2, mPaint);

				// --------------------------------------------------------
				// --------------------------------------------------------
				// --------------------------------------------------------
				// 获取头部要显示的信息:年龄和性别
				String gender = face.getJSONObject("attribute").getJSONObject("gender").getString("value");
				int age = face.getJSONObject("attribute").getJSONObject("age").getInt("value");

				Bitmap ageBitmap = buildBitmap(age, "Male".endsWith(gender));
				int ageWidth = ageBitmap.getWidth();
				int ageHeight = ageBitmap.getHeight();

				if (bit.getWidth() < mImageView.getWidth() && bit.getHeight() < mImageView.getHeight()) {

					float scale = Math.max(bit.getWidth() * 1.0f / mImageView.getWidth(), bit.getHeight() * 1.0f / mImageView.getHeight());

					ageBitmap = Bitmap.createScaledBitmap(ageBitmap, (int) (ageWidth * scale), (int) (ageHeight * scale), false);
				}

				canvas.drawBitmap(ageBitmap, x - ageBitmap.getWidth() / 2, y - h / 2 - ageBitmap.getHeight(), null);

				// 将绘制好的图片返回给要设置的图片
				bitmap = bit;
			}
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 显示年龄和性别的view
	 * 
	 * @param age
	 * @param endsWith
	 * @return
	 */
	private Bitmap buildBitmap(int age, boolean isMale) {
		topview.setText(age + "");
		if (isMale) {
			topview.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.male), null, null, null);
		} else {
			topview.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.female), null, null, null);
		}
		topview.setDrawingCacheEnabled(true);
		Bitmap bitmap = Bitmap.createBitmap(topview.getDrawingCache());
		topview.destroyDrawingCache();
		return bitmap;
	}

	/**
	 * 检测照片
	 */
	private void checkPhoto() {
		Https.detect(bitmap, new CallBack() {

			@Override
			public void success(JSONObject jsonObject) {
				Message msg = new Message();
				msg.what = SUCCESS;
				msg.obj = jsonObject;
				handler.sendMessage(msg);
			}

			@Override
			public void faile(FaceppParseException e) {
				Message msg = new Message();
				msg.what = FAIL;
				msg.obj = e.getMessage();
				handler.sendMessage(msg);
			}
		});
	}

	/**
	 * 打开本地相册
	 */
	private void openGrally() {
		Intent intent = new Intent();
		intent.setAction(Intent.ACTION_PICK);
		intent.setType("image/*");
		startActivityForResult(intent, 1);
	}

	/**
	 * 压缩图片大小:防止图片太大出现异常
	 */
	private void compressPhoto() {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(photoPath, options);
		// 获取最大的比例
		double scale = Math.max(options.outWidth * 1.0 / 1024f, options.outHeight * 1.0 / 2014f);
		options.inSampleSize = (int) Math.ceil(scale);
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(photoPath, options);
	}

	/**
	 * 打开之后点击照片,显示在自己的app中
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == 1) {
			if (resultCode == RESULT_OK) {
				if (data != null) {
					// 1.获取路劲
					Uri uri = data.getData();
					Cursor cursor = getContentResolver().query(uri, null, null, null, null);
					cursor.moveToFirst();
					int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
					photoPath = cursor.getString(index);
					cursor.close();
					// 2.压缩图片
					compressPhoto();
					// 3.设置图片
					mImageView.setImageBitmap(bitmap);
				}
			}
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	/**
	 * 点击事件
	 */
	OnClickListener listener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			switch (v.getId()) {
			case R.id.check_photo:
				mProgressBar.setVisibility(View.VISIBLE);
				if (photoPath != null && !photoPath.trim().equals("")) {
					compressPhoto();
				} else {
					bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.t4);
				}
				checkPhoto();
				break;
			case R.id.open_grally:
				openGrally();
				break;
			}
		}
	};
}

五:总结

以上就完成了刷脸神器,现在等待你的就是赶紧找自己的图片来试一试,发现自己的颜值到底有多高,来试一试最近风靡一时的刷脸神器,就这样在你手中完成了,当然你想要理解原来,那么你还需要了解更多。
Demo下载地址: http://download.csdn.net/detail/u011546655/8832163

你可能感兴趣的:(源码,android,how-old,刷脸神器)