Outils pour utilisateurs

Outils du site


diy:projets:vintage

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
diy:projets:vintage [2018/05/31 14:07] – [Le programme] tphilibertdiy:projets:vintage [2018/06/01 10:58] (Version actuelle) – [Solutions possibles et améliorations] tphilibert
Ligne 13: Ligne 13:
  
 ====Outils requis==== ====Outils requis====
-  * Un classifier entraîné dans la détection du visage, comme [[https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_frontalface_default.xml|celui-ci]]. +Aucun outil spécifique n'est requis pour faire fonctionner ce programme. 
-  * Cette [[https://github.com/JsuisUnLama/BE-2018---PHILIBERT-Thomas/blob/master/code/oof.png|image de base]]. +====Librairies==== 
-Le tout à placer dans le même dossier que celui du programme.\\ +Ce programme utilise les librairies suivantes:
-\\ +
-__Remarques:__  +
-  * Le classifier donné est celui utilisé par le programme. Vous pouvez le remplacer par n'importe quel autre classifier remplissant la même fonction mais si vous le faites, n'oubliez pas de changer son nom ici:\\+
 <code python> <code python>
-# Load XML Classifier +import cv2 
-face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')+import numpy as np 
 +import copy 
 +import random as rng 
 +import sys
 </code> </code>
-//ligne 133//.\\ +//lignes 1 à 5//.\\ 
-  * N'importe quelle image peut-être l'image de base du moment qu'elle s'appelle 'oof.png'. +\\ 
-====Librairies====+  * ''cv2'' référence la librairie [[https://opencv.org/|OpenCV]] permettant de nombreuses opérations sur les images en Python et C++\\ 
 +  * ''numpy'' référence la librairie [[http://www.numpy.org/|NumPy]] prodiguant une meilleure création/utilisation/gestion des objets à plusieurs dimensions.\\ 
 +  * ''copy'' référence la librairie [[https://docs.python.org/2/library/copy.html|copy]] en sa qualité de duplicateur de données.\\ 
 +  * ''random'' référence la librairie [[https://docs.python.org/2/library/random.html|random]] pour la génération de valeurs aléatoires.\\ 
 +  * ''sys'' référence la librairie [[https://docs.python.org/3/library/sys.html|sys]] pour la gestion des paramètres en Python. 
 + 
 +----
 ====== Explication du programme ====== ====== Explication du programme ======
 +====Le contrôle d'erreur====
 +Il s'agit d'un pan entier de code contrôlant l'arbre d'argument suivant:\\
 +{{ :diy:projets:arbre_des_arguments_vintage_1_.png |}}\\
 +Ce n'est pas nécessairement excitant mais ça permet au programme de détecter différentes erreurs, de s'arrêter dans de meilleures conditions et en indiquant l'erreur en question.
 +Si cela vous intéresse, le contrôle s'étend //lignes 163 à 196.//\\
 +----
 +====Les fonctions====
 +Ce programme contient 7 fonctions:
 +  * **generateCircleMask**(//img,center,radius//).
 +  * **cappedValue**(//value,least=0,most=255//).
 +  * **applyVariationToBGRPixel**(//pixel,var,withRNG=False,low_rng=0,high_rng=0//).
 +  * **maskDifference**(//mask1,mask2//).
 +  * **vintage**(//img//).
 +  * **options**().
 +  * **optionTime**(//time//).
 +
 +**generateCircleMask**\\
 +<code python>
 +def generateCircleMask(img,center,radius):
 +
 + h,w,v = img.shape
 + sq_rad = radius**2
 + toThreshold = cv2.cvtColor(img.astype('uint8',copy=False),cv2.COLOR_BGR2GRAY)
 + for i in range (0,h):
 + for j in range (0,w):
 + if(((i-center[0])**2 + (j-center[1])**2) <= sq_rad):
 + toThreshold[i,j] = 0
 + else:
 + toThreshold[i,j] = 255
 + ret, circleMask = cv2.threshold(toThreshold, 10, 255, cv2.THRESH_BINARY)
 + return circleMask
 +</code>
 +//lignes 9 à 21//\\
 +\\
 +La fonction prend une image //img// et renvoie un masque circulaire de centre //center// et de rayon //radius// de la même taille que celle de l'image donnée.\\
 +\\
 +
 +**cappedValue**\\
 +<code python>
 +def cappedValue(value,least=0,most=255):
 +
 + if(value < least):
 + value = least
 + elif(value > most):
 + value = most
 + return value
 +</code>
 +//lignes 25 à 31//\\
 +\\
 +La fonction prend une valeur //value// et s'assure qu'elle appartienne à l'intervalle [//least,most//].\\
 +\\
 +
 +**applyVariationToBGRPixel**\\
 +<code python>
 +def applyVariationToBGRPixel(pixel,var,withRNG=False,low_rng=0,high_rng=0):
 +
 + b,g,r = pixel
 + if(withRNG):
 + b = cappedValue(b - (var + rng.randint(low_rng,high_rng)))
 + g = cappedValue(g - (var + rng.randint(low_rng,high_rng)))
 + r = cappedValue(r - (var + rng.randint(low_rng,high_rng)))
 + else:
 + b = cappedValue(b - var)
 + g = cappedValue(g - var)
 + r = cappedValue(r - var)
 + pixel = [b,g,r]
 + return pixel
 +</code>
 +//lignes 35 à 47//\\
 +\\
 +La fonction prend un pixel \\pixel\\ (i.e. un objet à trois dimensions), une valeur \\var\\ et soustrait cette valeur uniformément aux valeurs que contient //pixel//.\\
 +Si le booléen //withRNG// est vrai, à chaque instance de var lui sera ajouté une valeur aléatoire comprise dans l'intervalle [//low_rng,high_rng//].\\
 +\\
 +
 +**maskDifference**\\
 +<code python>
 +def maskDifference(mask1,mask2):
 +
 + h,w = mask1.shape
 + mask_diff = copy.copy(mask1)
 + for i in range (0,h):
 + for j in range (0,w):
 + if(mask1[i,j] == 0 and mask2[i,j] == 255):
 + mask_diff[i,j] = 255
 + else:
 + mask_diff[i,j] = 0
 + return mask_diff
 +</code>
 +//lignes 51 à 61//\\
 +\\
 +La fonction prend deux masques //mask1// et //mask2// de même taille et renvoie le masque résultant de leur différence.\\
 +\\
 +
 +**vintage**\\
 +<code python>
 +def vintage(img):
 +
 + # Useful datas 
 + height, width, value = img.shape
 +
 + # Get Canny edges
 + grayimg = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 + edgyimg = cv2.Canny(grayimg,50,200,apertureSize=3)
 +
 + # Dilate edges
 + rect = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
 + thicc_img = cv2.dilate(edgyimg,rect,iterations=1)
 +
 + # Thickening edges
 + invertimg = cv2.bitwise_not(thicc_img)
 + colorgray = cv2.cvtColor(invertimg,cv2.COLOR_GRAY2BGR)
 + ret, mask = cv2.threshold(grayimg, 10, 255, cv2.THRESH_BINARY)
 + mask_inv = mask
 + roi = grayimg[0:height, 0:width]
 + img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
 + img2_fg = cv2.bitwise_and(img,img,mask = mask)
 + img1_bg = cv2.cvtColor(img1_bg,cv2.COLOR_GRAY2BGR)
 + addimg = cv2.add(img1_bg,img2_fg)
 + img[0:height, 0:width] = addimg
 +
 + # Speckle Noise
 + gauss = np.random.randn(height,width,value)
 + gauss = gauss.reshape(height,width,value)        
 + img = img + (img * gauss)/16
 +
 + # Sepia filter I
 + sepia = np.matrix([[0.272,0.534,0.131],[0.349,0.686,0.168],[0.393,0.769,0.189]])
 + img = cv2.transform(img,sepia)
 +
 + # Toneing
 + center_h = int(height/2)
 + center_w = int(width/2)
 + mask = generateCircleMask(img,[center_h,center_w],center_h-5)
 + outer_mask = generateCircleMask(img,[center_h,center_w],center_h+5)
 + outer_mask = maskDifference(outer_mask,mask)
 + var = 5
 + unb = 1
 + low = -2
 + high = 2
 + for i in range (0,height):
 + for j in range (0,width):
 + if(mask[i,j] == 255):
 + img[i,j] = applyVariationToBGRPixel(img[i,j],var,True,low,high)
 + elif(outer_mask[i,j] == 255):
 + img[i,j] = applyVariationToBGRPixel(img[i,j],int(var/2),True,low,high)
 +
 + # Sepia filter II
 + sepia = np.matrix([[0.272,0.534,0.131],[0.349,0.686,0.168],[0.393,0.769,0.189]])
 + img = cv2.transform(img,sepia)
 +
 + # Gaussian blur
 + img = cv2.GaussianBlur(img,(5,5),0)
 +
 + # Border
 + bs = 10
 + img = cv2.copyMakeBorder(img,bs,bs,bs,bs,cv2.BORDER_CONSTANT,value=(230,245,245))
 +
 + # Return result
 + return img
 +</code>
 +//lignes 65 à 128//\\
 +\\
 +La fonction prend une image //img//.\\
 +La partie ''#Useful Datas'' récupère la taille, la hauteur et la valeur de //img// et les place dans des variables.\\
 +La partie ''Get Canny edges'' trace les contours de l'image en niveaux de gris.\\
 +La partie ''Dilate edges'' [[https://fr.wikipedia.org/wiki/Morphologie_math%C3%A9matique#Dilatation_et_%C3%A9rosion|dilate]] ses contours.\\
 +La partie ''Thickening edge'' les désagrège de l'image originale.\\
 +La partie ''Speckle noise'' rajoute du [[https://fr.wikipedia.org/wiki/Bruit_num%C3%A9rique|bruit]] sur l'image.\\
 +La partie ''Sepia filter I'' applique un [[https://fr.wikipedia.org/wiki/S%C3%A9pia#Photographie|filtre sépia]] sur l'image.\\
 +La partie ''Toneing'' éclaircit une zone centrale de l'image.\\
 +La partie ''Sepia filter II'' applique à nouveau un filtre sépia.\\
 +La partie ''Gaussian Blur'' applique un [[https://fr.wikipedia.org/wiki/Lissage_d%27images#Filtre_gaussien|flou Gaussien à l'image]].\\
 +La partie ''Border'' génère des bordures à l'image.\\
 +La partie ''Return result'' retourne l'image ainsi changée.\\
 +\\
 +
 +**options**\\
 +<code python>
 +def options():
 + print("Nom ou chemin de l'image à traiter (avec l'extension)")
 + name_i = input("-> ")
 + print("")
 + image = cv2.imread(name_i)
 + try:
 + dtype_debug = image.dtype
 + except AttributeError as ae:
 + print("Erreur,",name_i,"ne peut pas être lu (fichier invalide ou absent)\n")
 + raise ae 
 +
 + print("Quel nom donner à l'image en sortie (avec l'extension)?")
 + name_o = input("-> ")
 + print("")
 +
 + return image,name_o
 +</code>
 +//lignes 132 à 147//\\
 +Communique avec l'utilisateur pour récupérer certaines informations (notamment l'image à traiter).\\
 +__Remarque:__ uniquement si le programme a été lancé avec l'argument ''-o''.\\ 
 +\\
 +
 +**optionTime**\\
 +<code python>
 +def optionTime(time):
 + # See Execution time of vintage function
 + print("Voulez-vous connaître le temps d'execution de la fonction vintage? [y/n]")
 + know = input("-> ")
 + if(know == 'y'):
 + print("Temps d'execution du programme:",time,"secondes")
 +</code>
 +//lignes 151 à 156//\\
 +Demande à afficher le temps //time// d'exécution du programme.\\
 +__Remarque:__ uniquement si le programme a été lancé avec l'argument ''-o''.\\ 
 +\\
 +
 +====Le main====
 +Le main ne s'occupe que des options (si argument ''-o'') et de la fonction principale.
 +
 +----
 +=====Problèmes et améliorations=====
 +====Problèmes====
 +Le programme est particulièrement lent (~4s).
 +
 +====Solutions possibles et améliorations====
 +Doter le programme d'une meilleure algorithmie pour notamment virer des opérations en trop/peu utiles. Le réécrire en C++ serait aussi un bon moyen pour booster ses performances.\\
 +\\
 +Pour les améliorations possibles, on pourrait envisager du temps réel et une meilleure gestion d'arguments.\\
 +\\
 +\\
 +\\
 +----
 +//Merci pour votre attention.//\\ 
 +//[[thomas.philibert@univ-tlse3.fr|Philibert Thomas]]//
 +
diy/projets/vintage.1527775642.txt.gz · Dernière modification : 2018/05/31 14:07 de tphilibert