Skip to content

Instantly share code, notes, and snippets.

@mguijarr
Last active September 21, 2018 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mguijarr/acc04b4bb58a04f6b0ddaf1c4d02475f to your computer and use it in GitHub Desktop.
Save mguijarr/acc04b4bb58a04f6b0ddaf1c4d02475f to your computer and use it in GitHub Desktop.
multiprocessing_greyscale
# installation de PIL avec Conda:
# conda install pillow
#
# récupération de la photo de Lena:
# https://i.stack.imgur.com/3T6Gc.jpg
#
# récupération de photos plus grandes
# https://visibleearth.nasa.gov/view.php?id=73751
#
# affichage/sauvegarde de l'histogramme
# conda install matplotlib
from PIL import Image
from multiprocessing import Pool
import sys
import os
import contextlib
import time
import collections
import operator
import functools
import matplotlib.pyplot as plt
@contextlib.contextmanager
def timeit():
t0 = time.time()
yield
print(f"Execution took {1000*(time.time()-t0)} ms.")
def calc_hist(l_data):
print(os.getpid())
cnt = collections.Counter(l_data)
return cnt
def to_greyscale(rgb_data):
print(os.getpid())
result = []
for r,g,b in (rgb_data[i:i+3] for i in range(0,len(rgb_data),3)):
result.append((r+g+b)//3)
return bytes(result)
def convert(image_filename, nprocess=4, multiprocessing=True):
# on va découper l'image selon le nombre de process demandé,
# qui doit être un multiple de 2
assert nprocess % 2 == 0
im = Image.open(image_filename)
# vérifications sur l'image, on veut 3 bandes (R,G,B) de 8 bits et une taille multiple de 2
assert im.layers==3
assert im.bits==8
assert im.width % 2 == 0
assert im.height % 2 == 0
rgb_data = im.tobytes() #on obtient une suite R,G,B,R,G,B,...,R,G,B,R,G,B
sub_data_size = 3*((im.width * im.height) // nprocess)
# generator expression qui renvoie les morceaux d'image R,G,B...R,G,B de longueur sub_data_size
sub_data = (rgb_data[i:i+sub_data_size] for i in range(0,len(rgb_data),sub_data_size))
if multiprocessing:
with Pool(nprocess) as pool:
# conversion en niveaux de gris
result = pool.map(to_greyscale, sub_data)
# calcul de l'histogramme sur les données de l'image en niveaux de gris
hist_result = functools.reduce(operator.add, pool.map(calc_hist, result))
else:
result = list(map(to_greyscale, sub_data))
hist_result = functools.reduce(operator.add, map(calc_hist, result))
# on reconstruit les données de l'image en niveaux de gris
out_bytes = b"".join(result)
# sauvegarde de l'image en niveaux de gris, on ajoute juste
# un suffixe _greyscale pour le nom du fichier
im_out = Image.frombytes('L', (im.width, im.height), out_bytes)
filename, file_ext = os.path.splitext(image_filename)
img_out_filename = filename+"_greyscale"+file_ext
im_out.save(img_out_filename)
# création du plot de l'histogramme
# et sauvegarde au format .png
plt.plot([hist_result[h] for h in sorted(hist_result)])
hist_out_filename = filename+"_hist.png"
plt.savefig(hist_out_filename)
if __name__ == '__main__':
try:
multiprocessing = int(sys.argv[2])
except IndexError:
multiprocessing = True
with timeit():
convert(sys.argv[1], nprocess=8, multiprocessing=multiprocessing)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment