0

I am trying to write a simple software that, given a set of images, recognise if the person I am looking is in that set. By looking at the openCV doc I came across the class FaceRecognizer. I have tried to look for examples and this one was the only one I was able to find: https://github.com/bytedeco/javacv/blob/master/samples/OpenCVFaceRecognizer.java

I have made some replacements because some classes were not available in Java since I am not using org.bytedeco. This is the updated code:

/**
 * 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 http://fivedots.coe.psu.ac.th/~ad/jg/nui07/index.html 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.
 *
 * Source: http://pcbje.com/2012/12/doing-face-recognition-with-javacv/
 *
 * @author Petter Christian Bjelland
 */
public class OpenCVFaceRecognizer {
    public static void main(String[] args) {
        String trainingDir = args[0];
        Mat testImage = Imgcodecs.imread(args[1], Imgcodecs.IMREAD_GRAYSCALE);

        File root = new File(trainingDir);

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

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

        List<Mat> images = new ArrayList<>(imageFiles.length);

        Mat labels = new Mat(imageFiles.length, 1, CvType.CV_32SC1);
        IntBuffer labelsBuf = labels.createBuffer();

        int counter = 0;

        for (File image : imageFiles) {
            Mat img = Imgcodecs.imread(image.getAbsolutePath(), Imgcodecs.IMREAD_GRAYSCALE);

            int label = Integer.parseInt(image.getName().split("\\-")[0]);

            images.add(counter, img);

            labelsBuf.put(counter, label);

            counter++;
        }

        FaceRecognizer faceRecognizer = FisherFaceRecognizer.create();
        // FaceRecognizer faceRecognizer = EigenFaceRecognizer.create();
        // FaceRecognizer faceRecognizer = LBPHFaceRecognizer.create();

        faceRecognizer.train(images, labels);

        //IntPointer label = new IntPointer(1);
        int[] label = new int [1];
        //DoublePointer confidence = new DoublePointer(1);
        double[] confidence = new double [1];
        faceRecognizer.predict(testImage, label, confidence);
        int predictedLabel = label[0];

        System.out.println("Predicted label: " + predictedLabel);
    }
}

My questions are:

  1. .createBuffer() does not exist for the Mat class in the opencv dependency. So, how can I replace it?
  2. Why do all images have to be of the same size? Because of course the training directory has images of different sizes.
  3. Why the faces have to be already cropped out? I am able to successfully detect a face by drawing a rectangle (if you want I can share the code here as well). So, I should save the detected faces to file or I can simply create a new instance of BufferedImages with the area of the detected face?
  4. What are labels and what's their use? Simply to determine that those photos represent the same person? For instance: 1-jon_at_the_sea.png 1-jon_at_the_beach.png

Thank you.

gutey
  • 56
  • 6

0 Answers0