vcvycy 发表于 2018-6-27 20:54

【人脸识别】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:27

本帖最后由 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什么的。

汆肉米线 发表于 2018-6-27 21:08

这么厉害的么

idealming 发表于 2018-6-27 21:09

这个厉害了-我的大神

cao_jf 发表于 2018-6-27 21:23

技术大神,小白路过

yinweiyujianni 发表于 2018-6-27 21:27

这么厉害吗{:1_904:}

我才不是狮子喵 发表于 2018-6-27 21:27

感谢分享,楼主辛苦了

j296849823 发表于 2018-6-27 21:30

厉害了-我的神

handlertools 发表于 2018-6-27 22:26

pc上用python写好,android调用api多好

A00 发表于 2018-6-27 22:49

非常不错的源码,能帮助到需要的人

幻象 发表于 2018-6-28 03:43

视频中人体跟踪之类的怎么写啊,有没有思路?弄了好久了还是写不出来,求楼主帮帮忙
页: [1] 2 3
查看完整版本: 【人脸识别】Google的Facenet移植到安卓