Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from PIL import Image, ImageFile
- from sys import argv
- from math import sqrt, floor # Pythagore
- import numpy as np # moyenne RGB rapide (optionel)
- from os import listdir, remove
- from os.path import isfile, join
- # Pour un problème de compatibilité avec les jpeg...
- # voir http://bit.ly/2IkyJ6U
- ImageFile.LOAD_TRUNCATED_IMAGES = True
- '''
- Determine la distance euclidienne entre deux couleur (pythagore en 3D)
- '''
- def distance(color1, color2):
- r1, g1, b1 = color1
- r2, g2, b2 = color2
- # Étonnament la manière la plus rapide
- return sqrt((r2-r1)**2 + (g2-g1)**2 + (b2-b1)**2)
- '''
- Cherche l'image qui correspond le mieux au block de pixel donné
- retourne l'image la plus adapté à ce block
- '''
- def getClosestImage(imgCrop, imgdb):
- imgBlockAvgRGB = avgRGB(imgCrop) # Valeur moyenne RGB de l'image source
- # Cherche l'élément présentant la valeur RGB moyenne la plus proche
- nearestRGB = min(imgdb.keys(), key=lambda imAvgRGB: distance(imAvgRGB, imgBlockAvgRGB))
- nearestImg = imgdb[nearestRGB]
- return nearestImg
- '''
- Obtient la valeur RGB (red, green, blue) moyenne d'une image
- '''
- def avgRGB(img):
- return tuple(np.array(img).mean(axis=(0,1)))
- '''
- Normalise la taille de chaque image de la base de donnée
- imgdb: base d'images à normaliser
- size: tuple representant la taille voulue, ex: (tailleX, tailleY)
- '''
- def normaliseSize(imgdb, size):
- for i in range(len(imgdb)):
- imgdb[i] = imgdb[i].resize(size)
- return imgdb
- '''
- Charge les images dans la base de donnée
- '''
- def loadMosaDatabase(imgDbPath):
- # Contient toute les images utiles pour la mosaic
- imgdb = []
- for imagePath in listdir(imgDbPath):
- # Obtient le chemin complet vers le fichier
- imageFullPath = join(imgDbPath, imagePath)
- # Passe à la boucle suivante si l'élément n'est pas un fichier
- if not isfile(imageFullPath):
- continue
- # Ajoute l'objet image à la liste des images utiles
- imgdb.append(Image.open(imageFullPath))
- return imgdb
- # Vérifie que tout les paramètres sont fournis
- if len(argv) < 5:
- exit("Usage: python3 script.py cheminVersImage cheminVersBasededonnee resolution facteurDeSortie")
- imgOrigPath = argv[1] # chemin vers l'image à "mosaiquer"
- imgDbPath = argv[2] # chemin vers le dossier contenant les images pour la mosaique
- resolution = int(argv[3]) # nombre de divisions de l'image originale
- outputFactor = abs(int(argv[4])) # facteur par lequel multiplier la taille de l'image d'entrée
- img = Image.open(imgOrigPath) # Charge l'image originale
- if outputFactor != 1: # Si la taille de l'image d'entrée doit être ajusté
- img = img.resize((img.size[0]*outputFactor, img.size[1]*outputFactor))
- print("L'image de mosaique sera {} fois plus grande que l'image d'entrée".format(outputFactor))
- origSize = img.size # Garde en mémoire la taille de l'image originale pour plus tard
- print("Chargement des images dans la base de donnée... ")
- imgdb = loadMosaDatabase(imgDbPath) # Charge la base de donnée d'images
- blockSize = ( floor(img.size[0]/resolution), floor(img.size[1]/resolution) )
- apprxSize = ( blockSize[0]*resolution, blockSize[1]*resolution )
- print("La taille de image originale vas être changer en:\t {}".format(apprxSize))
- print("La mosaique se constitura d'images de taille:\t {}".format(blockSize))
- print("Changement de la taille de l'image originale en {}...".format(apprxSize))
- img = img.resize(apprxSize) # Change la taille de l'image originale pour tomber juste
- print("Changement de chaque image de la base de donnée {} ...".format(blockSize))
- imgdb = normaliseSize(imgdb, blockSize) # Change la taille des images pour convenir à la résolution
- print("Construction du dictionnaire Image <--> valeur RGB moyenne...")
- imgDbAvgRGB = dict() # Dictionnaire liant chaque image à ses valeur RGB moyennes
- for im in imgdb:
- imgDbAvgRGB[avgRGB(im)] = im
- imgMosa = Image.new("RGB", apprxSize, (255,0,0)) # Contiendra la mosaique
- print("Création de la mosaique...")
- for x in range(0, apprxSize[0], blockSize[0]): # Vas de 0 à apprxSize[0] en faisant x = x + blockSize[0] à chaque tour (step)
- for y in range(0, apprxSize[1], blockSize[1]):
- blockFrame = (x,y, x+blockSize[0], y+blockSize[1])
- # Découpe la portion de l'image originale à faire correspondre
- imgCrop = img.crop(blockFrame)
- # Obtient l'image à placer dans le block actuel, depuis la base de donnée
- imgBlock = getClosestImage(imgCrop, imgDbAvgRGB)
- # colle l'image à placer dans sa position dans la nouvelle mosaique
- imgMosa.paste(imgBlock, blockFrame)
- print("Terminé !")
- print("Changement de la taille de la mosaique pour être égale à celle de l'image originale {}".format(origSize))
- imgMosa = imgMosa.resize(origSize)
- print("Fichier enregistré sous \"mosa.png\"")
- imgMosa.save("mosa.png")
Advertisement
Add Comment
Please, Sign In to add comment