How Old Are You?


今天要分享的是一個測年齡的小應用,就類似是http://how-old.net官網測年齡的功能一樣,我的也是這樣一個功能,細節捕獲當然沒有how-old多啦,不過這些主要是基於一個第三方的jar包,我這里用到的是Face++的jar包,用到的是這個版本:Java SDK (Android) (Android2.3及以上)。

一、功能展示:

LY`%5SE7RI_JR`8XA[YPIVL

(F36JJ)~2N}MSOHR3NRVETK

2HVI)T{XX}5EEA}7%9%}O6I

圖一展示的是從圖庫選擇測試圖片的一個界面;圖二是解析欲測試圖片的一個界面;圖三是一個測試結果的界面。下面說一下這個小應用的一些要點:

  • 實現圖庫:

這里是采用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字符串;如果失敗的話,返回一個異常的數據。對應於不同的情況有不同的返回值,我定義了一個CallBackinterface;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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM