How Old Are You?
今天要分享的是一个测年龄的小应用,就类似是http://how-old.net官网测年龄的功能一样,我的也是这样一个功能,细节捕获当然没有how-old多啦,不过这些主要是基于一个第三方的jar包,我这里用到的是Face++的jar包,用到的是这个版本:Java SDK (Android) (Android2.3及以上)。
一、功能展示:
|
|
|
|
图一展示的是从图库选择测试图片的一个界面;图二是解析欲测试图片的一个界面;图三是一个测试结果的界面。下面说一下这个小应用的一些要点:
- 实现图库:
这里是采用Intent.ACTION_PICK中调用图库的用法来实现的,当然图片也要适当的压缩;
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGetImage:
Intent intent=new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent,PICK_CODE);
break;
}
}
onClick()
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode==PICK_CODE)
{
if (intent!=null)
{
Uri uri=intent.getData();
Cursor cursor=getContentResolver().query(uri, null, null,null, null);
cursor.moveToFirst();
int idx=cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
currentPhotoString=cursor.getString(idx);
cursor.close();
resizePhono();
ivPhoto.setImageBitmap(photoImg);
tvTip.setText("Click Detect==>");
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
/**
* 压缩图片
*/
private void resizePhono() {
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds=true;//仅仅加载图片
BitmapFactory.decodeFile(currentPhotoString, options);
double radio=Math.max(options.outWidth*1.0d/1024f, options.outHeight*1.0d/1024f);
options.inSampleSize=(int) Math.ceil(radio);
options.inJustDecodeBounds=false;
photoImg=BitmapFactory.decodeFile(currentPhotoString,options);
}
onActivityResult
- detect工具类实现:
对应于detect()方法,如果图片解析成功的话,就返回一个json字符串;如果失败的话,返回一个异常的数据。对应于不同的情况有不同的返回值,我定义了一个CallBack的interface;detetct()方法内部呢是要执行一个耗时的操作,所以要开启一个线程;那这个方法的主要功能也就是将图片转化为字节数组,封装到PostParameters中,通过detectionDetect方法返回JSON对象。
package com.example.how_old; import java.io.ByteArrayOutputStream; import org.json.JSONObject; import android.graphics.Bitmap;
import android.util.Log; import com.facepp.error.FaceppParseException;
import com.facepp.http.HttpRequests;
import com.facepp.http.PostParameters; public class FaceppDetect
{
public interface CallBack
{
void success(JSONObject result);
void error(FaceppParseException exception);
}
/**
* 将图片转化为字节数组,封装到PostParameters中,
* 通过detectionDetect方法返回JSON对象
* @param bitmap
* @param callBack
*/
public static void detect(final Bitmap bitmap,final CallBack callBack)
{
//匿名内部类参数最好声明成final类型
Log.v("aaaaa", "aaaa");
new Thread(new Runnable() { public void run() {
try {
Log.v("qqq", "11111");
HttpRequests requests=new HttpRequests(Constant.KET,Constant.SECRET,true,true);
Bitmap bmSmall=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bmSmall.compress(Bitmap.CompressFormat.JPEG, 100, stream); byte[] arrays=stream.toByteArray(); PostParameters parameters=new PostParameters();
parameters.setImg(arrays);
JSONObject jsonObject=requests.detectionDetect(parameters);
Log.v("TAG", jsonObject.toString());
if (callBack!=null) {
callBack.success(jsonObject);
}
} catch (FaceppParseException e) {
e.printStackTrace();
if (callBack!=null) {
callBack.error(e);
}
}
}
}).start();
} }
detect
- JSON解析,捕获属性值:
根据JSON的格式我们来解析JSON,获取到我们想要的属性值,说到JSON解析呢,有一个很好的JSON校验网站,bejson.com可以将无序的json字符串格式化,能帮助我们很好的解析json。将获取到的属性值赋值给控件,这里需要在主线程中更新UI,当然这也是Android的一个机制,Handler机制,通过Handler来更新主线程中的UI。
JSONArray faces;
faces = rs.getJSONArray("face");
int faceCount=faces.length();
tvTip.setText("find "+faceCount);
for (int i = 0; i < faceCount; i++) {
JSONObject face = faces.getJSONObject(i);
JSONObject posObj=face.getJSONObject("position"); float x=(float) posObj.getJSONObject("center").getDouble("x");
float y=(float) posObj.getJSONObject("center").getDouble("y"); float w=(float) posObj.getDouble("width");
float h=(float) posObj.getDouble("height"); x=x/100*bitmap.getWidth();
y=y/100*bitmap.getHeight(); w=w/100*bitmap.getWidth();
h=h/100*bitmap.getHeight();
解析JSON
private Handler handler=new Handler()
{
public void handleMessage(android.os.Message msg)
{
switch (msg.what) {
case MSG_SUCCESS:
flWaitting.setVisibility(View.GONE);
JSONObject rs=(JSONObject) msg.obj;
prepareRsBitmap(rs);
ivPhoto.setImageBitmap(photoImg);
break;
case MSG_ERROR:
flWaitting.setVisibility(View.GONE);
String errorMsg=(String) msg.obj;
if (TextUtils.isEmpty(errorMsg)) {
tvTip.setText("Error");
}
else {
tvTip.setText(errorMsg);
}
break;
}
super.handleMessage(msg);
}
Handler
- 绘制脸部及年龄显示框:
脸部显示框用到的主要的一个方法就是Canvas的drawLine()方法,而显示年龄的气泡,我们采用一个简单的控件Textview控件,简单设置下背景background、drawableLeft、text即可显示出气泡的赶脚,无需使用Canvas绘制。而主要的一个就是如何将Textview转化为Bitmap,我写了一个buildAgeBitmap()方法来转化。当然对应于图片的缩放,我们的气泡也是有一个缩放的,这样才合理嘛。哇咔咔!!!!
mPaint.setColor(0xffffffff);
mPaint.setStrokeWidth(3);
//画脸部方框
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); JSONObject attrObj=face.getJSONObject("attribute");
int ageValue=attrObj.getJSONObject("age").getInt("value");
// int ageRange=attrObj.getJSONObject("age").getInt("range");
String genderValue=attrObj.getJSONObject("gender").getString("value"); Bitmap ageBitmap=buildAgeBitmap(ageValue,"Male".equals(genderValue));
//气泡缩放
int ageWidth=ageBitmap.getWidth();
int ageHeight=ageBitmap.getHeight();
if (bitmap.getWidth()<ivPhoto.getWidth()&&bitmap.getHeight()<ivPhoto.getHeight()) {
float ratio=Math.max(bitmap.getWidth()*1.0f/ivPhoto.getWidth(), bitmap.getHeight()*1.0f/ivPhoto.getHeight());
ageBitmap=Bitmap.createScaledBitmap(ageBitmap, (int)(ageWidth*ratio),(int)(ageHeight*ratio), false);
}
canvas.drawBitmap(ageBitmap, x-ageBitmap.getWidth()/2,y-h/2-ageBitmap.getHeight(), null);
photoImg=bitmap;
绘制显示框
private Bitmap buildAgeBitmap(int ageValue, boolean isMale) {
TextView tvQp=(TextView) flWaitting.findViewById(R.id.tvAgeGender);
tvQp.setText(ageValue+"");
if (isMale) {
tvQp.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.male), null, null, null);
}
else {
tvQp.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.female), null, null, null);
}
tvQp.setDrawingCacheEnabled(true);
Bitmap bitmap=Bitmap.createBitmap(tvQp.getDrawingCache());
tvQp.destroyDrawingCache();
return bitmap;
};
buildAgeBitmap
其中,JSON解析和绘制显示框等操作都是放置在prepareRsBitmap()方法中的。基本上就这么多啦。啊你哦!!!!o 0我应该大家看一下JSON的格式:
{
"face": [
{
"position": {
"mouth_right": {
"y": 28.476451,
"x": 54.946591
},
"mouth_left": {
"y": 30.445734,
"x": 44.776818
},
"center": {
"y": 25.255973,
"x": 47.272727
},
"height": 16.723549,
"width": 22.272727,
"nose": {
"y": 25.643515,
"x": 45.270455
},
"eye_left": {
"y": 23.175427,
"x": 41.6
},
"eye_right": {
"y": 21.064334,
"x": 51.402045
}
},
"attribute": {
"race": {
"value": "Asian",
"confidence": 99.53840000000001
},
"gender": {
"value": "Female",
"confidence": 99.9903
},
"smiling": {
"value": 88.3311
},
"age": {
"value": 35,
"range": 7
}
},
"tag": "",
"face_id": "ac2a5139c9293e8b18d2cc26fe6b3d54"
}
],
"session_id": "09739b73148e45af98a1dd87671973d4",
"img_height": 586,
"img_width": 440,
"img_id": "ff62269ed6c0fff160d8f3a77c2eb4e3",
"url": null,
"response_code": 200
}
JSON
随机推荐
- 有关于CSS的面试题和练习
如果你处在一个需要面试别人有关于CSS方面技巧和知识,一时想起来还真有点难.我把我能想出来的整理在一起,提供给大家参考. 练习要做 正如他们说的,大家实际工作很重要.当然,大家通过工作练习更为重要.这 ...
- insertAfter()
<div id="b">bbbbbbbbb</div> <div>dddddd</div> JavaScript window.on ...
- mina高并发短连接导致java.io.IOException: Too many open files解决方案
http://marsvaadin.iteye.com/blog/1698924 mina性能测试 http://hi.baidu.com/rendong/item/bb5d2b0e4563c76dd ...
- ztree使用心得
一个很好用的Jquery树形控件 官网:http://www.ztree.me/v3/main.php#_zTreeInfo 我主要引用的文件为: //最新版的JS压缩包 <script src ...
- (转)用AGG实现高质量图形输出(三)
转自 :http://www.cnblogs.com/CoolJie/archive/2011/04/27/2030260.html 线段生成器(Span Generator) 我们前面举的例子使用的 ...
- CSS3 Animation 基于 less 构建的 css3 动画库
LESS动画优点 · 快速开发css3动画 · 采用less mixins写法,不会生成冗余css · 已加入主流浏览器前缀,保证最大兼容性 · LESS-Animation 部分mixins支持传参 ...
- iOS7与iOS8的比較
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1c2h1d2VpMDIyNA==/font/5a6L5L2T/fontsize/400/fill/I0 ...
- j简单的递归
1 某人写了n封信和n个信封,如果所有的信都装错了信封.求所有的信都装错信封共有多少种不同情况. 归纳法例子 1.有n个硬币(n为偶数)正面朝上排成一排,每次将n-1个硬币翻成朝上为止.编程让计算机把 ...
- MHA 安装过程 原创
root@monitor yum.repos.d]# cat CentOS-Base.repo [base]name=CentOS-$releasever - Basefailovermethod=p ...
- ext2磁盘布局
概述 本篇博客主要关注ext2文件系统的磁盘布局,即ext2会在格式化时将磁盘划分成什么样子. ext2磁盘布局 任何Ext2分区中的第一个块从不受Ext2文件系统的管理, ...


