/*
  FaceVerifier.cpp
  
  Author: Sergi Diaz Planas (2017)
*/
#include "FaceVerifier.h"
#include <iostream>

// Constructor
FaceVerifier::FaceVerifier()
{
    this->threshold = 0.6;
    this->netLoaded = false;
}

FaceVerifier::FaceVerifier(std::string file)
{
    this->threshold = 0.6;
   this->netLoaded  = loadNet(file);
}

bool FaceVerifier::loadNet(std::string file)
{
    try
    {
        dlib::deserialize(file) >> this->net;
        this->netLoaded = true;
        return true;
    }
    catch (int e)
    {
        this->netLoaded = false;
        return false;
    }
}

void FaceVerifier::setThreshold(double threshold)
{
    this->threshold = threshold;
}

bool FaceVerifier::samePerson(Face face_1, Face face_2)
{
    // Input images in cv matrix format. We need to transform those
    // into something that Dlib can comprehend.
    dlib::array2d<unsigned char> face_1_gray;
    dlib::array2d<unsigned char> face_2_gray;
    cv::Mat image_1, gray_1;
    cv::Mat image_2, gray_2;

    image_1 = face_1.getImage();
    image_2 = face_2.getImage();

    // Convert input images to grayscale for face detection
    if (image_1.channels() == 3)
        cv::cvtColor(image_1, gray_1, cv::COLOR_BGR2GRAY);
    else
        gray_1 = image_1.clone();
    if (image_2.channels() == 3)
        cv::cvtColor(image_2, gray_2, cv::COLOR_BGR2GRAY);
    else
        gray_2 = image_2.clone();

    dlib::assign_image(face_1_gray, dlib::cv_image<unsigned char>(gray_1));
    dlib::assign_image(face_2_gray, dlib::cv_image<unsigned char>(gray_2));

    // Prepare images for face verification
    dlib::matrix<unsigned char> matrix_1 = dlib::mat(face_1_gray);
    dlib::matrix<unsigned char> matrix_2 = dlib::mat(face_2_gray);
    // DNN expects color images. Hence, we transdorm grayscale images
    // into rgb images
    dlib::matrix<dlib::rgb_pixel> face_1_color;
    dlib::matrix<dlib::rgb_pixel> face_2_color;
    dlib::assign_image(face_1_color, matrix_1);
    dlib::assign_image(face_2_color, matrix_2);

    std::vector<matrix<rgb_pixel> > faces;
    faces.push_back(face_1_color);
    faces.push_back(face_2_color);

    // The size of the testing images must match that of the ones the ResNet was
    // trained with. Hence, we have to rescale the images to 150x150
    std::vector<matrix<rgb_pixel> > resized_faces;
    for (unsigned int i=0; i<faces.size(); i++) {
        matrix<rgb_pixel> resized(150, 150);
        dlib::resize_image(faces[i], resized);
        resized_faces.push_back(resized);
    }
    // Use ResNet to make comparison
    std::vector<dlib::matrix<float, 0, 1>> face_descriptors = net(resized_faces);
    float dist = length(face_descriptors[0] - face_descriptors[1]);
    // Return false if separation between images exceeds threshold, true otherwise
    return dist < this->threshold;
}

bool FaceVerifier::isLoaded()
{
    return this->netLoaded;
}



