转载请标明出处: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
不多说,接下来看看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"
}
三:具体实施
①下载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" />
⑥主界面的调用
/**
* 初始化
*/
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;
}
}
};
}