人脸识别在Android [英] Face Recognition on Android

查看:314
本文介绍了人脸识别在Android的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开发在Android上一个人脸识别应用程序,因为我不希望使用NDK的项目(根本没有切换的时间),我坚持发展与整个应用程序Java和为此我有一些问题:

  1. 看来模块的Contrib中不包含OpenCV的2.4.2。反正是有使用它的项目?

  2. 我试着用JavaCV使用的Contrib模块的FaceRecognizer级。有可用的所谓的FaceRecognizer与&amp两个类; FaceRecognizerPtr。没有任何人知道这两者之间的区别是什么呢?

  3. 上面提到的都被称为火车,它(在C ++中)接收类型两个载体垫和放大器;整的方法的类(建模>火车(图像,标签) &安培;火车(矢量<垫> theImages,矢量< INT> theLabels )我试图将它们的ArrayList<垫>&安培; ArrayList的<整数GT; 和载体在Java中,但似乎该方法明确接受这我不知道如何获得CvArr数据类型...以下是错误:

  

在类型的方法列车(opencv_core.CvArr,opencv_core.CvArr)   opencv_contrib.FaceRecognizer是不适用的参数   (ArrayList中,ArrayList中)

有谁知道如何改变我的ArrayList到CvArr?!

这是我的第一篇文章,我不知道是否要问的一个职位或三个职位非常抱歉这三个问题的任何不便之处......如果您需要了解该项目的任何其他信息,随意问。

解决方案

更新

下面这篇文章是由皮特基督教彼杰兰的,所以所有的信用是他的。我张贴在这里,因为他的博客似乎是在维护模式的时刻,但我认为这是值得分享。

干什么用JavaCV人脸识别(从 http://pcbje.com

我无法找到如何执行OpenCV的使用和Java人脸识别任何教程,所以我决定在这里分享一个可行的解决方案。该解决方案是非常低效的现有形式的人才培养模式是建立在每次运行,但它显示了我们所需要的,使其工作。

类下面有两个参数:路径包含了培训面和路径要分类的图像的目录。这并不是说所有的图片必须是相同的大小,并且已经有了被裁切掉他们的原始图像的面孔(看看这里如果你还没有这样做的人脸检测还)。

有关这个职位的简单,类也需要训练图像有文件名格式为:<标签> -rest_of_filename.png 。例如:

1,jon_doe_1.png
1,jon_doe_2.png
2 jane_doe_1.png
2 jane_doe_2.png

...等等。

在code:

进口com.google code.javacv.cpp.opencv_core; 进口静电com.google code.javacv.cpp.opencv_highgui *。 进口静电com.google code.javacv.cpp.opencv_core *。 进口静电com.google code.javacv.cpp.opencv_imgproc *。 进口静电com.google code.javacv.cpp.opencv_contrib *。 进口的java.io.File; 进口java.io.FilenameFilter; 公共类OpenCVFaceRecognizer {   公共静态无效的主要(字串[] args){     串trainingDir =的args [0];     IplImage的testImage = cvLoadImage(参数[1]);     文件根=新的文件(trainingDir);     的FilenameFilter pngFilter =新的FilenameFilter(){       公共布尔接受(文件目录,字符串名称){         返回name.toLowerCase()的endsWith(PNG)。       }     };     文件[]的图像文件= root.listFiles(pngFilter);     MatVector图像=新MatVector(imageFiles.length);     INT []标签=新INT [imageFiles.length]     INT计数器= 0;     INT标签;     IplImage的IMG;     IplImage的grayImg;     对于(文件图像:图像文件中){       //获取图像和标签:       的img = cvLoadImage(image.getAbsolutePath());       标签=的Integer.parseInt(image.getName()分裂(\\ - )[0]);       //转换图像灰度:       grayImg = IplImage.create(img.width(),img.height(),IPL_DEPTH_8U,1);       cvCvtColor(IMG,grayImg,CV_BGR2GRAY);       //它附加在图像列表中:       images.put(计数器,grayImg);       //并在标签列表:       标签[窗口] =标签;       //增加柜台下一张图片:       反++;     }     FaceRecognizer faceRecognizer = createFisherFaceRecognizer();     // FaceRecognizer faceRecognizer = createEigenFaceRecognizer();     // FaceRecognizer faceRecognizer = createLBPHFaceRecognizer()     faceRecognizer.train(图像,标签);     //将测试图像:     IplImage结构greyTestImage = IplImage.create(testImage.width(),testImage.height(),IPL_DEPTH_8U,1);     cvCvtColor(testImage,greyTestImage,CV_BGR2GRAY);     //并获得prediction:     。INT predictedLabel = faceRecognizer predict(greyTestImage);     的System.out.println(predicted标签:+ predictedLabel);   } }

类需要OpenCV的Java接口。如果你正在使用Maven,你可以检索所需的库与以下的pom.xml:

&LT;项目的xmlns =htt​​p://maven.apache.org/POM/4.0.0的xmlns:XSI =htt​​p://www.w3.org/2001/XMLSchema-instance      XSI:的schemaLocation =htt​​p://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">   &LT; modelVersion&GT; 4.0.0&LT; / modelVersion&GT;   &LT;的groupId&GT; com.pcbje&LT; /的groupId&GT;   &LT; artifactId的&GT; opencvfacerecognizer&LT; / artifactId的&GT;   &LT;版&GT; 0.1-SNAPSHOT&LT; /版本&GT;   &LT;包装&GT;罐子&LT; /包装&GT;   &LT;名称&gt;&opencvfacerecognizer LT; /名称&gt;   &LT;网址&GT; HTTP://pcbje.com< / URL&GT;   &LT;依赖&GT;     &LT;依赖&GT;       &LT;的groupId&GT; com.google code.javacv&LT; /的groupId&GT;       &LT; artifactId的&GT; javacv&LT; / artifactId的&GT;       &LT;版&GT; 0.3&LT; /版本&GT;     &LT; /依赖性&GT;     &LT;! - 对于Linux的x64环境 - &GT;     &LT;依赖&GT;       &LT;的groupId&GT; com.google code.javacv&LT; /的groupId&GT;       &LT; artifactId的&GT; javacv&LT; / artifactId的&GT;       &LT;分级&GT;的Linux x86_64的&LT; /分类&GT;       &LT;版&GT; 0.3&LT; /版本&GT;     &LT; /依赖性&GT;     &LT;! - 对于OSX环境 - &GT;     &LT;依赖&GT;       &LT;的groupId&GT; com.google code.javacv&LT; /的groupId&GT;       &LT; artifactId的&GT; javacv&LT; / artifactId的&GT;       &LT;分级&GT; MacOSX的-x86_64的&LT; /分类&GT;       &LT;版&GT; 0.3&LT; /版本&GT;     &LT; /依赖性&GT;   &LT; /依赖性&GT;   &LT;库&GT;     &LT;库&GT;       &LT; ID&GT; javacv&LT; / ID&GT;       &LT;名称&gt;&JavaCV LT; /名称&gt;       &LT;网址&GT; HTTP://maven2.javacv.google$c$c.com/git/< / URL&GT;     &LT; /存储库&GT;   &LT; /存储库&GT; &LT; /项目&GT;

的原贴

这是我的答复是在 http://answers.opencv.org报价/问题/ 865 /最的contrib模块-问题

而无需使用javacv,让我们看看我们有多远可以通过看界面搞定!该项目是在谷歌code,它可以很容易地浏览code: HTTP://$c$c.google.com/p/javacv

先来看看如何 CV :: FaceRecognizer 已被折(<一href="http://$c$c.google.com/p/javacv/source/browse/src/main/java/com/google$c$c/javacv/cpp/opencv_contrib.java#845"相对=nofollow> opencv_contrib.java,线845在写这篇时间):

  @Namespace(CV)公共静态类FaceRecognizer扩展算法{
    静态{Loader.load(); }
    公共FaceRecognizer(){}
    公共FaceRecognizer(指针p){超(P); }

    公共/ *抽象* /本地无效列车(@ByRef MatVector SRC,@Adapter(ArrayAdapter)CvArr标签);
    公共/ *抽象* /本地INT predict(@Adapter(ArrayAdapter)CvArr SRC);
    公共/ *抽象* /原生虚空predict(@Adapter(ArrayAdapter)CvArr SRC,@ByRef INT []标签,@ByRef双[] DIST);
    公共本地无效保存(字符串文件名);
    公共本地无效负载(字符串文件名);
    公共本地无效保存(@Adapter(FileStorageAdapter)CvFileStorage FS);
    公共本地无效负载(@Adapter(FileStorageAdapter)CvFileStorage FS);
}
 

啊哈,所以你需要通过 MatVector 的图像!你可以通过标签在 CvArr (一行​​或一列)。该 MatVector 中定义的 opencv_core,线4629(在写这篇的时间),它看起来是这样的:

 公共静态类MatVector扩展指针{
    静{负载(); }
    公共MatVector(){分配(); }
    公共MatVector(N久){分配(N); }
    公共MatVector(指针p){超(P); }
    私人本地无效分配();
    私人本地无效分配(@Cast(为size_t)N久);

    公共本地长尺寸();
    公共本地无效调整大小(@Cast(为size_t)N久);

    @index @ValueGetter公共本地@Adapter(MatAdapter)与CvMat getCvMat(@Cast(为size_t),长一);
    @index @ValueGetter公共本地@Adapter(MatAdapter)CvMatND getCvMatND(@Cast(为size_t),长一);
    @index @ValueGetter公共本地@Adapter(MatAdapter)的IplImage getIplImage(@Cast(为size_t),长一);
    @index @ValueSetter公共本地MatVector认沽(@Cast(为size_t)长的我,@Adapter(MatAdapter)CvArr值);
}
 

同样只是通过看code,我想这可以是这样的:

  INT numberOfImages = 10;
//分配一些内存:
MatVector图像=新MatVector(numberOfImages);
//然后填写MatVector,你可能想要做一些有用的东西,而不是:
对于(INT IDX = 0; IDX&LT; numberOfImages; IDX ++){
   //加载图像:
   CvArr图像= cvLoadImage(/路径/要/你/图像);
   //并把它放入MatVector:
   images.put(IDX,图像);
}
 

您可能要自己写,做了转换,从一个Java 的ArrayList MatVector (如果方法这样的功能并不在javacv尚不存在)。

现在你的第二个问题。 FaceRecognizer 是相当于 CV :: FaceRecognizer 。本机OpenCV的C ++类返回 CV :: PTR&LT; CV :: FaceRecognizer&GT; ,这是一个(智能)指针到 CV :: FaceRecognizer 。这必须包装为好。看到一个模式在这里?

FaceRecognizerPtr 的接口,现在看起来是这样的:

  @Name(CV :: PTR&LT; CV :: FaceRecognizer&gt;中)
公共静态类FaceRecognizerPtr扩展指针{
    静{负载(); }
    公共FaceRecognizerPtr(){分配(); }
    公共FaceRecognizerPtr(指针p){超(P); }
    私人本地无效分配();

    公共本地FaceRecognizer得到();
    公共本地FaceRecognizerPtr认沽(FaceRecognizer值);
}
 

所以,你可以得到一个 FaceRecognizer 从这个类或放 FaceRecognizer 成。你应该只关心的get(),因为指针是充满创造的具体 FaceRecognizer 算法的方法

  @Namespace(CV)公共静态本地@ByVal FaceRecognizerPtr createEigenFaceRecognizer(INT num_components / * = 0 * /,双阈值/ * = DBL_MAX * /);
@Namespace(CV)公共静态本地@ByVal FaceRecognizerPtr createFisherFaceRecognizer(INT num_components / * = 0 * /,双阈值/ * = DBL_MAX * /);
@Namespace(CV)公共静态本地@ByVal FaceRecognizerPtr createLBPHFaceRecognizer(INT半径/ * = 1 * /,
        诠释邻居/ * = 8 * / INT grid_x / * = 8 * / INT grid_y / * = 8 * /,双阈值/ * = DBL_MAX * /);
 

所以,一旦你得到了FaceRecognizerPtr,你可以做这样的事情:

  //保存你的训练数据和标签:
MatVector图像;
CvArr标签;
//做一些与图像和标签...可能填补他们?
// ...
//然后得到一个指向一个FaceRecognizer(FaceRecognizerPtr)。
// Java没有默认参数,所以你必须要加一些自己,
//如果传递0作为num_components到EigenFaceRecognizer,数量
//部件是由数据确定的,该阈值使用的最大可能
//如果你不想一个值。我不知道在Java中的常数:
FaceRecognizerPtr模型= createEigenFaceRecognizer(0,10000);
//然后训练它。看我怎么调用get(),以获得FaceRecognizer的FaceRecognizerPtr内:
。model.get()火车(图像,标签);
 

这学到你一个特征脸模型。就是这样!

I'm trying to develop a Face Recognition app on Android and since I don't want to use NDK on the project (simply don't have the time to switch), I'm sticking to develop the whole app with Java and therefor I'm having some problems :

  1. It seems the Contrib Module isn't included in OpenCV 2.4.2 . is there anyway to use it in the project ?

  2. I tried using JavaCV to use the Contrib Module's "FaceRecognizer" class. there are two classes available called "FaceRecognizer" & "FaceRecognizerPtr". does anybody know what the difference between these two is ?

  3. The classes mentioned above have a method called "Train" which (In C++) receives two Vectors of types "Mat & Integer" ( model->train(images,labels) & train(Vector<mat> theImages, Vector<int> theLabels) . I tried passing them ArrayList<mat> & ArrayList<integer> and Vectors in Java but it seems that the method explicitly accepts the "CvArr" Data type which I'm not sure how to acquire... Here is the error :

The method train(opencv_core.CvArr, opencv_core.CvArr) in the type opencv_contrib.FaceRecognizer is not applicable for the arguments (ArrayList, ArrayList)

Does anyone know how to change my ArrayList to CvArr ?!

This is my first post and I wasn't sure whether to ask all three questions in one post or in three posts so sorry for any inconveniences... If you need any other Information about the project, feel free to ask.

解决方案

Update

The following article was written by Petter Christian Bjelland, so all credit is his. I am posting it here, because his blog seems to be in Maintenance mode at the moment, but I think it is worth sharing.

Doing face recognition with JavaCV (from http://pcbje.com)

I couldn’t find any tutorial on how to perform face recognition using OpenCV and Java, so I decided to share a viable solution here. The solution is very inefficient in its current form as the training model is built at each run, however it shows what’s needed to make it work.

The class below takes two arguments: The path to the directory containing the training faces and the path to the image you want to classify. Not that all images has to be of the same size and that the faces already has to be cropped out of their original images (Take a look here if you haven’t done the face detection yet).

For the simplicity of this post, the class also requires that the training images have filename format: <label>-rest_of_filename.png. For example:

1-jon_doe_1.png
1-jon_doe_2.png
2-jane_doe_1.png
2-jane_doe_2.png

... and so on.

The code:

import com.googlecode.javacv.cpp.opencv_core;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_contrib.*;
import java.io.File;
import java.io.FilenameFilter;

public class OpenCVFaceRecognizer {
  public static void main(String[] args) {
    String trainingDir = args[0];
    IplImage testImage = cvLoadImage(args[1]);

    File root = new File(trainingDir);

    FilenameFilter pngFilter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        return name.toLowerCase().endsWith(".png");
      }
    };

    File[] imageFiles = root.listFiles(pngFilter);

    MatVector images = new MatVector(imageFiles.length);

    int[] labels = new int[imageFiles.length];

    int counter = 0;
    int label;

    IplImage img;
    IplImage grayImg;

    for (File image : imageFiles) {
      // Get image and label:
      img = cvLoadImage(image.getAbsolutePath());
      label = Integer.parseInt(image.getName().split("\\-")[0]);
      // Convert image to grayscale:
      grayImg = IplImage.create(img.width(), img.height(), IPL_DEPTH_8U, 1);
      cvCvtColor(img, grayImg, CV_BGR2GRAY);
      // Append it in the image list:
      images.put(counter, grayImg);
      // And in the labels list:
      labels[counter] = label;
      // Increase counter for next image:
      counter++;
    }

    FaceRecognizer faceRecognizer = createFisherFaceRecognizer();
    // FaceRecognizer faceRecognizer = createEigenFaceRecognizer();
    // FaceRecognizer faceRecognizer = createLBPHFaceRecognizer()

    faceRecognizer.train(images, labels);

    // Load the test image:
    IplImage greyTestImage = IplImage.create(testImage.width(), testImage.height(), IPL_DEPTH_8U, 1);
    cvCvtColor(testImage, greyTestImage, CV_BGR2GRAY);

    // And get a prediction:
    int predictedLabel = faceRecognizer.predict(greyTestImage);
    System.out.println("Predicted label: " + predictedLabel);
  }
}

The class requires the OpenCV Java interface. If you’re using Maven, you can retrieve the required libraries with the following pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.pcbje</groupId>
  <artifactId>opencvfacerecognizer</artifactId>
  <version>0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>opencvfacerecognizer</name>
  <url>http://pcbje.com</url>

  <dependencies>
    <dependency>
      <groupId>com.googlecode.javacv</groupId>
      <artifactId>javacv</artifactId>
      <version>0.3</version>
    </dependency>

    <!-- For Linux x64 environments -->
    <dependency>
      <groupId>com.googlecode.javacv</groupId>
      <artifactId>javacv</artifactId>
      <classifier>linux-x86_64</classifier>
      <version>0.3</version>
    </dependency>    

    <!-- For OSX environments -->
    <dependency>
      <groupId>com.googlecode.javacv</groupId>
      <artifactId>javacv</artifactId>
      <classifier>macosx-x86_64</classifier>
      <version>0.3</version>
    </dependency>
  </dependencies>

  <repositories>
    <repository>
      <id>javacv</id>
      <name>JavaCV</name>
      <url>http://maven2.javacv.googlecode.com/git/</url>
    </repository>
  </repositories>
</project>

Original Post

Quoting from my reply on http://answers.opencv.org/question/865/the-contrib-module-problem.

Without ever having used javacv, let's see how far we can get by just looking at the interfaces! The project is on googlecode, which makes it easy to browse the code: http://code.google.com/p/javacv.

First have a look at how cv::FaceRecognizer has been wrapped (opencv_contrib.java, line 845 at time of writing this):

@Namespace("cv") public static class FaceRecognizer extends Algorithm {
    static { Loader.load(); }
    public FaceRecognizer() { }
    public FaceRecognizer(Pointer p) { super(p); }

    public /*abstract*/ native void train(@ByRef MatVector src, @Adapter("ArrayAdapter") CvArr labels);
    public /*abstract*/ native int predict(@Adapter("ArrayAdapter") CvArr src);
    public /*abstract*/ native void predict(@Adapter("ArrayAdapter") CvArr src, @ByRef int[] label, @ByRef double[] dist);
    public native void save(String filename);
    public native void load(String filename);
    public native void save(@Adapter("FileStorageAdapter") CvFileStorage fs);
    public native void load(@Adapter("FileStorageAdapter") CvFileStorage fs);
}

Aha, so you need to pass a MatVector for the images! You can pass the labels in a CvArr (one row or one column). The MatVector is defined in opencv_core, line 4629 (at time of writing this) and it looks like this:

public static class MatVector extends Pointer {
    static { load(); }
    public MatVector()       { allocate();  }
    public MatVector(long n) { allocate(n); }
    public MatVector(Pointer p) { super(p); }
    private native void allocate();
    private native void allocate(@Cast("size_t") long n);

    public native long size();
    public native void resize(@Cast("size_t") long n);

    @Index @ValueGetter public native @Adapter("MatAdapter") CvMat getCvMat(@Cast("size_t") long i);
    @Index @ValueGetter public native @Adapter("MatAdapter") CvMatND getCvMatND(@Cast("size_t") long i);
    @Index @ValueGetter public native @Adapter("MatAdapter") IplImage getIplImage(@Cast("size_t") long i);
    @Index @ValueSetter public native MatVector put(@Cast("size_t") long i, @Adapter("MatAdapter") CvArr value);
}

Again just by looking at the code, I guess it can be used like this:

int numberOfImages = 10;
// Allocate some memory:
MatVector images = new MatVector(numberOfImages);
// Then fill the MatVector, you probably want to do something useful instead:
for(int idx = 0; idx < numberOfImages; idx++){
   // Load an image:
   CvArr image = cvLoadImage("/path/to/your/image");
   // And put it into the MatVector:
   images.put(idx, image);
}

You probably want to write yourself a method that does the conversion from a Java ArrayList to a MatVector (if such a function does not exist in javacv yet).

Now to your second question. FaceRecognizer is the equivalent to cv::FaceRecognizer. The native OpenCV C++ classes return a cv::Ptr<cv::FaceRecognizer>, which is a (Smart) Pointer to a cv::FaceRecognizer. This has to be wrapped as well. See a pattern here?

The interface of FaceRecognizerPtr now looks like this:

@Name("cv::Ptr<cv::FaceRecognizer>")
public static class FaceRecognizerPtr extends Pointer {
    static { load(); }
    public FaceRecognizerPtr()       { allocate();  }
    public FaceRecognizerPtr(Pointer p) { super(p); }
    private native void allocate();

    public native FaceRecognizer get();
    public native FaceRecognizerPtr put(FaceRecognizer value);
}

So you can either get a FaceRecognizer from this class or put a FaceRecognizer into. You should only be concerned about the get(), as the Pointer is filled by the method creating the concrete FaceRecognizer algorithm:

@Namespace("cv") public static native @ByVal FaceRecognizerPtr createEigenFaceRecognizer(int num_components/*=0*/, double threshold/*=DBL_MAX*/);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createFisherFaceRecognizer(int num_components/*=0*/, double threshold/*=DBL_MAX*/);
@Namespace("cv") public static native @ByVal FaceRecognizerPtr createLBPHFaceRecognizer(int radius/*=1*/,
        int neighbors/*=8*/, int grid_x/*=8*/, int grid_y/*=8*/, double threshold/*=DBL_MAX*/);

So once you have got the FaceRecognizerPtr, you can do things like:

// Holds your training data and labels:
MatVector images;
CvArr labels;
// Do something with the images and labels... Probably fill them?
// ...
// Then get a Pointer to a FaceRecognizer (FaceRecognizerPtr).
// Java doesn't have default parameters, so you have to add some yourself,
// if you pass 0 as num_components to the EigenFaceRecognizer, the number of
// components is determined by the data, for the threshold use the maximum possible
// value if you don't want one. I don't know the constant in Java:
FaceRecognizerPtr model = createEigenFaceRecognizer(0, 10000);
// Then train it. See how I call get(), to get the FaceRecognizer inside the FaceRecognizerPtr:
model.get().train(images, labels);

This learns you an Eigenfaces model. And that's it!

这篇关于人脸识别在Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆