"""
Programme   : TP-images-partie3-correction-exo1.py
Langage     : Python 3.7.3
Modules     : Pillow 7.1.2
Auteur      : Mathieu Pons
Description : mise en oeuvre des filtres de convolution
Pillow      : https://pillow.readthedocs.io/en/stable/

Exercice à réaliser :
	1) Convertir votre image test en niveaux de gris en utilisant la méthode d'image disponible dans la librairie Pillow.
	Mettre en place un mécanisme de gestion des exceptions au cas où le fichier image spécifié n'existerai pas.
	2) Ecrire une fonction qui renvoit la matrice des voisins d'un pixel.
	3) Ecrire une fonction qui renvoit le produit de convolution des deux matrices K et V.
	4) Ecrire une fonction qui applique un filtre de flou et un filtre réhausseur de contraste à une image
"""

# IMPORT =========================================================================================
from PIL import Image, ImageOps
import math

# FONCTIONS =======================================================================================
def sauver_gris(pname):
	"""
	Description : 	convertit en gris le fichier image nommé pname et sauvegarde le résultat en préfixant le nom avec gris-
	Paramètres 	: 	type(pname) => str
	Retour 		: 	aucun
	"""
	try:
		img = Image.open(pname) # tentative d'ouverture du fichier pname
	except:
		print("Impossible d'ouvrir le fichier " + pname)
		return # on retourne au programme principal sans rien faire si l'ouverture du fichier a échoué

	# Si le fichier a pu être ouvert, on le convertit en niveaux de gris et on le sauvegarde
	img_gris = ImageOps.grayscale(img)
	img_gris.save("gris-" + pname, "PNG")

def voisinage(pimg, px, py):
	"""
	Description : 	construit la matrice carrée 3x3 au voisinage du pixel (px, py)
	Paramètres 	: 	type(pimg) => PIL.Image ; type(px, py) => (int, int)
	Retour 		: 	liste de listes 3x3
	"""
	return [[pimg.getpixel((px - 1, py - 1)), pimg.getpixel((px, py - 1)), pimg.getpixel((px + 1, py - 1))],
			[pimg.getpixel((px - 1, py    )), pimg.getpixel((px, py    )), pimg.getpixel((px + 1,     py))],
			[pimg.getpixel((px - 1, py + 1)), pimg.getpixel((px, py + 1)), pimg.getpixel((px + 1, py + 1))]]

def convolution(K, V):
	"""
	Description : 	effectue le produit de convolution de K par V
	Paramètres 	: 	type(K, V) => liste de listes 3x3
	Retour 		: 	int
	"""
	return  K[0][0] * V[0][0] + K[1][0] * V[1][0] + K[2][0] * V[2][0] + \
			K[0][1] * V[0][1] + K[1][1] * V[1][1] + K[2][1] * V[2][1] + \
			K[0][2] * V[0][2] + K[1][2] * V[1][2] + K[2][2] * V[2][2]

def filtrer(K, pnorme, pname):
	"""
	Description : 	applique le filtre défini par le noyau K sur le fichier image pname
					pnorme vaut la somme des coefficients positifs de la matrice K
	Paramètres 	: 	type(K, V) => liste de listes 3x3 ; type(pnorme) => int ; type(pname) => str
	Retour 		: 	Image.PIL ou None si le chargement a échoué
	"""
	try:
		img = Image.open(pname)
	except:
		print("Impossible d'ouvrir le fichier " + pname)
		return

	img.show()
	larg = img.width
	haut = img.height
	img_retour = Image.new("L", (larg, haut))
	for y in range(1, haut - 1): # on ignore la première et dernière colonne de l'image
		for x in range(1, larg - 1): # on ignore la première et dernière ligne de l'image
			V = voisinage(img, x, y) # on charge les voisins du pixel de coordonnées (x, y) dans une matrice
			gris = int(convolution(K, V) / pnorme) # on effectue le produit de convolution de K par V qu'on normalise
			img_retour.putpixel((x, y), gris)
	return img_retour

# PROGRAMME PRINCIPAL =============================================================================
# Question 1
# sauver_gris("paf.png")

# Questions 2, 3, 4
# Noyau de convolution appliquant un effet de flou à l'image
K_f = 	[[1, 1, 1],
		 [1, 1, 1],
		 [1, 1, 1]]
img = filtrer(K_f, 9, "gris-paf.png")
if img == None:
	print("Echec dans l'application du filtre")
else:
	img.show()

# Noyau de convolution appliquant un effet de flou Gaussien à l'image
K_g = 	[[1, 2, 1],
		 [2, 4, 2],
		 [1, 2, 1]]
img = filtrer(K_g, 16, "gris-paf.png")
if img == None:
	print("Echec dans l'application du filtre")
else:
	img.show()

# Noyau de convolution appliquant un effet réhausseur de contraste
K_c = 	[[0 , -1,  0],
		 [-1,  5, -1],
		 [0 , -1,  0]]
img = filtrer(K_c, 1, "gris-paf.png")
if img == None:
	print("Echec dans l'application du filtre")
else:
	img.show()
