Android 虹软人脸识别SDK-人脸对比
Posted yangchaojie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 虹软人脸识别SDK-人脸对比相关的知识,希望对你有一定的参考价值。
准备 :
登录官方网站,获取SDK,进行个人验证后新建项目,获取APP_ID,和SDK_KEY;
https://ai.arcsoft.com.cn/ucenter/resource/build/index.html#/ucenter/resource/openPlatform/application
实现 :
激活引擎 :
/**
* 激活引擎
*
* @param view
*/
public void activeEngine(final View view)
if (!checkPermissions(NEEDED_PERMISSIONS))
ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);
return;
if (view != null)
view.setClickable(false);
Observable.create(new ObservableOnSubscribe<Integer>()
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception
FaceEngine faceEngine = new FaceEngine();
//申请的APP_ID 和SDK_key
int activeCode = faceEngine.active(FaceMainActivity.this, Constants.APP_ID, Constants.SDK_KEY);
emitter.onNext(activeCode);
)
.subscribeOn(Schedulers.io())
.observeOn(androidSchedulers.mainThread())
.subscribe(new Observer<Integer>()
@Override
public void onSubscribe(Disposable d)
@Override
public void onNext(Integer activeCode)
if (activeCode == ErrorInfo.MOK)
showToast("OK");
else if (activeCode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED)
showToast("Not Active");
else
showToast("shibai");
if (view != null)
view.setClickable(true);
@Override
public void onError(Throwable e)
@Override
public void onComplete()
);
初始化引擎 :
private void initEngine()
faceEngine = new FaceEngine();
faceEngineCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_IMAGE, FaceEngine.ASF_OP_0_HIGHER_EXT,
16, 10, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_LIVENESS);
VersionInfo versionInfo = new VersionInfo();
faceEngine.getVersion(versionInfo);
Log.i(TAG, "initEngine: init: " + faceEngineCode + " version:" + versionInfo);
if (faceEngineCode != ErrorInfo.MOK)
Toast.makeText(this, "TEST", Toast.LENGTH_SHORT).show();
注册相机事件 :
button.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
File outImage = new File(getExternalCacheDir(), "output_image.jpg");
try
if (outImage.exists())
outImage.delete();
outImage.createNewFile();
catch (IOException e)
e.printStackTrace();
if (Build.VERSION.SDK_INT >= 24)
uri = FileProvider.getUriForFile(FaceMainActivity.this, "com.example.gdzc.cameraalbumtest.fileprovider", outImage);
else
uri = Uri.fromFile(outImage);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, TAKE_POTHO);
);
显示提示返回结果信息 :
/**
* 展示提示信息并且关闭提示框
*
* @param stringBuilder 带格式的提示文字
*/
private void showNotificationAndFinish(final SpannableStringBuilder stringBuilder)
runOnUiThread(new Runnable()
@Override
public void run()
if (tvNotice != null)
tvNotice.setText(stringBuilder.toString());
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
);
/**
* 追加提示信息
*
* @param stringBuilder 提示的字符串的存放对象
* @param styleSpan 添加的字符串的格式
* @param strings 字符串数组
*/
private void addNotificationInfo(SpannableStringBuilder stringBuilder, ParcelableSpan styleSpan, String... strings)
tvNotice.append(stringBuilder.toString());
if (stringBuilder == null || strings == null || strings.length == 0)
return;
int startLength = stringBuilder.length();
for (String string : strings)
stringBuilder.append(string);
int endLength = stringBuilder.length();
if (styleSpan != null)
stringBuilder.setSpan(styleSpan, startLength, endLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
人脸验证 :
首先人脸验证需要一个参照的人脸数据,与之后的人脸进行匹配,返回结果为通过与不通过。
//人脸比对数据显示
if (faceInfoList.size() > 0)
if (type == TYPE_MAIN)
int size = showInfoList.size();
showInfoList.clear();
showInfoAdapter.notifyItemRangeRemoved(0, size);
ivMainImage.setImageBitmap(mainBitmap);
mainFeature = new FaceFeature();
int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), mainFeature);
if (res != ErrorInfo.MOK)
mainFeature = null;
ivMainImage.setImageBitmap(bitmap);
StringBuilder stringBuilder = new StringBuilder();
if (faceInfoList.size() > 0)
stringBuilder.append("face info:\n\n");
for (int i = 0; i < faceInfoList.size(); i++)
stringBuilder.append("face[")
.append(i)
.append("]:\n")
.append(faceInfoList.get(i))
.append("\nage:")
.append(ageInfoList.get(i).getAge())
.append("\ngender:")
.append(genderInfoList.get(i).getGender() == GenderInfo.MALE ? "MALE"
: (genderInfoList.get(i).getGender() == GenderInfo.FEMALE ? "FEMALE" : "UNKNOWN"))
.append("\nface3DAngle:")
.append(face3DAngleList.get(i))
.append("\n\n");
tvMainImageInfo.setText(stringBuilder);
else if (type == TYPE_ITEM)
FaceFeature faceFeature = new FaceFeature();
int res = faceEngine.extractFaceFeature(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList.get(0), faceFeature);
if (res == 0)
FaceSimilar faceSimilar = new FaceSimilar();
int compareResult = faceEngine.compareFaceFeature(mainFeature, faceFeature, faceSimilar);
if (compareResult == ErrorInfo.MOK)
String resStr = "";
BigDecimal bigDecimal = new BigDecimal(faceSimilar.getScore());
if (bigDecimal.compareTo(new BigDecimal(0.8)) >= 0)
resStr = "通过";
else
resStr = "不通过";
ItemShowInfo showInfo = new ItemShowInfo(bitmap, ageInfoList.get(0).getAge(), genderInfoList.get(0).getGender(), faceSimilar.getScore(),resStr);
showInfoList.add(showInfo);
showInfoAdapter.notifyItemInserted(showInfoList.size() - 1);
else
showToast("error");
else
if (type == TYPE_MAIN)
mainBitmap = null;
else
showToast("can not get nv21 from bitmap!");
通过对比结果,对比结果值越接近1就越相似,此处识别通过标准为0.8。
代码 :
对比 :
package com.example.ttlock.activity;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.arcsoft.face.AgeInfo;
import com.arcsoft.face.ErrorInfo;
import com.arcsoft.face.Face3DAngle;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.FaceSimilar;
import com.arcsoft.face.GenderInfo;
import com.example.ttlock.R;
import com.example.ttlock.adapter.widget.ShowInfoAdapter;
import com.example.ttlock.model.ItemShowInfo;
import com.example.ttlock.utils.ImageUtil;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MultiImageActivity extends AppCompatActivity
private static final String TAG = "MultiImageActivity";
private static final int ACTION_CHOOSE_MAIN_IMAGE = 0x201;
private static final int ACTION_ADD_RECYCLER_ITEM_IMAGE = 0x202;
public static final int TAKE_POTHO = 1;
private static final int ACTION_REQUEST_PERMISSIONS = 0x001;
private Uri uri;
private ImageView ivMainImage;
private TextView tvMainImageInfo;
/**
* 选择图片时的类型
*/
private int TYPE_MAIN = 0;
private int TYPE_ITEM = 1;
/**
* 主图的第0张人脸的特征数据
*/
private FaceFeature mainFeature;
private ShowInfoAdapter showInfoAdapter;
private List<ItemShowInfo> showInfoList;
private FaceEngine faceEngine;
private int faceEngineCode = -1;
private Bitmap mainBitmap;
Toast toast = null;
private static String[] NEEDED_PERMISSIONS = new String[]
Manifest.permission.READ_PHONE_STATE
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_multi_image);
/**
* 在选择图片的时候,在android 7.0及以上通过FileProvider获取Uri,不需要文件权限
*/
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
List<String> permissionList = new ArrayList<>(Arrays.asList(NEEDED_PERMISSIONS));
permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
NEEDED_PERMISSIONS = permissionList.toArray(new String[0]);
if (!checkPermissions(NEEDED_PERMISSIONS))
ActivityCompat.requestPermissions(this, NEEDED_PERMISSIONS, ACTION_REQUEST_PERMISSIONS);
else
initEngine();
initView();
private void initView()
ivMainImage = findViewById(R.id.iv_main_image);
tvMainImageInfo = findViewById(R.id.tv_main_image_info);
RecyclerView recyclerFaces = findViewById(R.id.recycler_faces);
showInfoList = new ArrayList<>();
showInfoAdapter = new ShowInfoAdapter(showInfoList, this);
recyclerFaces.setAdapter(showInfoAdapter);
recyclerFaces.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerFaces.setLayoutManager(new LinearLayoutManager(this));
private void initEngine()
faceEngine = new FaceEngine();
faceEngineCode = faceEngine.init(this, FaceEngine.ASF_DETECT_MODE_IMAGE, FaceEngine.ASF_OP_0_HIGHER_EXT,
16, 6, FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_AGE | FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE);
Log.i(TAG, "initEngine: init " + faceEngineCode);
if (faceEngineCode != ErrorInfo.MOK)
Toast.makeText(this, "f", Toast.LENGTH_SHORT).show();
private void unInitEngine()
if (faceEngine != null)
faceEngineCode = faceEngine.unInit();
Log.i(TAG, "unInitEngine: " + faceEngineCode);
@Override
protected void onDestroy()
unInitEngine();
super.onDestroy();
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
super.onActivityResult(requestCode, resultCode, data);
//
// if (data == null || data.getData() == null)
// showToast("failed");
// return;
//
// if (requestCode == ACTION_CHOOSE_MAIN_IMAGE)
// mainBitmap = ImageUtil.getBitmapFromUri(data.getData(), this);
// if (mainBitmap == null)
// showToast("failed");
// return;
//
// processImage(mainBitmap, TYPE_MAIN);
// else if (requestCode == ACTION_ADD_RECYCLER_ITEM_IMAGE)
// Bitmap bitmap = ImageUtil.getBitmapFromUri(data.getData(), this);
// if (bitmap == null)
// showToast("failed");
// return;
//
// if (mainFeature == null)
// return;
//
// processImage(bitmap, TYPE_ITEM);
//
switch (requestCode)
case ACTION_CHOOSE_MAIN_IMAGE:
try
mainBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
// imageView.setImageBitmap(mBitmap);
//将图片解析成Bitmap对象,并把它显现出来
processImage(mainBitmap, TYPE_MAIN);
catch (FileNotFoundException e)
e.printStackTrace();
break;
case ACTION_ADD_RECYCLER_ITEM_IMAGE:
Bitmap bitmap = null;
try
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
catch (FileNotFoundException e)
e.printStackTrace();
if (bitmap == null)
showToast("failed");
return;
if (mainFeature == null)
return;
processImage(bitmap, TYPE_ITEM);
default:
break;
public void processImage(Bitmap bitmap, int type)
if (bitmap == null)
return;
if (faceEngine == null)
return;
//NV21宽度必须为4的倍数,高度为2的倍数
bitmap = ImageUtil.alignBitmapForNv21(bitmap);
if (bitmap == null)
return;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
//bitmap转NV21
final byte[] nv21 = ImageUtil.bitmapToNv21(bitmap, width, height);
if (nv21 != null)
List<FaceInfo> faceInfoList = new ArrayList<>();
//人脸检测
int detectCode = faceEngine.detectFaces(nv21, width, height, FaceEngine.CP_PAF_NV21, faceInfoList);
if (detectCode != 0 || faceInfoList.size() == 0)
showToast("face detection finished, code is " + detectCode + ", face num is " + faceInfoList.size());
return;
//绘制bitmap
bitmap = bitmap.copy(Bitmap.Config.RGB_565, true);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(10);
paint.setColor(Color.YELLOW);
if (faceInfoList.size() > 0)
for (