本项目采用了 Face++人脸识别 第三方接口,实现了自选本地手机相册图片上传人脸(faceSet中添加人脸) 和 自选本地手机相册图片寻找出集合中相似度最高的一个face,可返回比对相似度等信息。
项目具体步骤如下:
一 、所需权限
<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"/>
二、第三方app id app key
项目采用了Face++第三方接口,可自行注册获取
三、添加依赖和sdk
1. 将FaceppSDK.jar文件放到libs路径下。
2. gradle中添加一下依赖:
//导入sdk
compile files('libs/FaceppSDK.jar')
四、布局文件
人脸寻找1:n
主要代码:
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.facesearchdemo.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="textPersonName" /> 54 55 <Button 56 android:id="@+id/addFaceBtn" 57 android:layout_width="match_parent" 58 android:layout_height="wrap_content" 59 android:text="添加" /> 60 61 <Button 62 android:id="@+id/searchBtn" 63 android:layout_width="match_parent" 64 android:layout_height="wrap_content" 65 android:layout_marginTop="@dimen/activity_horizontal_margin" 66 android:text="寻找" /> 67 68 <TextView 69 android:id="@+id/resultBtn" 70 android:layout_width="match_parent" 71 android:layout_height="wrap_content" 72 android:layout_marginTop="@dimen/activity_horizontal_margin" 73 android:background="#eeeeee" 74 android:padding="6dp" 75 android:layout_weight="2.94" /> 76 77 </LinearLayout> 78 </ScrollView>
页面包含:
① ImageView 点击ImageView 可跳转手机相册,选择要使用的图片。
② TextView1 faceSet添加face 结果再次显示
③ EditText 设定face 的user_uid
④ button1 添加人脸按钮
⑤ button2 寻找相似度最高人脸按钮
⑥ TextView2 寻找结果展示view
faceSet 中添加 face过程:
1. 点击imageView 选取图片
2. 输入uid
3. 点击添加
寻找相似度最高face过程:
1.点击imageView 选取图片
2. 点击寻找按钮
五、页面activity
主要代码:
1 package com.example.lifen.facesearchdemo; 2 3 import android.content.ContentResolver; 4 import android.content.Intent; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapFactory; 7 import android.net.Uri; 8 import android.os.Bundle; 9 import android.os.Handler; 10 import android.os.Message; 11 import android.support.v7.app.AlertDialog; 12 import android.support.v7.app.AppCompatActivity; 13 import android.text.TextUtils; 14 import android.util.Base64; 15 import android.util.Log; 16 import android.view.View; 17 import android.widget.Button; 18 import android.widget.EditText; 19 import android.widget.ImageView; 20 import android.widget.TextView; 21 import android.widget.Toast; 22 23 import com.megvii.cloud.http.CommonOperate; 24 import com.megvii.cloud.http.FaceOperate; 25 import com.megvii.cloud.http.FaceSetOperate; 26 import com.megvii.cloud.http.Response; 27 28 import org.json.JSONException; 29 import org.json.JSONObject; 30 31 import java.io.ByteArrayOutputStream; 32 import java.io.FileNotFoundException; 33 import java.util.ArrayList; 34 35 /** 36 * 人脸对比 1:1 37 * 38 * @author LiFen 39 */ 40 public class MainActivity extends AppCompatActivity { 41 private static final String TAG = "MainActivity"; 42 private static final int REQUEST_CODE1 = 11; 43 ImageView mImageView1; 44 Button mSearchBtn; 45 private Button mAddFaceBtn; 46 TextView mResultText; 47 private TextView mAddResultText; 48 private String mImgBase641; 49 private EditText uidEidtText; 50 ArrayList<String> faces = new ArrayList<>(); 51 String key = "";//api_key 52 String secret = "";//api_secret 53 private final static int i = 100; 54 private final static int j = 200; 55 private final static int s = 300; 56 private Handler handler = new Handler(){ 57 @Override 58 public void handleMessage(Message msg) { 59 if(msg.what == i){ 60 mAddResultText.setText((String)msg.obj); 61 } 62 if(msg.what == j){ 63 mAddResultText.append((String)msg.obj); 64 } 65 if(msg.what == s){ 66 mResultText.setText((String)msg.obj); 67 } 68 } 69 }; 70 71 @Override 72 protected void onCreate(Bundle savedInstanceState) { 73 super.onCreate(savedInstanceState); 74 setContentView(R.layout.activity_main); 75 76 mImageView1 = (ImageView) findViewById(R.id.img1); 77 mSearchBtn = (Button) findViewById(R.id.searchBtn); 78 mAddFaceBtn = (Button)findViewById(R.id.addFaceBtn); 79 mResultText = (TextView) findViewById(R.id.resultBtn); 80 mAddResultText = (TextView)findViewById(R.id.addRresultTV); 81 uidEidtText = (EditText)findViewById(R.id.uidEt); 82 if(TextUtils.isEmpty(key) || TextUtils.isEmpty(secret)){ 83 AlertDialog.Builder builder = new AlertDialog.Builder(this); 84 builder.setMessage("please enter key and secret"); 85 builder.setTitle(""); 86 builder.show(); 87 return; 88 } 89 mImageView1.setOnClickListener(new View.OnClickListener() { 90 @Override 91 public void onClick(View v) { 92 startAlbumActivity(REQUEST_CODE1); 93 } 94 }); 95 mAddFaceBtn.setOnClickListener(new View.OnClickListener() { 96 @Override 97 public void onClick(View v) { 98 addFace(); 99 } 100 }); 101 mSearchBtn.setOnClickListener(new View.OnClickListener() { 102 @Override 103 public void onClick(View v) { 104 startSearch(); 105 } 106 }); 107 } 108 109 private void addFace(){ 110 if ("".equals(mImgBase641) || mImgBase641 == null) { 111 Toast.makeText(this, "请选择图片再添加", Toast.LENGTH_SHORT).show(); 112 return; 113 } 114 if(uidEidtText.getText().toString().equals("")){ 115 Toast.makeText(this,"请输入uid(名字)",Toast.LENGTH_SHORT).show(); 116 return; 117 } 118 mResultText.setText("人脸添加中..."); 119 new Thread(new Runnable() { 120 @Override 121 public void run() { 122 CommonOperate commonOperate = new CommonOperate(key, secret, false); 123 try{ 124 //获取faceToken 125 Response response = commonOperate.detectBase64(mImgBase641, 0, null); 126 FaceOperate faceOperate = new FaceOperate(key,secret,false); 127 String faceToken = getFaceToken(response); 128 String uid = uidEidtText.getText().toString(); 129 Log.i(TAG, "run: " + uid); 130 faceOperate.faceSetUserId(faceToken, uid); 131 faces.add(faceToken); 132 Message msg = new Message(); 133 msg.what = i; 134 msg.obj = faceToken; 135 handler.sendMessage(msg); 136 //faceSet中添加faceToken 137 FaceSetOperate FaceSet = new FaceSetOperate(key, secret, false); 138 String faceTokens = creatFaceTokens(faces); 139 Response faceSet = FaceSet.addFaceByFaceToken(faceTokens, "469e42d27947506b44cee9a8dba2eb4f"); 140 String result = new String(faceSet.getContent()); 141 msg.what = j; 142 msg.obj = result; 143 handler.sendMessage(msg); 144 }catch (Exception e){ 145 Log.i(TAG, "addFace: " +e.toString()); 146 } 147 } 148 }).start(); 149 } 150 151 private void startSearch() { 152 if ("".equals(mImgBase641) || mImgBase641 == null) { 153 Toast.makeText(this, "请选择图片再寻找", Toast.LENGTH_SHORT).show(); 154 return; 155 } 156 mResultText.setText("搜索比对中..."); 157 new Thread(new Runnable() { 158 @Override 159 public void run() { 160 Log.i(TAG, "run() called"); 161 CommonOperate commonOperate = new CommonOperate(key, secret, false); 162 //获取faceToken 163 Response response = null; 164 try { 165 response = commonOperate.detectBase64(mImgBase641, 0, null); 166 String faceToken = getFaceToken(response); 167 Response searchByOuterId = commonOperate.searchByOuterId(faceToken, null, null, "test", 1); 168 Message msg = new Message(); 169 msg.what = s; 170 String result = new String(searchByOuterId.getContent()); 171 msg.obj = result; 172 handler.sendMessage(msg); 173 } catch (Exception e) { 174 e.printStackTrace(); 175 } 176 } 177 }).start(); 178 } 179 180 private void startAlbumActivity(int requestCode) { 181 Intent intent = new Intent(); 182 intent.setType("image/*"); 183 intent.setAction(Intent.ACTION_GET_CONTENT); 184 startActivityForResult(intent, requestCode); 185 } 186 187 @Override 188 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 189 if (data == null) 190 return; 191 Uri uri = data.getData(); 192 Log.e("uri", uri.toString()); 193 ContentResolver cr = this.getContentResolver(); 194 Bitmap bitmap = null; 195 try { 196 bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri)); 197 /* 将Bitmap设定到ImageView */ 198 } catch (FileNotFoundException e) { 199 Log.e("Exception", e.getMessage(), e); 200 } 201 if (resultCode == RESULT_OK && requestCode == REQUEST_CODE1) { 202 mImageView1.setImageBitmap(bitmap); 203 mImgBase641 = bitmapToBase64(bitmap); 204 } 205 super.onActivityResult(requestCode, resultCode, data); 206 } 207 208 private String bitmapToBase64(Bitmap bitmap) { 209 ByteArrayOutputStream bStream = new ByteArrayOutputStream(); 210 bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bStream); 211 return Base64.encodeToString(bStream.toByteArray(), 0); 212 } 213 214 private String getFaceToken(Response response) throws JSONException { 215 if(response.getStatus() != 200){ 216 return new String(response.getContent()); 217 } 218 String res = new String(response.getContent()); 219 Log.e("response", res); 220 JSONObject json = new JSONObject(res); 221 String faceToken = json.optJSONArray("faces").optJSONObject(0).optString("face_token"); 222 return faceToken; 223 } 224 225 private String creatFaceTokens(ArrayList<String> faceTokens){ 226 if(faceTokens == null || faceTokens.size() == 0){ 227 return ""; 228 } 229 StringBuffer face = new StringBuffer(); 230 for (int i = 0; i < faceTokens.size(); i++){ 231 if(i == 0){ 232 face.append(faceTokens.get(i)); 233 }else{ 234 face.append(","); 235 face.append(faceTokens.get(i)); 236 } 237 } 238 return face.toString(); 239 } 240 }
其中key 和 secret 可自行注册填入。本项目之前已经创建了faceSet,创建过程可参考:https://download.csdn.net/download/qq_36726507/10293566
注意:uid 不超过255个字符,不能包括^@,&=*'",不可使用中文(用中文挂掉好几次)。
项目地址:https://download.csdn.net/download/qq_36726507/10293600