Распознавание лиц на Андроид

Я пытаюсь разработать приложение для распознавания лиц на Android, и поскольку я не хочу использовать NDK в проекте (просто нет времени переключаться), я придерживаюсь разработки всего приложения с Java, и поэтому у меня возникли некоторые проблемы:

  1. Кажется, что модуль Contrib не включен в OpenCV 2.4.2 . есть ли вообще использовать его в проекте ?

  2. Я попытался использовать JavaCV для использования класса "FaceRecognizer" модуля Contrib. Есть доступны два класса: "FaceRecognizer "и"FaceRecognizerPtr". кто-нибудь знает, в чем разница между этими двумя ?

  3. вышеупомянутые классы имеют метод под названием "Train", который (в C++) получает два вектора типов "Mat & Integer" (model->train(images,labels) & train(Vector<mat> theImages, Vector<int> theLabels) . Я пытался пройти мимо них ArrayList<mat> & ArrayList<integer> и векторы в Java, но кажется, что метод явно принимает тип данных "CvArr", который я не уверен, как получить... Здесь ошибка :

метод train(opencv_core.CvArr, opencv_core.CvArr) в типе opencv_contrib.FaceRecognizer не применяется для Аргументов (ArrayList, ArrayList)

кто-нибудь знает, как изменить мой ArrayList на CvArr ?!

Это мой первый пост, и я не был уверен, задавать ли все три вопроса в одном посте или в трех сообщениях, так что извините за любые неудобства... Если вам нужна любая другая информация о проект, не стесняйтесь спрашивать.

2 ответов


обновление

следующая статья была написана Петтер Кристиан Бьелланд, так что весь кредит его. Я размещаю его здесь, потому что его блог, кажется, находится в режиме обслуживания в данный момент, но я думаю, что стоит поделиться.

делаешь распознавания лиц с JavaCV (с http://pcbje.com)

я не смог найти учебник о том, как выполнять распознавание лиц с помощью OpenCV и Java, поэтому я решил поделиться жизнеспособным решение здесь. Решение очень неэффективно в его нынешнем виде, так как модель обучения строится на каждом прогоне, однако она показывает, что необходимо, чтобы заставить его работать.

классом ниже принимает два аргумента: путь к каталогу с подготовки лица и путь к изображению, которое вы хотите классифицировать. Не то, чтобы все изображения должны быть одинакового размера и что лица уже должны быть обрезаны из их исходных изображений (посмотрите здесь, Если вы не сделали обнаружение лица еще.)

для простоты этого сообщения класс также требует, чтобы обучающие изображения имели формат файла:<label>-rest_of_filename.png. Например:

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

... и так далее.

код:

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);
  }
}

класс требует интерфейса OpenCV Java. Если вы используете Maven, вы можете получить необходимые библиотеки со следующим 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>

Оригинальное Сообщение

цитата из моего ответа на http://answers.opencv.org/question/865/the-contrib-module-problem.

никогда не используя javacv, давайте посмотрим, как далеко мы можем зайти, просто глядя на интерфейсы! Проект находится на googlecode, что позволяет легко просматривать код:http://code.google.com/p/javacv.

сначала посмотрите, как cv::FaceRecognizer была разбита (opencv_contrib.java, строка 845 на момент написания это):

@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);
}

Ага, так что вам нужно пройти MatVector для изображений! Вы можете передать метки в CvArr (одна строка или один столбец). The MatVector определена в opencv_core, строка 4629 (на момент написания этого) и выглядит это так:

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);
}

опять же, просто посмотрев на код, я думаю, его можно использовать следующим образом:

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);
}

вы, вероятно, хотите написать себе метод, который выполняет преобразование из Java ArrayList до MatVector (если такая функция еще не существует в javacv).

теперь к вашему второму вопросу. FaceRecognizer эквивалентно cv::FaceRecognizer. Собственные классы OpenCV C++ возвращают cv::Ptr<cv::FaceRecognizer>, который является (умным) указателем на cv::FaceRecognizer. Это тоже нужно завернуть. Видишь здесь закономерность?

интерфейс FaceRecognizerPtr теперь выглядит так:

@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);
}

так что вы можете либо получить FaceRecognizer из этого класса или поставить FaceRecognizer што. Вы должны только будьте обеспокоены get(), так как указатель заполняется методом создания бетона :

@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*/);

таким образом, как только вы получили FaceRecognizerPtr, вы можете делать такие вещи, как:

// 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);

это учит вас модели собственных лиц. И это все!


Я сделал android-приложение для распознавания лиц с помощью opencv. Для хорошего распознавания вам нужно лучшее обнаружение, вы можете проверить его из:https://github.com/yaylas/AndroidFaceRecognizer Надеюсь, это поможет.