【人脸识别】Google的Facenet移植到安卓
前天发了一个【人脸检测】的帖子,好像还是有人看的。把我移植的另一个也放进来。
准确来说,这个项目包含两部分:
(1)人脸检测,从图中找出人脸,也就是之前的那个项目包含到这个项目里面。
(2)人脸识别,识别出当前人脸是谁。其实就是提取特征,然后直接比较两个人之间的特征欧几里得距离D.。
如果D小于某个阈值(官方的设置值是1.204),就判断为两个人脸图是同一个。
用的卷积神经网络是别人训练好的,90MB+,在公共数据集上有99+%的准确率。
核心代码【这个代码比较简单,一两百行代码】:
Facenet.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;
intValues = new int;
}
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;
floatValues = (((val >> 16) & 0xFF) - imageMean) / imageStd;
floatValues = (((val >> 8) & 0xFF) - imageMean) / imageStd;
floatValues = ((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;
phase=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
package com.example.vcvyc.myapplication;
/* by cjf 1801615 352871242@qq.com*/
/**
* 人脸特征(512维特征值)
* 相似度取特征向量之间的欧式距离.
*/
public class FaceFeature {
public static final int DIMS=512;
private float fea[];
FaceFeature(){
fea=new float;
}
public float[] getFeature(){
return fea;
}
//比较当前特征和另一个特征之间的相似度
public double compare(FaceFeature ff){
double dist=0;
for (int i=0;i<DIMS;i++)
dist+=(fea-ff.fea)*(fea-ff.fea);
dist=Math.sqrt(dist);
return dist;
}
}
效果图:
本帖最后由 vcvycy 于 2018-6-28 15:32 编辑
幻象 发表于 2018-6-28 03:43
视频中人体跟踪之类的怎么写啊,有没有思路?弄了好久了还是写不出来,求楼主帮帮忙
人体跟踪是类似这种?
https://v.youku.com/v_show/id_XMTg3OTMyMDAwMA==.html?spm=a2hzp.8244740.0.0
以前我做了一个很简单的跟踪,就是传统的方法,统计RGB什么的比例,然后跟踪。
现在有深度学习的方法,直接用别人的东西就好了,比如yolo什么的。 这么厉害的么 这个厉害了-我的大神
技术大神,小白路过 这么厉害吗{:1_904:} 感谢分享,楼主辛苦了 厉害了-我的神 pc上用python写好,android调用api多好 非常不错的源码,能帮助到需要的人 视频中人体跟踪之类的怎么写啊,有没有思路?弄了好久了还是写不出来,求楼主帮帮忙