前天发了一个【人脸检测】的帖子,好像还是有人看的。
把我移植的另一个也放进来。
准确来说,这个项目包含两部分:
(1)人脸检测,从图中找出人脸,也就是之前的那个项目包含到这个项目里面。
(2)人脸识别,识别出当前人脸是谁。其实就是提取特征,然后直接比较两个人之间的特征欧几里得距离D.。
如果D小于某个阈值(官方的设置值是1.204),就判断为两个人脸图是同一个。
用的卷积神经网络是别人训练好的,90MB+,在公共数据集上有99+%的准确率。
核心代码【这个代码比较简单,一两百行代码】:
Facenet.java
[Java] 纯文本查看 复制代码 package com.example.vcvyc.myapplication;
import android.app.Activity;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Log;
/*
import android.graphics.Bitmap;
import android.os.Trace;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Vector;
*/
import org.tensorflow.Operation;
import org.tensorflow.contrib.android.TensorFlowInferenceInterface;
import java.io.IOException;
import java.nio.IntBuffer;
/**功能:人脸转换为512维特征向量
*/
public class Facenet{
private static final String MODEL_FILE = "file:///android_asset/20180402-114759.pb";
private static final String INPUT_NAME = "input:0";
private static final String OUTPUT_NAME = "embeddings:0";
private static final String PHASE_NAME = "phase_train:0";
private static final String[] outputNames = new String[] {OUTPUT_NAME};
//神经网络输入大小
private static final int INPUT_SIZE=160;
private float[] floatValues; //保存input的值
private int[] intValues; //像素值
private AssetManager assetManager;
private TensorFlowInferenceInterface inferenceInterface;
Facenet(AssetManager mgr){
assetManager=mgr;
loadModel();
floatValues=new float[INPUT_SIZE*INPUT_SIZE*3];
intValues = new int[INPUT_SIZE * INPUT_SIZE];
}
private boolean loadModel(){
//AssetManager
try {
inferenceInterface = new TensorFlowInferenceInterface(assetManager, MODEL_FILE);
Log.d("Facenet","[*]load model success");
}catch(Exception e){
Log.e("Facenet","[*]load model failed"+e);
return false;
}
return true;
}
//Bitmap to floatValues
private int normalizeImage(final Bitmap _bitmap){
// (0) bitmap缩放到INPUT_SIZE*INPUT_SIZE
float scale_width=((float)INPUT_SIZE)/_bitmap.getWidth();
float scale_height=((float)INPUT_SIZE)/_bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scale_width,scale_height);
Bitmap bitmap = Bitmap.createBitmap(_bitmap,0,0,_bitmap.getWidth(),_bitmap.getHeight(),matrix,true);
//Log.d("Facenet","[*]bitmap size:"+bitmap.getHeight()+"x"+bitmap.getWidth());
// (1) 将像素映射到[-1,1]区间内
float imageMean=127.5f;
float imageStd=128;
bitmap.getPixels(intValues,0,bitmap.getWidth(),0,0,bitmap.getWidth(),bitmap.getHeight());
for (int i=0;i<intValues.length;i++){
final int val=intValues[i];
floatValues[i * 3 + 0] = (((val >> 16) & 0xFF) - imageMean) / imageStd;
floatValues[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd;
floatValues[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd;
}
//Log.d("Facenet","[*]normalizeImage");
//Log.d("Facenet","[*]normalizeImage"+intValues.length);
return 0;
}
public FaceFeature recognizeImage(final Bitmap bitmap){
//Log.d("Facenet","[*]recognizeImage");
//(0)图片预处理,normailize
normalizeImage(bitmap);
//(1)Feed
try {
inferenceInterface.feed(INPUT_NAME, floatValues, 1, INPUT_SIZE, INPUT_SIZE, 3);
boolean []phase=new boolean[1];
phase[0]=false;
inferenceInterface.feed(PHASE_NAME,phase);
}catch (Exception e){
Log.e("Facenet","[*] feed Error\n"+e);
return null;
}
//(2)run
// Log.d("Facenet","[*]Feed:"+INPUT_NAME);
try {
inferenceInterface.run(outputNames, false);
}catch (Exception e){
Log.e("Facenet","[*] run error\n"+e);
return null;
}
//(3)fetch
FaceFeature faceFeature=new FaceFeature();
float[] outputs=faceFeature.getFeature();
try {
inferenceInterface.fetch(OUTPUT_NAME, outputs);
}catch (Exception e){
Log.e("Facenet","[*] fetch error\n"+e);
return null;
}
return faceFeature;
}
}
FaceFeature.java
[Java] 纯文本查看 复制代码 package com.example.vcvyc.myapplication;
/* by cjf 1801615 [email]352871242@qq.com[/email]*/
/**
* 人脸特征(512维特征值)
* 相似度取特征向量之间的欧式距离.
*/
public class FaceFeature {
public static final int DIMS=512;
private float fea[];
FaceFeature(){
fea=new float[DIMS];
}
public float[] getFeature(){
return fea;
}
//比较当前特征和另一个特征之间的相似度
public double compare(FaceFeature ff){
double dist=0;
for (int i=0;i<DIMS;i++)
dist+=(fea[i]-ff.fea[i])*(fea[i]-ff.fea[i]);
dist=Math.sqrt(dist);
return dist;
}
}
效果图:
|