1. 程式人生 > >Android移動開發-在Android專案裡整合face++人臉識別的實現

Android移動開發-在Android專案裡整合face++人臉識別的實現

“人工智慧”是今年比較火的一個名詞,甚至大多數人認為“人工智慧”是繼“IT網際網路”之後一個新的浪潮,將會是本世紀最高科技的水準。個人覺得,目前國內語音識別做的比較好的是科大訊飛,影象識別(或人臉識別)做的比較好的是face++(曠視)。

那麼,如何在Android專案裡整合face++人臉識別的實現呢?
首先在face++的開發平臺網址:https://www.faceplusplus.com.cn/ ,然後在平臺註冊成為開發者後在點選“應用管理”——建立“API Key”號,如下圖所示:

這裡寫圖片描述

接著再繫結Bundle ID號,如下圖所示:

這裡寫圖片描述

  • layout/activity_main.xml介面佈局程式碼如下:
<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<ImageView android:id="@+id/id_photo" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_alignTop="@+id/id_detect" android:src="@drawable/face" />
<TextView android:id="@+id/id_tip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignTop="@+id/id_detect" android:layout_marginRight="10dp" android:layout_toLeftOf="@+id/id_detect" android:gravity="center" android:text="tip" /> <Button android:id="@+id/id_detect" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginRight="10dip" android:layout_toLeftOf="@+id/id_getImg" android:text="檢測人臉" /> <Button android:id="@+id/id_getImg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginRight="10dp" android:text="選擇圖片" /> <FrameLayout android:id="@+id/id_waiting" android:layout_width="match_parent" android:layout_height="match_parent" android:clickable="true" android:visibility="gone"> <ProgressBar android:id="@+id/id_progressBar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <TextView android:id="@+id/id_age_and_gender" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/hint" android:drawableLeft="@drawable/male" android:gravity="center" android:text="123" android:textColor="#ffff00ff" android:textSize="22sp" android:visibility="invisible" /> </FrameLayout> </RelativeLayout>
  • MainActivity.java邏輯程式碼如下:
package com.fukaimei.facerecognition;

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

import com.facepp.error.FaceppParseException;
import com.fukaimei.facerecognition.utils.FaceppDetect;

import android.content.Intent;
import android.content.pm.PackageManager;
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.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements OnClickListener {

    private ImageView mPhoto;
    private Button mDetect, mGetImg;
    private TextView mTip;
    private View mWaiting;

    private Canvas canvas;
    private Paint mPaint;
    private String mCurrentPhotoStr;
    private Bitmap mBitmapPhoto;
    private static final int PICK_CODE = 0x110;
    private static final int MSG_SUCCESS = 0x111;
    private static final int MSG_ERROR = 0x112;
    private Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_SUCCESS:
                    mWaiting.setVisibility(View.GONE);
                    JSONObject rs = (JSONObject) msg.obj;
                    prepareResultBitmap(rs);

                    mPhoto.setImageBitmap(mBitmapPhoto);

                    break;
                case MSG_ERROR:
                    mWaiting.setVisibility(View.GONE);
                    String errorMsg = (String) msg.obj;
                    if (TextUtils.isEmpty(errorMsg)) {
                        mTip.setText("Error.");
                    } else {
                        mTip.setText(errorMsg);
                    }
                    break;
            }
        }

    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 申請訪問SD卡的動態許可權
        sdPermissions();
        mPhoto = (ImageView) findViewById(R.id.id_photo);
        mDetect = (Button) findViewById(R.id.id_detect);
        mGetImg = (Button) findViewById(R.id.id_getImg);
        mTip = (TextView) findViewById(R.id.id_tip);
        mWaiting = findViewById(R.id.id_waiting);
        mDetect.setOnClickListener(this);
        mGetImg.setOnClickListener(this);
        mPaint = new Paint();
    }

    // 定義訪問SD卡的動態許可權
    private void sdPermissions() {
        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{
                    android.Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        }
    }

    /**
     * 重寫onRequestPermissionsResult方法
     * 獲取動態許可權請求的結果,再訪問SD卡
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

        } else {
            Toast.makeText(this, "使用者拒絕了許可權", Toast.LENGTH_SHORT).show();
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    private void prepareResultBitmap(JSONObject rs) {
        // TODO Auto-generated method stub
        Bitmap bitmap = Bitmap.createBitmap(mBitmapPhoto.getWidth(), mBitmapPhoto.getHeight(),
                mBitmapPhoto.getConfig());
        canvas = new Canvas(bitmap);
        canvas.drawBitmap(mBitmapPhoto, 0, 0, null);

        try {
            JSONArray faces = rs.getJSONArray("face");
            int faceCount = faces.length();
            mTip.setText("find " + faceCount);

            for (int i = 0; i < faceCount; i++) {
                // 拿到單獨face物件
                JSONObject face = faces.getJSONObject(i);
                JSONObject positonObj = face.getJSONObject("position");
                // get face position
                float x = (float) positonObj.getJSONObject("center").getDouble("x");
                float y = (float) positonObj.getJSONObject("center").getDouble("y");
                float w = (float) positonObj.getDouble("width");
                float h = (float) positonObj.getDouble("height");

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

                mPaint.setColor(0xffffffff);
                mPaint.setStrokeWidth(3);
                // draw 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);// 上

                // get age and gender
                int age = face.getJSONObject("attribute").getJSONObject("age").getInt("value");
                String gender = face.getJSONObject("attribute").getJSONObject("gender").getString("value");

                Bitmap ageBitmap = buildAgeBitmap(age, gender.equals("Male"));

                int ageWidth = ageBitmap.getWidth();
                int ageHeight = ageBitmap.getHeight();
                if(bitmap.getWidth()<=mPhoto.getWidth() && bitmap.getHeight()<=mPhoto.getHeight()){
                    float ratio = Math.max(bitmap.getWidth() * 1.0f / mPhoto.getWidth(),
                            bitmap.getHeight() * 1.0f / mPhoto.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);
                }
                mBitmapPhoto = bitmap;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    };

    private Bitmap buildAgeBitmap(int age, boolean isMale) {
        TextView tv = (TextView) mWaiting.findViewById(R.id.id_age_and_gender);
        tv.setText(age + "");
        if (isMale) {
            tv.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.male), null, null, null);
        } else {
            tv.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.female), null, null, null);
        }
        tv.setDrawingCacheEnabled(true);
        Bitmap bitmap = Bitmap.createBitmap(tv.getDrawingCache());
        tv.destroyDrawingCache();
        return bitmap;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (requestCode == PICK_CODE) {
            if (data != null) {
                Uri uri = data.getData();
                Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                cursor.moveToFirst();

                int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                mCurrentPhotoStr = cursor.getString(index);
                cursor.close();

                resizePhoto();
                mPhoto.setImageBitmap(mBitmapPhoto);
                mTip.setText("點選檢測 ==>");
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    private void resizePhoto() {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(mCurrentPhotoStr, options);

        double ratio = Math.max(options.outWidth * 1.0d / 1024f, options.outHeight * 1.0d / 1024f);
        options.inSampleSize = (int) Math.ceil(ratio);
        options.inJustDecodeBounds = false;

        mBitmapPhoto = BitmapFactory.decodeFile(mCurrentPhotoStr, options);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.id_getImg:
                Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType("image/*");
                startActivityForResult(intent, PICK_CODE);
                break;

            case R.id.id_detect:
                if (mBitmapPhoto != null && !mBitmapPhoto.isRecycled()) {
                    mWaiting.setVisibility(View.VISIBLE);
                    FaceppDetect.detect(mBitmapPhoto, new FaceppDetect.CallBack() {
                        @Override
                        public void success(JSONObject result) {
                            Message msg = mHandler.obtainMessage(MSG_SUCCESS);
                            msg.obj = result;
                            msg.sendToTarget();
                        }

                        @Override
                        public void error(FaceppParseException exception) {

                            Message msg = mHandler.obtainMessage(MSG_ERROR);
                            msg.obj = exception.getErrorMessage();
                            msg.sendToTarget();
                        }
                    });
                } else {
                    Toast.makeText(MainActivity.this, "請選擇您要檢測的人臉圖片", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
}
  • 然後在 Constant.java邏輯程式碼下新增在face++平臺申請到的APP_KEY碼和APP_SECRET碼如下:
package com.fukaimei.facerecognition;

public class Constant {

    public static final String APP_KEY = "填寫你申請到的APP_KEY碼";
    public static final String APP_SECRET = "填寫你申請到的APP_SECRET碼";
}
  • Demo程式執行效果介面截圖如下:

這裡寫圖片描述

相關推薦

Android移動開發-在Android專案整合face++人臉識別實現

“人工智慧”是今年比較火的一個名詞,甚至大多數人認為“人工智慧”是繼“IT網際網路”之後一個新的浪潮,將會是本世紀最高科技的水準。個人覺得,目前國內語音識別做的比較好的是科大訊飛,影象識別(或人臉識別)做的比較好的是face++(曠視)。 那麼,

Android開發-在Android專案整合友盟統計SDK進行對移動APP統計的實現

前 言 友盟(Umeng),2010年4月在北京成立,是中國最專業、最有資料凝聚力的移動開發者服務平臺。友盟以移動應用統計分析為產品起點,發展成為提供從基礎設定搭建-開發-運營服務的整合服務平臺,致力於為移動開發者提供專業的資料統計分析、開發和運營元件

Android移動開發-在Android專案整合呼叫微信支付開發實現

如今移動支付比較火,尤其是在中國的市場。移動支付也稱為手機支付,就是允許使用者使用其移動終端(通常是手機)對所消費的商品或服務進行賬務支付的一種服務方式。單位或個人通過移動裝置、網際網路或者近距離感測直接或間接向銀行金融機構傳送支付指令產生貨幣支付與資金轉

Android移動開發-在Android應用整合QQ分享的實現

QQ分享分為QQ好友分享與QQ空間分享同屬QQ互聯平臺上的QQ分享,該QQ互聯的網址為:https://connect.qq.com/ 。然後在該網址裡申請開發者應用id。 建立工程並配置工程 新建工程並匯入SDK的jar檔案(SDK

Face++人臉識別 android studio開發整合

最近幾年人臉識別被炒到了風口上,相對應的第三方平臺也比較多,如face++,科大訊飛,閱面科技,包括騰訊等等都有自己的人臉資料庫,以及開放的api介面,因為專案需要,因此需要在android平臺整合人臉檢測以及人臉識別技術,在此過程中也是踩了不少坑,在此,把我整合的步驟以及遇到的坑分享一下. 先

Android專案整合Cordova詳解

一 安裝node.js 安裝完成後,cmd執行 npm install -g cordova ,全域性安裝Cordova。 注意:可能會有點慢,請耐心等待! 二 cmd建立Android專案 1.新建一個專案: 路徑名>co

android移動開發的一點體會

協作開發 自動化 成了 省電 概率 很多 sim卡 體會 message 做手機的一點體會 整個android系統是一個完整的生態系統,谷歌提供開放的android平臺,下遊有各種生產硬件的廠家提供各種手機的硬件,像富士康這樣的工廠提供手機的代加工, 然後是高通這樣的公司提

Android移動開發01----用Android Studio進行開發

    一直以來都用Eclipse進行開發,但是最近發現Eclipse執行越來越緩慢,再加上自己的電腦已入暮年,時不時卡頓一下實在讓人受不了。在開發Ruby的時候接觸了RubyMine,一個基於IntelliJ IDEA的IDE,功能強大,速度比較快。於是決定拋棄Ecl

Android NDK開發 Android JNI專案建立

本篇文章只介紹android ndk在windows系統的編譯環境配置方法 更新於2015年1月11日 將更加詳細的介紹一個基本的Android Jni專案的建立。 步驟一:下圖是必須的,配置好這一步驟就可以進行Android JNI專案的建立了。 步驟二:新建一個Andr

Android移動開發檢測網路狀態並使用BroadcastReceiver(廣播接收者)進行接收網路變化的後續處理

在Android開發中,許多功能需要網路連線,所以在開發過程中需要進行手機網路的檢測。而每做一個App,就要進行檢測,那麼我直接將檢測網路狀態的功能封裝成一個類。 檢測網路狀態所需要的Api: ConnectivityManager主要用於檢視網路狀態和管理網路連線相關的

筆試面試-移動開發-Android 考點小結1

1.安卓的六大布局管理器是: LinearLayout、FrameLayout、TableLayout、RelativeLayout、AbsoluteLayout、GridLayout 2.SharedPreferences儲存檔案的路徑和副檔名是? /data/d

移動開發------Android WebView 基本使用

轉載於: http://blog.csdn.net/lowprofile_coding/article/details/77928614   WebView介紹 Android WebView在Android平臺上是一個特殊的View, 基於webkit引擎、展現

移動開發----android 中uri.parse()用法

android 中uri.parse()用法 //1,調web瀏覽器 Uri myBlogUri = Uri.parse("http://xxxxx.com"); returnIt = new Intent(Intent.ACTION_VIEW, myBlogUri); //2,地圖 U

移動開發----Android模仿打字機效果的自定義View實現

前言   在做splash介面的時候,需要做類似於打字機打字的效果,字一個一個地蹦出來,顯示每一個字都帶有打字的聲音。 效果演示 實現原理:   這個其實不難實現,通過一個定時器不斷呼叫TextView的setText就行了,在setTex

移動開發----Android開發者網址導航

官網 Android Developer Android Training 中文版 Android API中文版 Android API指南中文版 Android設計指南中文版 Material Design中文版 Android D

移動開發----Android判斷螢幕鎖屏的方法

由於做一個專案,需要判斷螢幕是否鎖屏,發現網上方法很多,但是比較雜,現在進行總結一下: 總共有兩類方法: 一、程式碼直接判定 二、接收廣播 現在先說第一類方法(程式碼直接判定): 1、通過PowerManager的isScreenOn方法,程式碼如下: [java] view plain co

Android移動開發中通用技術整理

悲劇的住院了,閒來無聊。整理下以前做的幾個專案的寫下的筆記。 因為專案的通用性,以前老大給的建議是能做成類似於封裝完的jar包。 因為沒什麼時間,還有老大太高估我了 = =。 在此只是列一下幾個通用技術 通用技術一:App進入後的網路檢測。 程式碼很簡單 import a

Android移動開發-檢測點選按鍵事件的實現

檢測點選按鍵事件一般不對手機上的輸入按鍵進行處理,直接由系統按照預設情況操作。當然有時為了改善使用者體驗,需要讓應用攔截按鍵事件,並進行額外處理。 要想監控按鍵事件,首先得知道每個按鍵的編碼,這樣才能根據不同的編碼值進行相應的處理。監聽器OnKeyL

Android移動開發-使用URLConnection提交請求的實現

URL的openConnection()方法將返回一個URLConnection物件,該物件表示應用程式和URL之間的通訊連線。程式可以通過URLConnection例項向該URL傳送請求,讀取URL引用的資源。 通常建立一個和URL的連線,併發

Android移動開發-藍芽(BlueTooth)裝置檢測連線的實現

無論是WIFI還是4G網路,建立網路連線後都是訪問網際網路資源,並不能直接訪問區域網資源。比如兩個人在一起,A要把手機上的視訊傳給B,通常情況是開啟手機QQ,通過QQ傳送檔案給對方。不過上傳視訊很耗流量,如果現場沒有可用的WIFI,手機的資料流量又不足,那