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:06] – [Le programme] tphilibertdiy:projets:vintage [2018/06/01 10:58] (Version actuelle) – [Solutions possibles et améliorations] tphilibert
Ligne 12: Ligne 12:
 \\ \\
  
 +====Outils requis====
 +Aucun outil spécifique n'est requis pour faire fonctionner ce programme.
 ====Librairies==== ====Librairies====
 +Ce programme utilise les librairies suivantes:
 +<code python>
 +import cv2
 +import numpy as np
 +import copy
 +import random as rng
 +import sys
 +</code>
 +//lignes 1 à 5//.\\
 +\\
 +  * ''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.1527775601.txt.gz · Dernière modification : 2018/05/31 14:06 de tphilibert