Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

vitesse manipulation liste (generateur ?)

14 réponses
Avatar
Lulu
Bonjour,

J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)

Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).


Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PIL import Image

Fichier_Image = "Anna_et_Lulu.jpg"

ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()

(l, h) = ze_image.size

# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))

# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))

# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))

liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]

for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))

ze_image_rouge_fast.putdata(liste_pixels_rouges)

ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<

Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.

Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.

Merci de vos avis

10 réponses

1 2
Avatar
Nicolas
Le 27/03/2020 à 00:50, Lulu a écrit :
Bonjour,
J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
Fichier_Image = "Anna_et_Lulu.jpg"
ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()
(l, h) = ze_image.size
# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))
# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))
# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
ze_image_rouge_fast.putdata(liste_pixels_rouges)
ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<
Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.
Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.

Pour créer les listes :
(l, h) = ze_image.size
l1 = [[0,0,0]] * (l*h)
l2 = [[0,0,0]] * (l*h)
l3 = [[0,0,0]] * (l*h)
Reste à remplir avec les données.
GetPixel() est très lent. A n'utiliser que ponctuellement.
Il est préférable de passer par tostring().
Un truc du genre : pix_data = ze_image.convert("RGB").tostring("raw", "RGB")
Si les images sont déjà en RVB, pas forcément besoin d'appeler convert().
pix_data est une liste d'octets R,V,B,R,V,B,R...
Attention, avec les images dont les couleurs sont codées sur plus que
8bits.
Nicolas
Merci de vos avis
Avatar
Lulu
Le 27-03-2020, Nicolas a écrit :
Le 27/03/2020 à 00:50, Lulu a écrit :
J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).


J'avais aussi essayé la "compréhension de liste" (par exemple ici :
https://openclassrooms.com/fr/courses/1206331-utilisation-avancee-des-listes-en-python
), mais je n'ai rien compris...
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
Fichier_Image = "Anna_et_Lulu.jpg"
ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()
(l, h) = ze_image.size
# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))
# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))
# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
ze_image_rouge_fast.putdata(liste_pixels_rouges)
ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<
Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.
Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.

Pour créer les listes :
(l, h) = ze_image.size
l1 = [[0,0,0]] * (l*h)
l2 = [[0,0,0]] * (l*h)
l3 = [[0,0,0]] * (l*h)

Merci, je ne savais pas qu'on pouvait faire cette opération sur une
liste.
Reste à remplir avec les données.

Mais je ne vois pas comment faire...
GetPixel() est très lent. A n'utiliser que ponctuellement.

Oui, j'ai vu.
Il est préférable de passer par tostring().
Un truc du genre : pix_data = ze_image.convert("RGB").tostring("raw", "RGB")
Si les images sont déjà en RVB, pas forcément besoin d'appeler convert().
pix_data est une liste d'octets R,V,B,R,V,B,R...

Je ne vois pas du tout comment remplir les listes l1, l2 et l3 avec ton
exemple de « ze_image.convert("RGB").tostring("raw", "RGB") ».
J'ai cherché ce que pouvait faire cette fonction, mais les exemples que
j'ai trouvés me semblent sans aucun rapport avec mon problème.
Attention, avec les images dont les couleurs sont codées sur plus que
8bits.

Oui, je n'avais pas pensé à ce problème.
Merci pour ton aide.
Avatar
Pierre Maurette
Lulu :
Bonjour,
J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
Fichier_Image = "Anna_et_Lulu.jpg"
ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()
(l, h) = ze_image.size
# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))
# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))
# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
ze_image_rouge_fast.putdata(liste_pixels_rouges)
ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<
Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.
Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.
Merci de vos avis

Fondamentalement une réponse est dans zip(*zipped).
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs =
[(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu) = list(zip(*RVBs))
im_rouge = [(x, 0, 0) for x in _rouge]
im_vert = [(0, x, 0) for x in _vert]
im_bleu = [(0, 0, x) for x in _bleu]
print(im_rouge)
print(im_vert)
print(im_bleu)
Remarques:
Avez-vous vraiment besoin d'une image "RVB" pour chaque channel ?
Normalement un channel se représente dans une image "L".
Peut-être y a-t-il moyen de tout faire à partir de PIL (Image.split(),
Image.getchannel(channel), et des fonctions de convertion ).
--
Pierre Maurette
Avatar
Pierre Maurette
Pierre Maurette :
[...]
Fondamentalement une réponse est dans zip(*zipped).
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs = [(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu) = list(zip(*RVBs))
im_rouge = [(x, 0, 0) for x in _rouge]
im_vert = [(0, x, 0) for x in _vert]
im_bleu = [(0, 0, x) for x in _bleu]
print(im_rouge)
print(im_vert)
print(im_bleu)
Remarques:
Avez-vous vraiment besoin d'une image "RVB" pour chaque channel ? Normalement
un channel se représente dans une image "L".
Peut-être y a-t-il moyen de tout faire à partir de PIL (Image.split(),
Image.getchannel(channel), et des fonctions de convertion ).

Pour info, en utilisant zip et une liste de "0" (zob):
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs =
[(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu, zob) = list(zip(*RVBs)) + [([0,] * len(RVBs)),]
(im_rouge, im_vert, im_bleu) = (list(zip(_rouge, zob, zob)),
list(zip(zob, _vert, zob)), list(zip(zob, zob, _bleu)))
print(im_rouge)
print(im_vert)
print(im_bleu)
--
Pierre Maurette
Avatar
Lulu
Le 27-03-2020, Pierre Maurette a écrit :
Lulu :
Bonjour,
J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
Fichier_Image = "Anna_et_Lulu.jpg"
ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()
(l, h) = ze_image.size
# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))
# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))
# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
ze_image_rouge_fast.putdata(liste_pixels_rouges)
ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<
Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.
Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.
Merci de vos avis

Fondamentalement une réponse est dans zip(*zipped).

J'arrivais justement sur le ng pour demander la fonction réciproque de
zip, car après une petite heure à lire de la doc sur zip, j'avais (mal
compris donc) que zip servait à "merger" des listes comme dans cet
exemple :
zipped = list(zip([1,2,3],[4,5,6])
zipped
[(1,4),(2,5),(3,6)]


#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs =
[(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu) = list(zip(*RVBs))

Je note la subtilité de l'étoile devant la liste.
Si RVBs est une liste, quel est cet objet désigné par *RVB ?
En tout cas, pour reprendre mon exemple :
(x,y) = list(zip(*zipped))
x



(1, 2, 3)



(4, 5, 6)
Donc ça marche, ça fait ce dont j'ai besoin.
im_rouge = [(x, 0, 0) for x in _rouge]
im_vert = [(0, x, 0) for x in _vert]
im_bleu = [(0, 0, x) for x in _bleu]
print(im_rouge)
print(im_vert)
print(im_bleu)

Je note !
Remarques:
Avez-vous vraiment besoin d'une image "RVB" pour chaque channel ?

A mon niveau, je voulais poursuivre mon apprentissage sur les listes et
comment les manipuler.
Je n'ai effectivement pas besoin d'une image RVB pour chaque channel,
mais mes élèves, oui !
C'est à but pédagogique, ils ont besoin que la composante rouge d'une
image soit... rouge.
Même si c'est pour leur faire remarquer ensuite que puisque cette
composante étant codée sur 8 bits avec finalement un seul canal puisque
tous les pixels verts et bleus sont à zéro, alors on a bien des niveaux
de gris (ils savent déjà qu'un capteur CCD n'est sensible qu'à la
luminance et qu'il ne fabrique des pixels RVB que grâce au filtre de
Bayer)
Normalement un channel se représente dans une image "L".

On est bien d'accord et c'est ce que mes élèves (seconde) finiront par
comprendre.
Peut-être y a-t-il moyen de tout faire à partir de PIL (Image.split(),
Image.getchannel(channel), et des fonctions de convertion ).

OK, je vais voir ça.
Merci pour vos réponses, toujours de qualité.
C'est rigolo, je relisais justement avant hier nos échanges d'août
dernier dans lesquels vous m'expliquiez bibliothèques, modules, classes
et fonctions... (le sujet était "manipulation d'image")
Merci encore.
Avatar
Lulu
Le 27-03-2020, Pierre Maurette a écrit :
Pierre Maurette :
[...]
Fondamentalement une réponse est dans zip(*zipped).
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs = [(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu) = list(zip(*RVBs))
im_rouge = [(x, 0, 0) for x in _rouge]
im_vert = [(0, x, 0) for x in _vert]
im_bleu = [(0, 0, x) for x in _bleu]
print(im_rouge)
print(im_vert)
print(im_bleu)

Pour info, en utilisant zip et une liste de "0" (zob):
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
RVBs =
[(1,2,3),(11,12,13),(21,22,23),(31,32,33),(411,412,413),(521,522,523)]
print(RVBs)
(_rouge, _vert, _bleu, zob) = list(zip(*RVBs)) + [([0,] * len(RVBs)),]
(im_rouge, im_vert, im_bleu) = (list(zip(_rouge, zob, zob)),
list(zip(zob, _vert, zob)), list(zip(zob, zob, _bleu)))
print(im_rouge)
print(im_vert)
print(im_bleu)

Je vais tester aussi (en utilisant un nom plus "académique" pour zob ;-))
Avatar
Nicolas
...
Je n'ai effectivement pas besoin d'une image RVB pour chaque channel,
mais mes élèves, oui !
C'est à but pédagogique, ils ont besoin que la composante rouge d'une
image soit... rouge.

Pour des élèves de seconde, je n'irai pas dans la voie "zip()".
Mon fils a pris la spécialisation NSI (il est en seconde).
Le programme est très chargé, voire même absurde. Apprendre à coder des
nombres à virgule fixe et des nombres à virgule flottante alors qu'ils
n'ont même pas intégré la logique de base... Mais je m'égare.
Donc, le programme est très chargé et les élèves ont (beaucoup) de mal a
digérer tout ce qu'ils doivent ingurgiter. Leur faire manipuler des
listes, c'est fondamental en Python. Mais, à mon avis, il faut rester le
plus simple possible.
Qu'elle est la différence entre
l = [1, 3, 5, 9]
for e in l :
print(e)
et
l = [1, 3, 5, 9]
for i in range(len(l)) :
print(l[i])
Dans quel cas faut-il utiliser la 1ere forme ? La deuxième forme ?
Ce sont des exemples simples mais ils en sont encore, pour beaucoup, à
mélanger les deux formes d'écriture.
"zip()" est très utile mais le risque de les embrouiller est là.
Il vaut mieux leur apprendre à parfaitement maitriser les bases.
Mais ce n'est que mon avis ;)
Nicolas
Avatar
Nicolas
Le 27/03/2020 à 15:29, Lulu a écrit :
Le 27-03-2020, Nicolas a écrit :
Le 27/03/2020 à 00:50, Lulu a écrit :

J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).


J'avais aussi essayé la "compréhension de liste" (par exemple ici :
https://openclassrooms.com/fr/courses/1206331-utilisation-avancee-des-listes-en-python
), mais je n'ai rien compris...

La compréhension de liste, c'est pas compliqué.
----------------------
Soit le code suivant :
l_in = [1, 45, 89, 56, 4]
l_out = []
for e in l_in :
l_out.append(e)
C'est exactement la même chose que :
l_out = [e for e in l_in]
--------------------------
On peut compléter un peu :
l_out = []
for e in l_in :
l_out.append(traitement(e))
est équivalent à :
l_out = [traitement(e) for e in l_in]
------------------
Version complète :
l_out = []
for e in l_in :
if is_ok(e) :
l_out.append(traitement(e))
est équivalent à :
l_out = [traitement(e) for e in l_in if is_ok(e)]
Les 4 lignes sont "mises à plat" en une seule ligne.
Ca serait plus facile à expliquer avec des couleurs ou un dessin mais,
sur la mailing list, c'est pas possible.
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PIL import Image
Fichier_Image = "Anna_et_Lulu.jpg"
ze_image = Image.open( Fichier_Image ).convert("RGB")
ze_image.show()
(l, h) = ze_image.size
# création de l'image rouge
ze_image_rouge = Image.new("RGB",(l,h))
# traitement pixel par pixel :
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge.putpixel((x,y), ( rouge, 0, 0))
# création en mémoire de l'image rouge
ze_image_rouge_fast = Image.new("RGB",(l,h))
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges=[]
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
ze_image_rouge_fast.putdata(liste_pixels_rouges)
ze_image_rouge.show()
ze_image_rouge_fast.show()
8<-----------8<---------8<----------8<----------8<----------8<----------8<
Sur une image de 1.600.000 pixels, la première double boucle avec deux
for imbriqués bricole pendant 7 secondes (pas très étonnant), mais la
deuxième boucle qui remplit trois listes n'est que 4 fois plus rapide.
Je crois que c'est en jouant sur ma manière de créer ces trois listes et
de les remplir que je peux gagner le plus.

Pour créer les listes :
(l, h) = ze_image.size
l1 = [[0,0,0]] * (l*h)
l2 = [[0,0,0]] * (l*h)
l3 = [[0,0,0]] * (l*h)

Merci, je ne savais pas qu'on pouvait faire cette opération sur une
liste.
Reste à remplir avec les données.

Mais je ne vois pas comment faire...
GetPixel() est très lent. A n'utiliser que ponctuellement.

Oui, j'ai vu.
Il est préférable de passer par tostring().
Un truc du genre : pix_data = ze_image.convert("RGB").tostring("raw", "RGB")
Si les images sont déjà en RVB, pas forcément besoin d'appeler convert().
pix_data est une liste d'octets R,V,B,R,V,B,R...

Je ne vois pas du tout comment remplir les listes l1, l2 et l3 avec ton
exemple de « ze_image.convert("RGB").tostring("raw", "RGB") ».
J'ai cherché ce que pouvait faire cette fonction, mais les exemples que
j'ai trouvés me semblent sans aucun rapport avec mon problème.

Je peux écrire un exemple si ça t'intéresse mais il faut que je trouve
un peu de temps pour ça ;)
Attention, avec les images dont les couleurs sont codées sur plus que
8bits.

Oui, je n'avais pas pensé à ce problème.
Merci pour ton aide.

De rien.
Avatar
Lulu
Le 28-03-2020, Nicolas a écrit :
Le 27/03/2020 à 15:29, Lulu a écrit :
Le 27-03-2020, Nicolas a écrit :
Le 27/03/2020 à 00:50, Lulu a écrit :

J'ai besoin de manipuler des listes rapidement pour manipuler une image.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)
Et je veux faire ça le plus rapidement possible.
J'imagine que ça pourrait passer par un générateur, mais je ne sais pas
comment en "fabriquer" et les exemples que je trouve sur le web ne
m'aident pas vraiment. (plus essais infructueux).


J'avais aussi essayé la "compréhension de liste" (par exemple ici :
https://openclassrooms.com/fr/courses/1206331-utilisation-avancee-des-listes-en-python
), mais je n'ai rien compris...

La compréhension de liste, c'est pas compliqué.
----------------------
Soit le code suivant :
l_in = [1, 45, 89, 56, 4]
l_out = []
for e in l_in :
l_out.append(e)
C'est exactement la même chose que :
l_out = [e for e in l_in]
--------------------------
On peut compléter un peu :
l_out = []
for e in l_in :
l_out.append(traitement(e))
est équivalent à :
l_out = [traitement(e) for e in l_in]
------------------
Version complète :
l_out = []
for e in l_in :
if is_ok(e) :
l_out.append(traitement(e))
est équivalent à :
l_out = [traitement(e) for e in l_in if is_ok(e)]

où j'imagine que traitement() et ok() sont deux fonctions ?
Les 4 lignes sont "mises à plat" en une seule ligne.
Ca serait plus facile à expliquer avec des couleurs ou un dessin mais,
sur la mailing list, c'est pas possible.

Donc pour mon exemple de liste de tuples.
D'une liste ((r,v,b),(a,b,c),(x,y,z),.....), je veux passer à trois
listes :
((r,0,0),(a,0,0),(x,0,0),....)
((0,v,0),(0,b,0),(0,y,0),....)
((0,0,b),(0,0,c),(0,0,z),....)




j'obtiens mes 3 listes avec l1 = [ (e[0], 0, 0) for e in l_in ]
l2 = [ (0, e[1], 0) for e in l_in ] et l3 = [ (0, 0, e[2]) for e in l_in ]
(Bizarrement, c'est aussi l'exemple de zip(list) et zip(*list)) donné
par Pierre qui m'a aussi permis de comprendre ;-)
Donc mille mercis encore à vous deux.
Je viens de tester dans mon script et la manipulation de liste par
compréhension est la plus rapide des 4 manipulations que je tente :
-=-=-=-
Image : ws_SBK-07_0834.jpg
taille de l'image : 1024 px × 768 px
nombre de pixels : 786432
-=-=-=-
1: Traitement par une boucle sur les 786432 pixels.
durée = 9.874 seconde(s)
-=-=-=-
2: Traitement par boucle avec list.append().
durée = 2.402 seconde(s)
4 fois plus rapide.
-=-=-=-
3: Traitement par compréhension de liste.
durée = 1.495 seconde(s)
6 fois plus rapide.
-=-=-=-
4: Traitement par split avec zip(*liste) et merge par zip(liste).
durée = 2.786 seconde(s)
3 fois plus rapide.
-=-=-=-
5: Traitement par split de liste et fausse compréhension
durée = 2.688 seconde(s)
3 fois plus rapide.
-=-=-=-
6: Traitement par Image.split().
durée = 0.002264 seconde(s)
4361 fois plus rapide.
Mon code :
8<-----------8<---------8<----------8<----------8<----------8<----------8<
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from datetime import datetime
from PIL import Image, ImageFilter
# Fichier_Image = "Les_Horribles_Cernettes.png"
# Fichier_Image = "avengers-endseries-comics.png"
# Fichier_Image = "Anna_et_Lulu.jpg"
Fichier_Image = "ws_SBK-07_0834.jpg"
# Fichier_Image = "Sauzon.jpg"
print("-=-=-=-nImage : ", Fichier_Image)
try:
ze_image = Image.open( Fichier_Image ).convert("RGB")
except:
print('n' * 2)
print(" Erreur : le fichier n",Fichier_Image,"" existe-t-il ?")
print('n' * 2)
sys.exit(1)
# j'appelle la méthode 'show' de la classe PIL.Image.Image (liste des méthodes help(Image))
ze_image.show()
(l, h) = ze_image.size
print("taille de l'image :", l, "px ×", h, "px")
nb_pixels = l*h
print("nombre de pixels :",nb_pixels)
# 1er procédé
# création en mémoire des 3 images à calculer
ze_image_rouge_p1 = Image.new("RGB",(l,h))
ze_image_verte_p1 = Image.new("RGB",(l,h))
ze_image_bleue_p1 = Image.new("RGB",(l,h))
# mesure du temps de traitement :
timestamp_debut = datetime.timestamp(datetime.now())
# traitement pixel par pixel :
print("-=-=-=-n1: Traitement par une boucle sur les", nb_pixels,"pixels.")
for y in range(h): # pour y variant de 0 à h-1
for x in range(l): # pour x variant de 0 à l-1
(rouge, vert, bleu) = ze_image.getpixel((x,y))
ze_image_rouge_p1.putpixel((x,y), ( rouge, 0, 0))
ze_image_verte_p1.putpixel((x,y), ( 0, vert, 0))
ze_image_bleue_p1.putpixel((x,y), ( 0, 0, bleu))
# mesure du temps de traitement :
timestamp_fin = datetime.timestamp(datetime.now())
duree_1 = timestamp_fin - timestamp_debut
print('durée =',"{:0.3f}".format(duree_1),"seconde(s)")
# 2ème procédé
# création en mémoire des 3 images à calculer
ze_image_rouge_p2 = Image.new("RGB",(l,h))
ze_image_verte_p2 = Image.new("RGB",(l,h))
ze_image_bleue_p2 = Image.new("RGB",(l,h))
liste_pixels = []
liste_pixels_rouges = []
liste_pixels_verts =[]
liste_pixels_bleus = []
print("-=-=-=-n2: Traitement par boucle avec list.append().")
timestamp_debut = datetime.timestamp(datetime.now())
liste_pixels = list(ze_image.getdata())
for i in range(len(liste_pixels)):
liste_pixels_rouges.append((liste_pixels[i][0], 0, 0))
liste_pixels_verts.append((0, liste_pixels[i][1], 0))
liste_pixels_bleus.append((0, 0, liste_pixels[i][2]))
ze_image_rouge_p2.putdata(liste_pixels_rouges)
ze_image_verte_p2.putdata(liste_pixels_verts)
ze_image_bleue_p2.putdata(liste_pixels_bleus)
timestamp_fin = datetime.timestamp(datetime.now())
duree_2 = timestamp_fin - timestamp_debut
print('durée =',"{:0.3f}".format(duree_2),"seconde(s)")
print(int(duree_1/duree_2), "fois plus rapide.")
# 3ème procédé
# création en mémoire des 3 images à calculer
ze_image_rouge_p3 = Image.new("RGB",(l,h))
ze_image_verte_p3 = Image.new("RGB",(l,h))
ze_image_bleue_p3 = Image.new("RGB",(l,h))
liste_pixels = []
# liste_pixels_rouges = []
liste_pixels_verts =[]
liste_pixels_bleus = []
print("-=-=-=-n3: Traitement par compréhension de liste.")
timestamp_debut = datetime.timestamp(datetime.now())
liste_pixels = list(ze_image.getdata())
#print("liste_pixels[:30] = ", liste_pixels[:30])
liste_pixels_rouges = [ (e[0], 0, 0) for e in liste_pixels ]
liste_pixels_verts = [ (0, e[1], 0) for e in liste_pixels ]
liste_pixels_bleus = [ (0, 0, e[2]) for e in liste_pixels ]
ze_image_rouge_p3.putdata(liste_pixels_rouges)
ze_image_verte_p3.putdata(liste_pixels_verts)
ze_image_bleue_p3.putdata(liste_pixels_bleus)
timestamp_fin = datetime.timestamp(datetime.now())
duree_3 = timestamp_fin - timestamp_debut
print('durée =',"{:0.3f}".format(duree_3),"seconde(s)")
print(int(duree_1/duree_3), "fois plus rapide.")
# 4ème procédé
# création en mémoire des 3 images à calculer
ze_image_rouge_p4 = Image.new("RGB",(l,h))
ze_image_verte_p4 = Image.new("RGB",(l,h))
ze_image_bleue_p4 = Image.new("RGB",(l,h))
liste_pixels = []
liste_pixels_rouges = []
liste_pixels_verts =[]
liste_pixels_bleus = []
liste_pixels_zero = []
print("-=-=-=-n4: Traitement par split avec zip(*liste) et merge par zip(liste).")
timestamp_debut = datetime.timestamp(datetime.now())
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges, liste_pixels_verts, liste_pixels_bleus = list(zip(*liste_pixels))
liste_pixels_zero = [0] * nb_pixels
ze_image_rouge_p4.putdata(list(zip(liste_pixels_rouges, liste_pixels_zero, liste_pixels_zero)))
ze_image_verte_p4.putdata(list(zip(liste_pixels_zero, liste_pixels_verts, liste_pixels_zero)))
ze_image_bleue_p4.putdata(list(zip(liste_pixels_zero, liste_pixels_zero, liste_pixels_bleus)))
timestamp_fin = datetime.timestamp(datetime.now())
duree_4 = timestamp_fin - timestamp_debut
print('durée =',"{:0.3f}".format(duree_4),"seconde(s)")
print(int(duree_1/duree_4), "fois plus rapide.")
# 5ème procédé
liste_pixels = []
liste_pixels_rouges = []
liste_pixels_verts =[]
liste_pixels_bleus = []
liste_pixels_zero = []
ze_image_rouge_p5 = Image.new("RGB",(l,h))
ze_image_verte_p5 = Image.new("RGB",(l,h))
ze_image_bleue_p5 = Image.new("RGB",(l,h))
print("-=-=-=-n5: Traitement par split de liste et fausse compréhension")
timestamp_debut = datetime.timestamp(datetime.now())
liste_pixels = list(ze_image.getdata())
liste_pixels_rouges, liste_pixels_verts, liste_pixels_bleus = list(zip(*liste_pixels))
liste_pixels_rouges = [(x, 0, 0) for x in liste_pixels_rouges ]
liste_pixels_verts = [(0, x, 0) for x in liste_pixels_verts ]
liste_pixels_bleus = [(0, 0, x) for x in liste_pixels_bleus ]
ze_image_rouge_p5.putdata(liste_pixels_rouges)
ze_image_verte_p5.putdata(liste_pixels_verts)
ze_image_bleue_p5.putdata(liste_pixels_bleus)
timestamp_fin = datetime.timestamp(datetime.now())
duree_5 = timestamp_fin - timestamp_debut
print('durée =',"{:0.3f}".format(duree_5),"seconde(s)")
print(int(duree_1/duree_5), "fois plus rapide.")
# 6ème procédé
print("-=-=-=-n6: Traitement par Image.split().")
timestamp_debut = datetime.timestamp(datetime.now())
ze_image_splited = Image.Image.split(ze_image)
timestamp_fin = datetime.timestamp(datetime.now())
duree_6 = timestamp_fin - timestamp_debut
print('durée =',"{:0.6f}".format(duree_6),"seconde(s)")
print(int(duree_1/duree_6), "fois plus rapide.")
x = input("Afficher les images [O/n] ? ")
if x == "" or x[0] == "o" or x[0] == "O" :
ze_image_rouge_p1.show()
ze_image_verte_p1.show()
ze_image_bleue_p1.show()
ze_image_rouge_p2.show()
ze_image_verte_p2.show()
ze_image_bleue_p2.show()
ze_image_rouge_p3.show()
ze_image_verte_p3.show()
ze_image_bleue_p3.show()
ze_image_rouge_p4.show()
ze_image_verte_p4.show()
ze_image_bleue_p4.show()
ze_image_rouge_p5.show()
ze_image_verte_p5.show()
ze_image_bleue_p5.show()
ze_image_splited[0].show()
ze_image_splited[1].show()
ze_image_splited[2].show()
Avatar
Lulu
Le 28-03-2020, Nicolas a écrit :
Je n'ai effectivement pas besoin d'une image RVB pour chaque channel,
mais mes élèves, oui !
C'est à but pédagogique, ils ont besoin que la composante rouge d'une
image soit... rouge.

Pour des élèves de seconde, je n'irai pas dans la voie "zip()".

Tu as évidemment raison, je ne parlais de but pédagogique que pour
éviter de les surprendre par une composante rouge qui s'affiche en
niveau de gris.
Mais comprendre zip(), c'était aussi un but pédagogique, mais pour moi
seul ;-)
Je ne donnerai mon code source qu'aux quelques geeks de mes 120 élèves
qui me poseraient des questions sur la manipulation des listes...
Mon fils a pris la spécialisation NSI (il est en seconde).

Euh... NSI (Numérique et Sciences Informatiques), c'est en première.
Je suis prof de seconde en Physique/Chimie et SNT (Sciences Numériques
et Technologie)
Le programme est très chargé, voire même absurde. Apprendre à coder des
nombres à virgule fixe et des nombres à virgule flottante alors qu'ils
n'ont même pas intégré la logique de base... Mais je m'égare.
Donc, le programme est très chargé et les élèves ont (beaucoup) de mal a
digérer tout ce qu'ils doivent ingurgiter. Leur faire manipuler des
listes, c'est fondamental en Python. Mais, à mon avis, il faut rester le
plus simple possible.

Oui.
Qu'elle est la différence entre
l = [1, 3, 5, 9]
for e in l :
print(e)
et
l = [1, 3, 5, 9]
for i in range(len(l)) :
print(l[i])
Dans quel cas faut-il utiliser la 1ere forme ? La deuxième forme ?

Ça, j'ai su mais j'ai oublié...
Peux-tu rafraichir ma mémoire ?
Ce sont des exemples simples mais ils en sont encore, pour beaucoup, à
mélanger les deux formes d'écriture.
"zip()" est très utile mais le risque de les embrouiller est là.
Il vaut mieux leur apprendre à parfaitement maitriser les bases.

Je suis bien d'accord.
Mais ce n'est que mon avis ;)

Tout à fait valable (mais ça n'est que mon avis ;-)
1 2