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

#DETEKCE OBLIČEJŮ METODOU VIOLA-JONES A NÁSLEDNÉ ROZPOZNÁNÍ METODOU LBPH
#TRÉNOVACÍ A TESTOVACÍ SADA OBRAZŮ SE NASTAVUJÍ V NAČTENÍ TRÉNOVACÍ (line 25 a 26)
# A TESTOVACÍ (line 96 a 97) SADY OBRAZŮ

import sys 
sys.path.append('/Users/michal.koupil/AppData/Local/Programs/Python/Python37/Lib/site-packages')

import os
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import math
import time
start_time = time.time()

#načtení trénovací sady obrazů
cropped_images=[]
images=[]
for i in os.listdir('trenovaci_sada_1'): 
	images.append(cv.imread('trenovaci_sada_1/{0}'.format(i),0))
    
  
#Viola - Jones algoritmus - lokalizace 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
a=[]
a=list(range(0,len(images)))
a=np.array(a)
indexes=[]
for i in range(len(a)):
    if cropped_images[i] is 'null':
        pass
    else:
        indexes.append(i)
        
cropped_images_orig = np.array(cropped_images,dtype=object)        
cropped_images = [x for x in cropped_images if not isinstance(x, str)]

widths = []
heights = []
for i in range(len(cropped_images)):
    widths.append(cropped_images[i].shape[0])
    heights.append(cropped_images[i].shape[1])

#vytvoření označení trénovací sady
a=[]
a=list(range(0,len(cropped_images)))
a=np.array(a)
    
#trénování modelu a uložení histogramů
#parametry modelu - rádius, sousedství, počet gridů v X ose, počet gridů v Y ose
indexes=np.array(indexes)
trained_model = cv.face.LBPHFaceRecognizer_create(1,8,8,8)
trained_model.train(cropped_images,a)   
trained_model.write('LBPH_classifier.yml')
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.read('LBPH_classifier.yml')
histograms = trained_model.getHistograms()

#Ukázka histogramu
'''hist = histograms[1]
y= list(range(16384))
x=hist.tolist()
x=x[0]
plt.plot(y,x)
plt.show()

fig, axes = plt.subplots(1,2,figsize=(10,6))
axes[0].imshow(cropped_images[1], cmap="gray")
axes[0].set_title("vstupní obraz")
axes[1].plot(y,x)
axes[1].set_title("finální histogram")'''

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

#Detekce obličejů v testovací sadě    
viola_jones(images_test, cropped_images_test)
cropped_image = []
pos = [0]

#Porovnávání jednotlivých snímků testovací sady s trénovací sadou
for i in range(len(cropped_images_test)):
    testing_pic = cropped_images_test[i]
    #Nejlepší shoda (výpočet euklidovské vzdálenosti) 
    idx, confidence = recognizer.predict(testing_pic)
    cropped_image = np.array(cropped_images[idx],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_pic, cmap="gray")
    axes[0].set_title("testing picture - person " + str(a[i+1]))
    axes[1].imshow(cropped_images[idx], 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

#Práh
threshold = 0.05

#Získání histogramů pro testovací sadu
a=[]
a=list(range(0,len(cropped_images_test)))
a=np.array(a)
trained_model = cv.face.LBPHFaceRecognizer_create(1,8,8,8)
trained_model.train(cropped_images_test,a)   
trained_model.write('LBPH_classifier.yml')
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.read('LBPH_classifier.yml')
histogram = trained_model.getHistograms()

#Funkce pro normalizaci dat do intervalu 0 - 1
def NormalizeData(data):
    return (data - np.min(data)) / (np.max(data) - np.min(data))

#Euklidovské vzdálenosti mezi histogramy testovací a trénovací sady
data=[]
distances=np.zeros((len(cropped_images),1))
dists=np.zeros((len(cropped_images),1))
for i in range(len(histogram)+1):
    dists = np.c_[dists,distances]
    distances = []
    for j in range(len(histograms)):
        dist = np.linalg.norm(histogram[i]-histograms[j])
        distances.append(dist)
#Vytvoření matice nul pro vyhodnocení        
dists = dists[:,2:]
s = (dists.shape[0],dists.shape[1])
distances_bool = np.zeros(s)

#Normalizace dat
data=[]
normalized_dist=np.zeros((len(cropped_images),1))
for i in range(dists.shape[1]):
    data = NormalizeData(dists[:,i])
    normalized_dist = np.c_[normalized_dist,data]
normalized_dist = normalized_dist[:,1:]

#Matice výsledků pro daný práh
for i in range(dists.shape[0]):
    for j in range(dists.shape[1]):
        if (normalized_dist[i,j] < 0.05):
            distances_bool[i,j] = 1
        else:
            distances_bool[i,j] = 0
   
#Výpočet kolik prvků se nachází za daným prahem 
counterFAR = 0   
rid = list(range(0,210,10))
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
#Výpočet FAR            
aFAR = (counterFAR/(len(images_test)*len(cropped_images))) * 100            

#Výpočet kolik prvků se nachází za daným prahem             
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    
#Výpočet FAR    
aFRR = (counterFRR/(len(images_test)*10)) * 100        
'''    
