本项目采用了百度AI 人脸识别 第三方接口,实现了自选本地手机相册图片上传人脸(faceSet中添加人脸) 和 自选本地手机相册图片寻找出集合中相似度最高的一个face,可返回比对相似度、位置等信息。

目前百度向个人开发者提供了免费人脸识别接口,QPS限制为2,企业认证后并发数可增至 5,个人测试还是没问题的。

项目具体步骤如下:

一 、所需权限

    <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

项目采用了百度AI 第三方接口,可自行注册获取

三、添加依赖和sdk

  1. http 工具类

     
  2. Base64 工具类
     

  以上是实现的Base64的加密算法,使用自带 Base64.encodeToString(); 方法也可以。

  Base64原理可参考这篇博文:http://www.cnblogs.com/jxust-jiege666/p/8590116.html

四、获取token

主要代码:

 

注意:access_token的有效期为30天,切记需要每30天进行定期更换,或者每次请求都拉取新token;

五、添加人脸

  在1:n 对比搜索前,首先要向创建的face组内添加face (另外百度也提供了后台添加加人脸,可登录控制台创建组和添加人脸),主要代码如下:

 public static String identify(byte[] imgData,byte[] imgData2,String groupid,String accessToken) {
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/face/v2/identify";
try {
// 本地文件路径
String imgStr = Base64Util.encode(imgData);
String imgParam = URLEncoder.encode(imgStr, "UTF-8"); String imgStr2 = Base64Util.encode(imgData2);
String imgParam2 = URLEncoder.encode(imgStr2, "UTF-8"); String param = "group_id=" + groupid + "&user_top_num=" + "1" + "&face_top_num=" + "1" + "&images=" + imgParam + "," + imgParam2; // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 String result = HttpUtil.post(url, accessToken, param);
System.out.println(result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

其中groupid是你之前创建的组的id,user_top_num 是要返回相似度最高的人的个数,face_top_num是返回相似度最高人的face个数。一个人可以添加多个face,该项目为每个人添加了两个face。

六、寻找人脸

主要代码:

 /**
* 人脸查找——识别
*/
public class Identify { /**
* 重要提示代码中所需工具类
* FileUtil,Base64Util,HttpUtil,GsonUtils请从
* https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
* https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
* https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
* https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
* 下载
*/
public static String identify(byte[] imgData,byte[] imgData2,String groupid,String accessToken) {
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/face/v2/identify";
try { String imgStr = Base64Util.encode(imgData);
String imgParam = URLEncoder.encode(imgStr, "UTF-8"); String imgStr2 = Base64Util.encode(imgData2);
String imgParam2 = URLEncoder.encode(imgStr2, "UTF-8"); String param = "group_id=" + groupid + "&user_top_num=" + "1" + "&face_top_num=" + "1" + "&images=" + imgParam + "," + imgParam2; // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。 String result = HttpUtil.post(url, accessToken, param);
System.out.println(result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

七、页面activity

主要代码:

 import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast; import com.example.lifen.baidufacesearchdemo.utils.AuthService;
import com.example.lifen.baidufacesearchdemo.utils.Base64Util;
import com.example.lifen.baidufacesearchdemo.utils.FaceAdd;
import com.example.lifen.baidufacesearchdemo.utils.Identify; import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException; /**
* 人脸寻找 fase集合中寻找最相似(1 或 多)的face
*
* @author LiFen
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int REQUEST_CODE1 = 11;
ImageView mImageView1;
Button mSearchBtn;
private Button mAddFaceBtn;
TextView mResultText;
private TextView mAddResultText;
private byte[] mImg1;
private EditText uidEidtText;
private EditText mInforEidtText;
String key = "";//api_key
String secret ="";//api_secret
private final static int i = 100;
private final static int j = 200;
private final static int s = 300;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == i){
mAddResultText.setText((String)msg.obj);
}
if(msg.what == j){
mAddResultText.append((String)msg.obj);
}
if(msg.what == s){
mResultText.setText((String)msg.obj);
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mImageView1 = (ImageView) findViewById(R.id.img1);
mSearchBtn = (Button) findViewById(R.id.searchBtn);
mAddFaceBtn = (Button)findViewById(R.id.addFaceBtn);
mResultText = (TextView) findViewById(R.id.resultBtn);
mAddResultText = (TextView)findViewById(R.id.addRresultTV);
uidEidtText = (EditText)findViewById(R.id.uidEt);
mInforEidtText = (EditText)findViewById(R.id.inforEt);
if(TextUtils.isEmpty(key) || TextUtils.isEmpty(secret)){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("please enter key and secret");
builder.setTitle("");
builder.show();
return;
}
mImageView1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startAlbumActivity(REQUEST_CODE1);
}
});
mAddFaceBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addFace();
}
});
mSearchBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startSearch();
}
});
} private void addFace(){
if ("".equals(mImg1) || mImg1 == null) {
Toast.makeText(this, "请选择图片再添加", Toast.LENGTH_SHORT).show();
return;
}
if(uidEidtText.getText().toString().equals("")){
Toast.makeText(this,"请输入uid(名字)",Toast.LENGTH_SHORT).show();
return;
}
mAddResultText.setText("人脸添加中...");
new Thread(new Runnable() {
@Override
public void run() {
String accessToken = AuthService.getAuth(key, secret);
Log.i(TAG, "accessToken:" + accessToken);
Message msg1 = new Message();
msg1.what = i;
msg1.obj = accessToken;
handler.sendMessage(msg1); String uid = uidEidtText.getText().toString();
String infor = mInforEidtText.getText().toString();
String encode = Base64Util.encode(infor.getBytes());
Log.i(TAG, "infor: " + encode);
/*String inforUtf = new String(Base64.decode(encode, Base64.DEFAULT));
Log.i(TAG, "infor: " + inforUtf);*/
String add = FaceAdd.add(mImg1, mImg1, uid,encode,"test",accessToken);
Log.i(TAG, "addFace: " + add);
Message msg2 = new Message();
msg2.what = j;
msg2.obj = add;
handler.sendMessage(msg2);
}
}).start();
} private void startSearch() {
if ("".equals(mImg1) || mImg1 == null) {
Toast.makeText(this, "请选择图片再寻找", Toast.LENGTH_SHORT).show();
return;
}
mResultText.setText("搜索比对中...");
new Thread(new Runnable() {
@Override
public void run() {
String accessToken = AuthService.getAuth(key, secret);
Log.i(TAG, "accessToken:" + accessToken);
String result = Identify.identify(mImg1, mImg1, "test", accessToken);
Log.i(TAG, "result" + result);
Message msg3 = new Message();
msg3.what = s;
msg3.obj = result;
handler.sendMessage(msg3);
}
}).start();
} private void startAlbumActivity(int requestCode) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, requestCode);
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data == null)
return;
Uri uri = data.getData();
Log.e("uri", uri.toString());
ContentResolver cr = this.getContentResolver();
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
/* 将Bitmap设定到ImageView */
} catch (FileNotFoundException e) {
Log.e("Exception", e.getMessage(), e);
}
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE1) {
mImageView1.setImageBitmap(bitmap);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] datas = baos.toByteArray();
mImg1 = datas;
}
super.onActivityResult(requestCode, resultCode, data);
}
}

八、布局文件

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. 点击寻找按钮

 <?xml version="1.0" encoding="utf-8"?>
<ScrollView
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="com.example.lifen.baidufacesearchdemo.MainActivity"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <ImageView
android:id="@+id/img1"
android:layout_width="0dp"
android:layout_height="180dp"
android:layout_weight="1.02"
android:scaleType="centerCrop"
android:src="@drawable/head"/> <ScrollView
android:layout_weight="0.74"
android:layout_width="60dp"
android:layout_height="match_parent">
<TextView
android:id="@+id/addRresultTV"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="添加结果"
android:textColor="@android:color/black" />
</ScrollView> </LinearLayout> <EditText
android:id="@+id/uidEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="请输入uid(字母、数字、下划线)"
android:inputType="textCapCharacters" /> <EditText
android:id="@+id/inforEt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="人脸关联的其他信息"
android:inputType="textPersonName" /> <Button
android:id="@+id/addFaceBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加" /> <Button
android:id="@+id/searchBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_horizontal_margin"
android:text="寻找" /> <TextView
android:id="@+id/resultBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_horizontal_margin"
android:background="#eeeeee"
android:padding="6dp"
android:layout_weight="2.94" /> </LinearLayout>
</ScrollView>

项目地址:https://download.csdn.net/download/qq_36726507/10295388

人脸识别1:n对比 (二)的更多相关文章

  1. 基于Python与命令行人脸识别项目(系列二)

    接着系统一,继续开始我们face_recognition. Python 模块:face_recognition 在Python中,你可以导入face_recognition模块,调用丰富的API接口 ...

  2. Android 虹软人脸识别SDK-人脸对比

    准备 : 登录官方网站,获取SDK,进行个人验证后新建项目,获取APP_ID,和SDK_KEY: https://ai.arcsoft.com.cn/ucenter/resource/build/in ...

  3. 转:基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】

    文章来自于:http://blog.renren.com/share/246648717/8171467499 基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴 ...

  4. TensorFlow人脸识别

    TensorFlow框架做实时人脸识别小项目(一)https://blog.csdn.net/Goerge_L/article/details/80208297 TensorFlow框架做实时人脸识别 ...

  5. iOS 使用百度的人脸识别登录验证,解决认证失败不跳转界面连续认证,认证相似度对比

    在使用百度人脸识别出现的问题:小米6调用摄像机是黑白的一个情况,iOS上会出现识别准确性上的问题(多次代开认证,会通过) 人脸识别(活体验证): 1.芝麻认证 : 0.4元/次,需要企业企业认证.不能 ...

  6. 人脸识别1:n对比 (一)

    本项目采用了 Face++人脸识别 第三方接口,实现了自选本地手机相册图片上传人脸(faceSet中添加人脸) 和 自选本地手机相册图片寻找出集合中相似度最高的一个face,可返回比对相似度等信息. ...

  7. 人脸识别经典算法二:LBP方法

    与第一篇博文特征脸方法不同,LBP(Local Binary Patterns,局部二值模式)是提取局部特征作为判别依据的.LBP方法显著的优点是对光照不敏感,但是依然没有解决姿态和表情的问题.不过相 ...

  8. ArcFace虹软与Dlib人脸识别对比

    我司最近要做和人脸识别相关的产品,原来使用的是其他的在线平台,识别率和识别速度很满意,但是随着量起来的话,成本也是越来越不能接受(目前该功能我们是免费给用户使用的),而且一旦我们的设备掉线了就无法使用 ...

  9. 项目总结二:人脸识别项目(Face Recognition for the Happy House)

    一.人脸验证问题(face verification)与人脸识别问题(face recognition) 1.人脸验证问题(face verification):           输入       ...

随机推荐

  1. Python多线程实例

    前言 感觉理解python多线程用“切换”和“共享”就差不多了.这里就贴上一个抢车票的小小实例,还有自己在编程过程中遇到的坑..... 实例:抢车票 抢车票有三类人:会员.弄了加速包.普通人. 说说区 ...

  2. Android 开发 Activity里获取View的宽度和高度 转载

    原文地址:https://blog.csdn.net/chenbaige/article/details/77991594 前言: 可能很多情况下,我们都会有在activity中获取view 的尺寸大 ...

  3. Android 开发 使用javax.mail发送邮件。

    简介 sun公司开源的邮件发送工具. 依赖 implementation 'com.sun.mail:android-mail:1.6.0' implementation 'com.sun.mail: ...

  4. Python2--Pytest_html测试报告优化(解决中文输出问题)

    1.报告的输出: pytest.main(["-s","Auto_test.py","--html=Result_test.html"]) ...

  5. mybatis学习 -每天一记 mybatis insert null 报错

    mybatis 插入数据,model的属性存在null,插入报错 在使用mybatis 进行insert时,如果字段值存在null的情况,会出现插入失败的情况,解决方案: 如果使用spring boo ...

  6. @Data的注解使用以及在IDEA上安装

    平时在开发过程中创建实体类的时候就经常的操作是:先写成员变量,然后再提供getXxx().setXxx()方法,然后看需要再提供toString等方法.这样一来不仅会发现每写一个实体类的话就会有很多相 ...

  7. django之缓存的用法, 文件形式与 redis的基本使用

    django的缓存的用法讲解 1. django缓存: 缓存的机制出现主要是缓解了数据库的压力而存在的 2. 动态网站中,用户的请求都会去数据库中进行相应的操作,缓存的出现是提高了网站的并发量 3. ...

  8. ---mipi command

    可惜这是5.1系统: http://www.cnblogs.com/lialong1st/p/8534728.html

  9. 【转】BFG Repo-Cleaner: Removes large or troublesome blobs like git-filter-branch does, but faster.

    https://rtyley.github.io/bfg-repo-cleaner/ an alternative to git-filter-branch The BFG is a simpler, ...

  10. jQuery之遍历索引相关方法

    遍历索引相关方法: .each(),补充.children() .index() 1 .each() 2..children() .index()