'''Intelligence artificielle'''

'''Réseau de neurones Convolution d’images Détection de contours - Couleurs'''

# ---- Modifications ---- #
# A voir dans le code sous cette forme
# ----------------------- #

## Lecture des images

# Affichage

import matplotlib.pyplot as plt
plt.close('all')

def f_Affiche(fig,image):
    plt.figure(fig)
    plt.imshow(image)
    plt.axis('off')
    plt.show()
    plt.pause(0.01)

# Lecture des images

def f_Lecture(Chemin):
    Image = plt.imread(Chemin)
    Image = Image[:,:,:3] # Si RGBA
    return Image

# Lecture et affichage de l'image fournie

Chemin = "Image.bmp"
Image = f_Lecture(Chemin)
f_Affiche(1,Image)

## Fonctions de transformation

# Imports

import numpy as np

# Données des transformations globales pour la suite

kr,kg,kb = 1/3,1/3,1/3
S = 60 # Seuil NB - Plus il est petit, plus il y a de blanc
K = np.array([[0,1,0],[1,-4,1],[0,1,0]]) # Noyau de convolution dimension 3
n = np.shape(K)[0]

# Nuances de gris

def f_NG(im):
    '''Passage d'une image quelconque en nuances de gris (R=G=B entre 0 et 255)'''
    Nl,Nc = im.shape[0:2]
    imng = np.copy(im)
    for c in range(Nc):
        for l in range(Nl):
            R,G,B = im[l,c]
            Nuance = kr * R + kg * G + kb * B
            Nuance = int(round(Nuance,0))
            imng[l,c,:] = Nuance
    return imng

# Noir et blanc

def f_NB(im):
    '''Passage d'une image quelconque en noir et blanc (0 ou 255)'''
    Nl,Nc = im.shape[0:2]
    imnb = np.copy(im)
    for c in range(Nc):
        for l in range(Nl):
            R,G,B = im[l,c]
            Nuance = kr * R + kg * G + kb * B # Inutile sur image NG
            if Nuance < S:
                NB = 0
            else:
                NB = 255
            imnb[l,c,:] = NB
    return imnb

# Convolution

def f_Conv_Loc(M,K):
    '''Produit de convolution local renvoyant le triplet RGB associé à l'image local M et le noyau K'''
    def f_RGB(i):
        M_RGB = M[:,:,i]
        Prod = K*M_RGB
        Somme = np.sum(Prod)
        RGB = int(Somme)
        RGB = max(min(RGB,255),0)
        return RGB
    R = f_RGB(0)
    G = f_RGB(1)
    B = f_RGB(2)
    return [R,G,B]

'''
La normalisation de K est inutile dans ce TD, la somme des coefficients vaut 0 dans le Laplacien
'''

def f_Convolution(im,f_conv_loc,K):
    '''Convolution de toute l'image, bords supprimés'''
    Nl,Nc = im.shape[0:2]
    k = n//2
    Im_Conv = np.copy(im)
    for c in range(k,Nc-k):
        for l in range(k,Nl-k):
            Im_Loc = im[l-k:l+k+1,c-k:c+k+1]
            Im_Conv_Loc = f_conv_loc(Im_Loc,K)
            Im_Conv[l,c] = Im_Conv_Loc
    Im_Conv = Im_Conv[k:-k,k:-k,:]
    return Im_Conv

# Test de filtrage

Image_NG = f_NG(Image)
f_Affiche(2,Image_NG)
Image_Conv = f_Convolution(Image_NG,f_Conv_Loc,K)
f_Affiche(3,Image_Conv)
Image_NB = f_NB(Image_Conv)
f_Affiche(4,Image_NB)

## Création de la convolution locale totale

def f_Conv_loc_NB(Mng,K):
    '''Convolution locale de la petite image en nuances de gris Mng de dimensions nxn'''
    # Convolution locale
    R = 0
    for l in range(n):
        for c in range(n):
            tk = K[l,c]
            RM = Mng[l,c,0]
            R += tk*RM
    R = int(round(R))
    R = max(min(R,255),0)
    # N&B
    if R < S:
        Val = 0 # Noir
    else:
        Val = 255 # Blanc
    return [Val,Val,Val]

# Test de filtrage

Image_Conv_Tot = f_Convolution(Image_NG,f_Conv_loc_NB,K)
f_Affiche(10,Image_Conv_Tot)

## Données pour le RN

# Question 1

from random import randint as rd
def f_Aleat_NG():
    im = np.zeros((n,n,3),dtype='uint8')
    for i in range(n*n):
        l = i // n
        c = i % n
        v = rd(0,255)
        im[l,c,:] = v,v,v
    return im

# ---- Modifications ---- #
# f_Aleat_NG -> f_Aleat
# Nouvelle fonction générant une image aléatoire en couleurs
# ----------------------- #

def f_Aleat():
    im = np.zeros((n,n,3),dtype='uint8')
    for i in range(n*n):
        l = i // n
        c = i % n
        r,g,b = rd(0,255),rd(0,255),rd(0,255)
        im[l,c,:] = r,g,b
    return im

Im_Alea = f_Aleat()
f_Affiche(20,Im_Alea)

# Question 2

def f_Analyse(imng):
    '''imng a des triples de valeurs identiques R=G=B'''
    Nl,Nc = imng.shape[0:2]
    L_R = []
    for l in range(Nl):
        for c in range(Nc):
            R = imng[l,c,0]
            R = R/255 # Normalisation
            R = float(R) # Evite des np.float de partout
            L_R += [R]
    return L_R

# ---- Modifications ---- #
# Nouvelle fonction renvoyant la liste RGB et non R seul - Ecrase la précédente
# ----------------------- #

def f_Analyse(im):
    Nl,Nc = im.shape[0:2]
    L_RGB = []
    for l in range(Nl):
        for c in range(Nc):
            R,G,B = im[l,c]/255
            L_RGB += [R,G,B]
    return L_RGB

# Question 3

def f_creation_donnees(N):
    Sources = []
    Cibles = []
    for i in range(N):
        print((i+1),"/",N)
        # Sources
        M = f_Aleat() # Modification: f_Aleat_NG -> f_Aleat
        Analyse = f_Analyse(M)
        Sources.append(Analyse)
        # Cibles
        M_NG = f_NG(M) # Modification: Création M_NG
        Pix = f_Conv_loc_NB(M_NG,K)
        Val = Pix[0]/255 # Normalisation # Vaut 0 ou 1
        Cibles.append(Val)
    return Sources,Cibles

N = 10000 # Permet 99% de réussite du rn

print("Création des données sources et cibles...")
Donnees_Sources,Donnees_Cibles = f_creation_donnees(N)

## Question 4 - Apprentissage

# Découpage des données

print('Découpage des données...')

from sklearn.model_selection import train_test_split
x = Donnees_Sources
y = Donnees_Cibles
x_train,x_test,y_train,y_test = train_test_split(x,y)

# Entrainement

print('Entrainement du réseau de neurones...')
from sklearn.neural_network import MLPClassifier
rn = MLPClassifier(solver='sgd')
rn.fit(x_train,y_train)

# Sauvegarde - Chargement du modèle

from joblib import dump
dump(rn,'rn_col.joblib')
'''
from joblib import load
rn = load('rn_col.joblib')
'''

# Performance

Score = rn.score(x_test,y_test)
Score = int(Score*10000)/100
print("Score:",Score,"%")

## Exploitation

# Question 5

def f_Conv_loc_rn(M,_): # Modification: M_NG -> M
    Donnee = f_Analyse(M) # Modification: M_NG -> M
    Res = rn.predict([Donnee])[0]
    Val = 255*Res # Dénormalisation
    return [Val,Val,Val]

# Test de filtrage par RN

Image_Conv_rn = f_Convolution(Image,f_Conv_loc_rn,K) # Modification: Image_NG -> Image
f_Affiche(30,Image_Conv_rn)
