本項目採用了百度AI 人臉識別 第三方接口,實現了自選本地手機相冊圖片上傳人臉(faceSet中添加人臉) 和 自選本地手機相冊圖片尋找出集合中類似度最高的一個face,可返回比對類似度、位置等信息。 html
目前百度向我的開發者提供了免費人臉識別接口,QPS限制爲2,企業認證後併發數可增至 5,我的測試仍是沒問題的。java
項目具體步驟以下:android
一 、所需權限算法
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
2、第三方app id app keyapi
項目採用了百度AI 第三方接口,可自行註冊獲取緩存
3、添加依賴和sdk服務器
以上是實現的Base64的加密算法,使用自帶 Base64.encodeToString(); 方法也能夠。併發
Base64原理可參考這篇博文:http://www.cnblogs.com/jxust-jiege666/p/8590116.htmlapp
4、獲取tokenide
主要代碼:
注意:
access_token
的有效期爲30天,切記須要每30天進行按期更換,或者每次請求都拉取新token;
5、添加人臉
在1:n 對比搜索前,首先要向建立的face組內添加face (另外百度也提供了後臺添加加人臉,可登陸控制檯建立組和添加人臉),主要代碼以下:
1 public static String identify(byte[] imgData,byte[] imgData2,String groupid,String accessToken) { 2 // 請求url 3 String url = "https://aip.baidubce.com/rest/2.0/face/v2/identify"; 4 try { 5 // 本地文件路徑 6 String imgStr = Base64Util.encode(imgData); 7 String imgParam = URLEncoder.encode(imgStr, "UTF-8"); 8 9 String imgStr2 = Base64Util.encode(imgData2); 10 String imgParam2 = URLEncoder.encode(imgStr2, "UTF-8"); 11 12 String param = "group_id=" + groupid + "&user_top_num=" + "1" + "&face_top_num=" + "1" + "&images=" + imgParam + "," + imgParam2; 13 14 // 注意這裏僅爲了簡化編碼每一次請求都去獲取access_token,線上環境access_token有過時時間, 客戶端可自行緩存,過時後從新獲取。 15 16 String result = HttpUtil.post(url, accessToken, param); 17 System.out.println(result); 18 return result; 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 return null; 23 } 24 }
其中groupid是你以前建立的組的id,user_top_num 是要返回類似度最高的人的個數,face_top_num是返回類似度最高人的face個數。一我的能夠添加多個face,該項目爲每一個人添加了兩個face。
6、尋找人臉
主要代碼:
1 /** 2 * 人臉查找——識別 3 */ 4 public class Identify { 5 6 /** 7 * 重要提示代碼中所需工具類 8 * FileUtil,Base64Util,HttpUtil,GsonUtils請從 9 * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72 10 * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2 11 * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3 12 * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3 13 * 下載 14 */ 15 public static String identify(byte[] imgData,byte[] imgData2,String groupid,String accessToken) { 16 // 請求url 17 String url = "https://aip.baidubce.com/rest/2.0/face/v2/identify"; 18 try { 19 20 String imgStr = Base64Util.encode(imgData); 21 String imgParam = URLEncoder.encode(imgStr, "UTF-8"); 22 23 String imgStr2 = Base64Util.encode(imgData2); 24 String imgParam2 = URLEncoder.encode(imgStr2, "UTF-8"); 25 26 String param = "group_id=" + groupid + "&user_top_num=" + "1" + "&face_top_num=" + "1" + "&images=" + imgParam + "," + imgParam2; 27 28 // 注意這裏僅爲了簡化編碼每一次請求都去獲取access_token,線上環境access_token有過時時間, 客戶端可自行緩存,過時後從新獲取。 29 30 String result = HttpUtil.post(url, accessToken, param); 31 System.out.println(result); 32 return result; 33 } catch (Exception e) { 34 e.printStackTrace(); 35 } 36 return null; 37 } 38 }
7、頁面activity
主要代碼:
1 import android.content.ContentResolver; 2 import android.content.Intent; 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.net.Uri; 6 import android.os.Bundle; 7 import android.os.Handler; 8 import android.os.Message; 9 import android.support.v7.app.AlertDialog; 10 import android.support.v7.app.AppCompatActivity; 11 import android.text.TextUtils; 12 import android.util.Log; 13 import android.view.View; 14 import android.widget.Button; 15 import android.widget.EditText; 16 import android.widget.ImageView; 17 import android.widget.TextView; 18 import android.widget.Toast; 19 20 import com.example.lifen.baidufacesearchdemo.utils.AuthService; 21 import com.example.lifen.baidufacesearchdemo.utils.Base64Util; 22 import com.example.lifen.baidufacesearchdemo.utils.FaceAdd; 23 import com.example.lifen.baidufacesearchdemo.utils.Identify; 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.FileNotFoundException; 27 28 /** 29 * 人臉尋找 fase集合中尋找最類似(1 或 多)的face 30 * 31 * @author LiFen 32 */ 33 public class MainActivity extends AppCompatActivity { 34 private static final String TAG = "MainActivity"; 35 private static final int REQUEST_CODE1 = 11; 36 ImageView mImageView1; 37 Button mSearchBtn; 38 private Button mAddFaceBtn; 39 TextView mResultText; 40 private TextView mAddResultText; 41 private byte[] mImg1; 42 private EditText uidEidtText; 43 private EditText mInforEidtText; 44 String key = "";//api_key 45 String secret ="";//api_secret 46 private final static int i = 100; 47 private final static int j = 200; 48 private final static int s = 300; 49 private Handler handler = new Handler(){ 50 @Override 51 public void handleMessage(Message msg) { 52 if(msg.what == i){ 53 mAddResultText.setText((String)msg.obj); 54 } 55 if(msg.what == j){ 56 mAddResultText.append((String)msg.obj); 57 } 58 if(msg.what == s){ 59 mResultText.setText((String)msg.obj); 60 } 61 } 62 }; 63 64 @Override 65 protected void onCreate(Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 setContentView(R.layout.activity_main); 68 69 mImageView1 = (ImageView) findViewById(R.id.img1); 70 mSearchBtn = (Button) findViewById(R.id.searchBtn); 71 mAddFaceBtn = (Button)findViewById(R.id.addFaceBtn); 72 mResultText = (TextView) findViewById(R.id.resultBtn); 73 mAddResultText = (TextView)findViewById(R.id.addRresultTV); 74 uidEidtText = (EditText)findViewById(R.id.uidEt); 75 mInforEidtText = (EditText)findViewById(R.id.inforEt); 76 if(TextUtils.isEmpty(key) || TextUtils.isEmpty(secret)){ 77 AlertDialog.Builder builder = new AlertDialog.Builder(this); 78 builder.setMessage("please enter key and secret"); 79 builder.setTitle(""); 80 builder.show(); 81 return; 82 } 83 mImageView1.setOnClickListener(new View.OnClickListener() { 84 @Override 85 public void onClick(View v) { 86 startAlbumActivity(REQUEST_CODE1); 87 } 88 }); 89 mAddFaceBtn.setOnClickListener(new View.OnClickListener() { 90 @Override 91 public void onClick(View v) { 92 addFace(); 93 } 94 }); 95 mSearchBtn.setOnClickListener(new View.OnClickListener() { 96 @Override 97 public void onClick(View v) { 98 startSearch(); 99 } 100 }); 101 } 102 103 private void addFace(){ 104 if ("".equals(mImg1) || mImg1 == null) { 105 Toast.makeText(this, "請選擇圖片再添加", Toast.LENGTH_SHORT).show(); 106 return; 107 } 108 if(uidEidtText.getText().toString().equals("")){ 109 Toast.makeText(this,"請輸入uid(名字)",Toast.LENGTH_SHORT).show(); 110 return; 111 } 112 mAddResultText.setText("人臉添加中..."); 113 new Thread(new Runnable() { 114 @Override 115 public void run() { 116 String accessToken = AuthService.getAuth(key, secret); 117 Log.i(TAG, "accessToken:" + accessToken); 118 Message msg1 = new Message(); 119 msg1.what = i; 120 msg1.obj = accessToken; 121 handler.sendMessage(msg1); 122 123 String uid = uidEidtText.getText().toString(); 124 String infor = mInforEidtText.getText().toString(); 125 String encode = Base64Util.encode(infor.getBytes()); 126 Log.i(TAG, "infor: " + encode); 127 /*String inforUtf = new String(Base64.decode(encode, Base64.DEFAULT)); 128 Log.i(TAG, "infor: " + inforUtf);*/ 129 String add = FaceAdd.add(mImg1, mImg1, uid,encode,"test",accessToken); 130 Log.i(TAG, "addFace: " + add); 131 Message msg2 = new Message(); 132 msg2.what = j; 133 msg2.obj = add; 134 handler.sendMessage(msg2); 135 } 136 }).start(); 137 } 138 139 private void startSearch() { 140 if ("".equals(mImg1) || mImg1 == null) { 141 Toast.makeText(this, "請選擇圖片再尋找", Toast.LENGTH_SHORT).show(); 142 return; 143 } 144 mResultText.setText("搜索比對中..."); 145 new Thread(new Runnable() { 146 @Override 147 public void run() { 148 String accessToken = AuthService.getAuth(key, secret); 149 Log.i(TAG, "accessToken:" + accessToken); 150 String result = Identify.identify(mImg1, mImg1, "test", accessToken); 151 Log.i(TAG, "result" + result); 152 Message msg3 = new Message(); 153 msg3.what = s; 154 msg3.obj = result; 155 handler.sendMessage(msg3); 156 } 157 }).start(); 158 } 159 160 private void startAlbumActivity(int requestCode) { 161 Intent intent = new Intent(); 162 intent.setType("image/*"); 163 intent.setAction(Intent.ACTION_GET_CONTENT); 164 startActivityForResult(intent, requestCode); 165 } 166 167 @Override 168 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 169 if (data == null) 170 return; 171 Uri uri = data.getData(); 172 Log.e("uri", uri.toString()); 173 ContentResolver cr = this.getContentResolver(); 174 Bitmap bitmap = null; 175 try { 176 bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri)); 177 /* 將Bitmap設定到ImageView */ 178 } catch (FileNotFoundException e) { 179 Log.e("Exception", e.getMessage(), e); 180 } 181 if (resultCode == RESULT_OK && requestCode == REQUEST_CODE1) { 182 mImageView1.setImageBitmap(bitmap); 183 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 184 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); 185 byte[] datas = baos.toByteArray(); 186 mImg1 = datas; 187 } 188 super.onActivityResult(requestCode, resultCode, data); 189 } 190 }
8、佈局文件
1:n 尋找
頁面包含:
① ImageView 點擊ImageView 可跳轉手機相冊,選擇要使用的圖片。
② TextView1 faceSet添加face 結果再次顯示
③ EditText 設定face 的user_uid
④ button1 添加人臉按鈕
⑤ button2 尋找類似度最高人臉按鈕
⑥ TextView2 尋找結果展現view
faceSet 中添加 face過程:
1. 點擊imageView 選取圖片
2. 輸入uid
3. 添加face關聯的信息(這裏我Base64編碼後上傳的服務器,使用時可自行解碼)
4. 點擊添加按鈕添加
尋找類似度最高face過程:
1.點擊imageView 選取圖片
2. 點擊尋找按鈕
1 <?xml version="1.0" encoding="utf-8"?> 2 <ScrollView 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:paddingBottom="@dimen/activity_vertical_margin" 8 android:paddingLeft="@dimen/activity_horizontal_margin" 9 android:paddingRight="@dimen/activity_horizontal_margin" 10 android:paddingTop="@dimen/activity_vertical_margin" 11 tools:context="com.example.lifen.baidufacesearchdemo.MainActivity"> 12 13 <LinearLayout 14 android:layout_width="match_parent" 15 android:layout_height="match_parent" 16 android:orientation="vertical" 17 android:weightSum="1"> 18 19 <LinearLayout 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content" 22 android:orientation="horizontal"> 23 24 <ImageView 25 android:id="@+id/img1" 26 android:layout_width="0dp" 27 android:layout_height="180dp" 28 android:layout_weight="1.02" 29 android:scaleType="centerCrop" 30 android:src="@drawable/head"/> 31 32 <ScrollView 33 android:layout_weight="0.74" 34 android:layout_width="60dp" 35 android:layout_height="match_parent"> 36 <TextView 37 android:id="@+id/addRresultTV" 38 android:layout_width="match_parent" 39 android:layout_height="match_parent" 40 android:gravity="center" 41 android:text="添加結果" 42 android:textColor="@android:color/black" /> 43 </ScrollView> 44 45 </LinearLayout> 46 47 <EditText 48 android:id="@+id/uidEt" 49 android:layout_width="match_parent" 50 android:layout_height="wrap_content" 51 android:ems="10" 52 android:hint="請輸入uid(字母、數字、下劃線)" 53 android:inputType="textCapCharacters" /> 54 55 <EditText 56 android:id="@+id/inforEt" 57 android:layout_width="match_parent" 58 android:layout_height="wrap_content" 59 android:ems="10" 60 android:hint="人臉關聯的其餘信息" 61 android:inputType="textPersonName" /> 62 63 <Button 64 android:id="@+id/addFaceBtn" 65 android:layout_width="match_parent" 66 android:layout_height="wrap_content" 67 android:text="添加" /> 68 69 <Button 70 android:id="@+id/searchBtn" 71 android:layout_width="match_parent" 72 android:layout_height="wrap_content" 73 android:layout_marginTop="@dimen/activity_horizontal_margin" 74 android:text="尋找" /> 75 76 <TextView 77 android:id="@+id/resultBtn" 78 android:layout_width="match_parent" 79 android:layout_height="wrap_content" 80 android:layout_marginTop="@dimen/activity_horizontal_margin" 81 android:background="#eeeeee" 82 android:padding="6dp" 83 android:layout_weight="2.94" /> 84 85 </LinearLayout> 86 </ScrollView>
項目地址:https://download.csdn.net/download/qq_36726507/10295388