# -*- coding: utf-8 -*-
"""
Autor: MICHAL KOUPIL
"""

#DETEKCE OBLIČEJŮ METODOU VIOLA-JONES A NÁSLEDNÉ ROZPOZNÁNÍ METODOU PCA
#TRÉNOVACÍ A TESTOVACÍ SADA OBRAZŮ SE NASTAVUJÍ V NAČTENÍ TRÉNOVACÍ (line 28 a 29)
# A TESTOVACÍ (line 87 a 88) SADY OBRAZŮ

import sys 
sys.path.append('/Users/michal.koupil/AppData/Local/Programs/Python/Python37/Lib/site-packages')
#načtení knihoven
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import os
import matplotlib.patches as patches
from sklearn.decomposition import PCA
from statistics import mean
import math
import time
start_time = time.time()


#Načtení trénovací sady obrazů
cropped_images=[]
images=[]
for i in os.listdir('trenovaci_sada_3'): 
	images.append(cv.imread('trenovaci_sada_3/{0}'.format(i),0))   
    
#Viola-Jones algoritmus - detekce obličeje v obraze    
def viola_jones(images,cropped_images):
    for i in range(len(images)):    
        image=images[i]
        face_cascade = cv.CascadeClassifier('haarcascade_frontalface_alt.xml') 
        detected_face = face_cascade.detectMultiScale(image)
        try:
            face = image[detected_face[0][1]:detected_face[0][1]+detected_face[0][3],
                     detected_face[0][0]:detected_face[0][0]+detected_face[0][2]] 
        except IndexError:
            face = 'null'
        cropped_images.append(face)

viola_jones(images, cropped_images)    

#odstranění obrazů, ve kterých nebyl detekován obličej
cropped_images_orig = np.array(cropped_images,dtype=object)  
cropped_images = [x for x in cropped_images if not isinstance(x, str)]

#Změna měřítka obrazů
widths = []
heights = []
for i in range(len(cropped_images)):
    widths.append(cropped_images[i].shape[0])
    heights.append(cropped_images[i].shape[1])
    
m1 = min(heights)
m2 = min(widths)
resized = []
for i in range(len(cropped_images)):
    resized.append(cv.resize(cropped_images[i],(m1,m2)))
vec_pictures=[]

#Převedení trénovací sady obrazů do PCA matice
for i in range(len(cropped_images)):
    vec_pictures.append(resized[i].flatten())
vec_pictures = np.array(vec_pictures)
pca = PCA().fit(vec_pictures)

#výběr nejvýznamnějších komponent
sig = pca.components_[:round(len(cropped_images)/6)]  

#Zobrazení x nejvýznamnějších eigenfaces
'''s1=5
s2=5
fig, axes = plt.subplots(s1,s2,figsize=(10,10))
for i in range(s1*s2):
    axes[i%s1][i//s2].imshow(sig[i].reshape(m1,m2), cmap="gray")
plt.show()'''

#Spočítání váhy pro vstupy
weights = sig @ (vec_pictures - pca.mean_).T

#Načtení testovací sady obrazů
cropped_images_test=[]
images_test=[]
for i in os.listdir('testovaci_sada_3'): 
	images_test.append(cv.imread('testovaci_sada_3/{0}'.format(i),0))

#Detekce obličejů v testovací sadě    
viola_jones(images_test, cropped_images_test)  

a=[]
a=list(range(0,len(images)))
a=np.array(a)
match_counter = 0 
cropped_image = []
pos = [0] 
min_distances=[]
distances=np.zeros((len(cropped_images),1))
sumy=[]

resized_test = []
for i in range(len(cropped_images_test)):
    resized_test.append(cv.resize(cropped_images_test[i],(m1,m2)))


#Porovnávání jednotlivých snímků testovací sady s trénovací sadou
for i in range(len(resized_test)):
    testing_image = cropped_images_test[i]
    testing_pic = resized_test[i].flatten()
    testing_pic_weight = sig @ (testing_pic - pca.mean_).T
    euc_dist = []
    for j in range(weights.shape[1]):
        dist = np.linalg.norm(weights[:,j] - testing_pic_weight)
        euc_dist.append(dist)

    #Nejlepší shoda (výpočet euklidovské vzdálenosti)
    distances = np.c_[distances,euc_dist]
    min_dist = np.argmin(euc_dist)
    min_distances.append(euc_dist[min_dist])
    cropped_image = np.array(cropped_images[min_dist],dtype=object)
    for j in range(len(cropped_images_orig)):
        if (np.array_equal(cropped_image, cropped_images_orig[j])) == True:
            pos.append(j)
    #Graf vyhodnocení
    fig, axes = plt.subplots(1,2,figsize=(10,6))
    axes[0].imshow(testing_image, cmap="gray")
    axes[0].set_title("testing picture - person " + str(a[i+1]))
    axes[1].imshow(cropped_images[min_dist], cmap="gray")
    axes[1].set_title("BEST MATCH")
    plt.show()   

len_im_test = str(len(images_test))
print("--- %s seconds ---" % (time.time() - start_time))

'''
#Statistické vyhodnocení FAR a FRR

#Určení prahu
threshold = 0.05

#Normalizace dat na 0 - 1
distances = distances[:,1:]
def NormalizeData(data):
    return (data - np.min(data)) / (np.max(data) - np.min(data))

normalized_dist=np.zeros((len(cropped_images),1))
data=[]

for i in range(distances.shape[1]):
    data = NormalizeData(distances[:,i])
    normalized_dist = np.c_[normalized_dist,data]
    
normalized_dist = normalized_dist[:,1:]
s = (distances.shape[0],distances.shape[1])
distances_bool = np.zeros(s)

#Podmínka pro určení zda daný prvek překračuje práh
for i in range(distances.shape[0]):
    for j in range(distances.shape[1]):
        if (normalized_dist[i,j] < threshold):
            distances_bool[i,j] = 1
        else:
            distances_bool[i,j] = 0
            
#Pomocný vektor pro vytvoření matic na výpočet FAR a FRR 
rid = list(range(0,210,10))

#výpočet FAR a FRR 
counterFAR = 0     
for i in range(distances_bool.shape[0]):
    for j in range(distances_bool.shape[1]):
        if (distances_bool[i,j] == 1) & (i != rid[j] + 1) & (i != rid[j] + 2) & (i != rid[j] + 3) & (i != rid[j] + 4) & (i != rid[j] + 5) & (i != rid[j] + 6) & (i != rid[j] + 7) & (i != rid[j] + 8) & (i != rid[j] + 9):
            counterFAR += 1
aFAR = (counterFAR/(len(images_test)*len(cropped_images))) * 100 
 
counterFRR = 0               
for i in range(distances_bool.shape[0]):
    for j in range(distances_bool.shape[1]):
        if ((distances_bool[i,j] == 0) & (i == rid[j] + 1)) | (distances_bool[i,j] == 0) & (i == rid[j] + 2) | (distances_bool[i,j] == 0) & (i == rid[j] + 3) | (distances_bool[i,j] == 0) & (i == rid[j] + 4) | (distances_bool[i,j] == 0) & (i == rid[j] + 5)| (distances_bool[i,j] == 0) & (i == rid[j] + 6) | (distances_bool[i,j] == 0) & (i == rid[j] + 7) | (distances_bool[i,j] == 0) & (i == rid[j] + 8) | (distances_bool[i,j] == 0) & (i == rid[j] + 9):
            counterFRR += 1            
aFRR = (counterFRR/(len(images_test)*10)) * 100
'''

