最近在市场中出现了一个特牛逼的功能,那就是刷脸,当然并不是老马的刷脸支付功能,而是how-old的刷脸神器,刷出自己的真实年龄和性别,看起来很牛叉,当然face++中也是实现了这个功能,当然既然是Android的刷脸神器,那么其实在红米和小米手机上,其实你也可以看到更更加强大的刷脸,照相功能自带刷脸识别,只刷神器,好了不吹牛逼了。
how-old地址:http://www.how-old.net/
face++地址:http://www.faceplusplus.com.cn/
上面分别是how-old和face++的地址,我们这里呢,可以直接去用他们的api进行快速开发,首先我想我们都避免不了需要去注册什么账号等,反正跟着做就好了,这里呢,我推荐大家使用face++,关于how-old呢,并不是说不能用,因为它是微软开发的,需要什么微软账号,注册起来,相当的蛋疼,反正我觉得麻烦,虽然我是不怕麻烦的人,但是呢,我还是很闲麻烦找上门。
这里呢,我们会获取两个值分别为:API_KEY 和 API_SECRET
不多说,接下来看看face++开发的详解,我们身为开发者,那么一定是看开发者文档咯,不用多说,直蹦主题
其实,我们可以看到,在face++给我们提供的api中有很多接口,功能说明,其中有检测脸,两张脸相似,脸的分类啊等等,看起来face++还是非常牛逼的,说明都为我们准备好了,我们呢,只是做一个简单的刷刷脸,所以,那么就看看第一个接口,检测脸,这个接口。戳进去看看:
首先是:参数介绍,不详细说,自己看看
接下来就是调用示例:需要什么参数,组件什么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" }
下载地址: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" />
/** * 初始化 */ 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); }
/** * 点击事件 */ 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; } } };
/** * 打开本地相册 */ 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); }
/** * 解析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; } } }; }