OpenCV Yüz Tanıma Eigenfaces, Fisherfaces, LBPH

Daha önce buradaki yazımda yüz tanımaya giriş yapmıştık, bu yazıda yüz tanıma için OpenCV de üç adet algoritma olduğunu belirtmiştik (Eigenfaces, Fisherfaces, LBPH ). Örnek olarak kullanılabilecek veritabanlarına da değinmiştik bu örnekte de att örnek yüz veri tabanını kullanacağız. Örnek uygulamayı JavaCV ile gerçekleştirereceğiz. Öncelikle JavaCV hakkında bilgi için buradaki yazıma göz atabilirsiniz.

Bu algoritmalar için yapılmış bir çok çalışma mevcut daha akademik bir çalışma içerisindeyseniz veya algoritmaların mantığını kavramak istiyorsanız bu konuda bilgi edinebileceğiniz bazı kaynakların linkine yazının altından erişebilirsiniz.

Bu algoritmalar öncelikle bir eğitim gerektirir. Eğitim yüz resimlerinin algoritmaya verilerek bu görüntülerden bir vektör oluşturur bu vektör eğitimde kullanılan yüzlerin belirgin özelliklerinden oluşur. Bu sayede elde edilen vektör veri tabanındaki tüm yüzlerden yararlanarak oluşturulmuş olur. Daha sonra karşılaştırma için gönderilecek yüzler bu vektör ile karşılaştırılır. Her eğitim sonrası, bu vektör değişir ve eğitim için kullanılan veri ne kadar fazla ise başarı oranı da bir o kadar artar.

Algoritmanın Eğitilmesi

Eğitim için en az iki adet görüntüye ihtiyaç vardır ve eğitim için kullanılacak her dosyanın genişliği ve yüksekliği aynı boyutta olmalıdır. Eğitim için örnek veritabanlarını indirip kullanacağınız gibi kendinizde çekmiş olduğunuz resimleri kullanabilirsiniz. Kullanılacak görsellerin formatları genellikle jpg, jpeg, png, pmg vb. dir. Att veritabanını indirirseniz, içerisindeki görüntü formatları pmg dir.

OpenCV de eğitim için FaceRecognizer sınıfı altında train() metodu mevcuttur. Bu metot parametre olarak eğitim için kullanılacak mat vektörlerini yani yüzleri ve bu yüzler için kullanılacak etiketleri (label) alır. Etiket kavramını daha önce açıklamıştık fakat tekrardan değinmek gerekirse, eğitilen her yüz görüntüsünün eşleşme sonucunda adlandırılması için verdiğimiz id numaralarıdır. Bu etiketler görüntü dosyasının isimlerinde kullanılır. Örneğin att içerisinde 1.pgm 2.pgm olarak giderken bazı veritabanlarında 1-jon_doe_1.pgm veya 1-jon_doe.jpg gibi olabilir. Bu etiketler yüzün kime ait olduğunu belirlemek için kullanılabilir.

eigenface_dataset

Bizim kullanacağımız att veritabanında 1.pgm olarak adlandırılmış fakat benimde kullanışlı bulduğum 1-jon_doe_1.pgm etiketlendirmesini kullanacağız. 1-jon_doe_1.pgm isimlendirmesinde ilk rakam kişinin id numarası, ikincisi tahmin edebileceğiniz üzere kişinin ismi ve sonuncu rakam ise bu kişinin veritabanında ki yüz sayısına göre verilmiş id si, örneğin jon doe kişsinin veritabanında 2 adet yüzü varsa isimlendirmesi 1-jon_doe_1.pgm ve 1-jon_doe_2.pgm şeklinde olacaktır.

Eğitim için kullanacağımız yüz görüntülerini okurken gri renk uzayına çevireceğiz. Renk uzayları hakkında daha detaylı bilgi almak isterseniz buradaki yazıma , renk uzayları arası dönüşüm içinde bu yazıya göz atabilirsiniz.

facedb
Hazırladığım örnek veri seti

Eşleştirme

Öncelikle eğitim için kullanacağımız yüz veri setinin dosya dizinine giderek buradaki tüm görüntüleri alacağız. Bu görüntülerin etiketlerini almak için split edeceğiz, bu işlemin ardından görüntüleri ve etiketleri train() metoduna vererek eğitimi tamamlayacağız. FaceRecognizer  sınıfınının predict metodu ile eşleştirme için bir yüz vereceğiz. Bu metot işlem sonucunda aradığımız yüz veri setinde eşleşiyor ise yani yüz veritabanında var ise bu yüzün etiketini döndürecektir. predict metodunun farklı overloadları vardır bunlara buradaki bağlantıdan ve şekilden göz atabilirsiniz. Eşleşme değerlerini ve birden fazla kayıt ile eşleşiyor ise, bunların hepsini almak için parametre olarak double ve int tipinde diziler metoda veriler. Bu diziler işlem sonucu etiketler ve eşleşme oranları ile doldurulur. Veya sadece eşleştirme resmini parametre olarak vererek eşleşen yüzün etiketini alabilirsiniz.

 

Predict Metodunun Overloadları
Predict Metodunun Overloadları

Aşağıdaki örnek kodda  Eigenfaces, Fisherfaces, LBPH  algoritmaları kullanılabilir durumdadır, kullanmak istediğiniz algoritmayı seçerek diğerlerini yorum satırı haline getirmeniz yeterli olacaktır. Uygulamaya istediğiniz gibi görsellik katarak projelerinize uyarlayabilirsiniz.

import java.io.File;
import java.io.FilenameFilter;
import java.nio.IntBuffer;

import static org.bytedeco.javacpp.opencv_core.CV_32SC1;
import static org.bytedeco.javacpp.opencv_core.CV_8UC1;
import static org.bytedeco.javacpp.opencv_face.createFisherFaceRecognizer;
import static org.bytedeco.javacpp.opencv_face.createEigenFaceRecognizer;
import static org.bytedeco.javacpp.opencv_face.createLBPHFaceRecognizer;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.opencv_face.FaceRecognizer;
import org.bytedeco.javacpp.opencv_core.Mat;
import org.bytedeco.javacpp.opencv_core.MatVector;
import org.bytedeco.javacpp.opencv_face;
import static org.bytedeco.javacpp.opencv_highgui.cvWaitKey;
import static org.bytedeco.javacpp.opencv_highgui.imshow;
import static org.bytedeco.javacpp.opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE;
import static org.bytedeco.javacpp.opencv_imgcodecs.imread;


public class OpenCVFaceRecognizer {

    public static void main(String[] args) {
        //Eğitim için kullanacağım veri setinin dizini
        String trainingDir = "C:/Users/mesutpiskin/Desktop/faces/";
        //Eşleştirme için kullanacağım diğer yüz
        Mat testImage = imread("C:/Users/mesutpiskin/Desktop/40.pgm", CV_LOAD_IMAGE_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);

        MatVector images = new MatVector(imageFiles.length);

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

        int counter = 0;

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

            int label = Integer.parseInt(image.getName().split("\\-")[0]);
            System.out.println("Eğitilen Yüz: "+label);
            images.put(counter, img);

            labelsBuf.put(counter, label);

            counter++;
        }
         FaceRecognizer faceRecognizer = createEigenFaceRecognizer();
        //FaceRecognizer faceRecognizer = createFisherFaceRecognizer();        
        //FaceRecognizer faceRecognizer = createLBPHFaceRecognizer();

        faceRecognizer.train(images, labels);

     
        int predictedLabel =  faceRecognizer.predict(testImage);
        faceRecognizer.predict(testImage);
        System.out.println("Bulunan Yüz ID: " + predictedLabel);
        cvWaitKey(0);
    }
}

İşlem Sonucu

yuz_tanima_sonuc

 


Yararlanabileceğiniz Kaynaklar
  • http://acikarsiv.ankara.edu.tr/browse/24480/
  • http://www.shedai.net/yildiz/sekiltanima/eigenfacerecognition.pdf
  • http://docs.opencv.org/2.4/modules/contrib/doc/facerec/facerec_api.html
  • http://docs.opencv.org/2.4/modules/contrib/doc/facerec/facerec_tutorial.html
  • http://www.vision.jhu.edu/teaching/vision08/Handouts/case_study_pca1.pdf
  • http://www.face-rec.org/algorithms/PCA/jcn.pdf
  • https://github.com/bytedeco/javacv/tree/master/samples