Optimisation traitement d'images

Optimisation traitement d'images - Python - Programmation

Marsh Posté le 27-09-2004 à 02:34:44    

Bonjour,
 
c'est mon premier post et aussi mon premier script python !
travaillant sur maya+renderman sur windows et os X, il me fallait un solution multi-plateforme pour créer des scripts de traitement d'image.
 
j'ai donc fait un script python qui prend plusieurs images (couleur, normals, depths, id objets), qui effectue des calculs avec pour faire ressortir les contours, puis assemble une image final avec l'outline (associé à un cell shading, on a un rendu cartoon donc).
 
ceci simule la fonction contour shader de mentalray pour les connaisseurs, mais peut importe le probleme n'est pas la.
 
le probleme c'est que le script est super super lent (genre 5 minutes pour une image en 1240x1024), et il me faut vraiment un truc plus rapide (genre quelques secondes).
 
la problématique se situe au niveau de la boucle qui traite l'image pixel par pixel..
 
je n'y connais rien en python a part ce qu'il y a dans le script, alors je sais pas trop quelle approche utiliser pour que ca boost vraiment, merci de me donner des conseils peut etre sur la manipulation des sequences, etc.. j'ai pas tout capter, ou mieux si vous avez ZE solution ;)
 
voici mon script :
 

Code :
  1. #parameters
  2. ndiff = 0.10 / 100.
  3. zdiff = 5. / 100.
  4. sampling = 3 #MUST be the same than renderman global's sampling size
  5. line_width = 4
  6. if (len(sys.argv) > 1) :
  7.     file = sys.argv[1]
  8. elif (len(sys.argv) > 2) :
  9.     file = sys.argv[2]
  10. else :
  11.     file = "C:/download/3D/Render_toonz/renderman/toon/rmanpix/untitled.0001.tga"
  12. #contour processing on tga files. kraken@machinemolle.com
  13. import Image
  14. import ImageFilter
  15. import ImageEnhance
  16. import ImageOps
  17. import ImageTk
  18. import ImageChops
  19. import commands
  20. import os
  21. import sys
  22. import math
  23. import array
  24. def seq_set_brush(pixels, x, y, width, height, size) :
  25.     #TODO : find correct side value (diff)
  26.     len = round(size / 2)
  27.     diff = (float((size + 1) % 2) / 2.)
  28.     for dx in range(- len, len) :
  29.         for dy in range (- len, len) :
  30.             fx = x + dx
  31.             fy = y + dy
  32.             if fx >= 0 and fy >= 0 and fx < width and fy < height :
  33.                 if abs(dx) < len or diff == 0 :
  34.                     seq_set_pixel(pixels, fx, fy, width, height, 255)
  35.                 else :
  36.                     seq_set_pixel(pixels, fx, fy, width, height, 255 * diff)
  37. def seq_set_pixel(pixels, x, y, width, height, value) :
  38.     if x >= 0 and y >= 0 and x < width and y < height :
  39.         pixels[x + y * width] = value
  40.         #pixels[x + y * width * 3 + 1] = value
  41.         #pixels[x + y * width * 3 + 2] = value
  42. def seq_get_pixel(pixels, x, y, width, height) :
  43.     if x >= 0 and y >= 0 and x < width and y < height :
  44.         return pixels[x + y * width]
  45. def dot(v1, v2) :
  46.     if (v1 and v2) :
  47.         return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]
  48.     else :
  49.         return 0
  50. def norm(vector) :
  51.     if (vector) :
  52.         return math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2])
  53. def normalize(vector) :
  54.     result = [0, 0, 0]
  55.     vnorm = norm(vector)
  56.     if vnorm != 0 and vector :
  57.         result[0] = vector[0] / vnorm
  58.         result[1] = vector[1] / vnorm
  59.         result[2] = vector[2] / vnorm
  60.     return result
  61. base = os.path.basename(file)
  62. fields = base.split("." )
  63. prefix = fields[0]
  64. num = fields[1]
  65. format = fields[2]
  66. suffix = num + "." + format
  67. im = Image.open(prefix + ".normals." + suffix)
  68. imdepths = Image.open(prefix + ".depths." + suffix)
  69. imids = Image.open(prefix + ".ids." + suffix)
  70. mask = im
  71. pixels = mask.getdata()
  72. depths = imdepths.getdata()
  73. depths = depths.convert("L" )
  74. ids = imids.getdata()
  75. ids = ids.convert("L" )
  76. contours = [0] * len(pixels) * 3
  77. #print len(contours)
  78. width = mask.size[0]
  79. height = mask.size[1]
  80. for x in range(0, width):
  81.     if (x % 10 == 0) :
  82.         print "ALF_PROGRESS " + str(50 + int((float(x*height)/float(width*height))*50)) + "%"
  83.     for y in range(0, height):
  84.         p1 = seq_get_pixel(pixels, x, y, width, height)
  85.         d1 = seq_get_pixel(depths, x, y, width, height)
  86.         id1 = seq_get_pixel(ids, x, y, width, height)
  87.         if d1 : d1 = d1 / 255.
  88.         p1 = normalize(p1)
  89.         a = 0
  90.         d = 0
  91.         for dx in range(-1, 1) :
  92.             for dy in range (-1, 1) :
  93.                 if dx + x >= 0 and dy + y >= 0 and dx + x < width and dy + y < height :
  94.                     p2 = seq_get_pixel(pixels, x + dx, y + dy, width, height)
  95.                     d2 = seq_get_pixel(depths, x + dx, y + dy, width, height)
  96.                     id2 = seq_get_pixel(ids, x + dx, y + dy, width, height)
  97.                     if (d2) :
  98.                         d2 = d2 / 255.
  99.                         d = abs(d2 - d1)
  100.                     p2 = normalize(p2)
  101.                     if (norm(p2) == 0 and norm(p1) == 0) :
  102.                         pa = 1
  103.                     else :
  104.                         pa = dot(p1, p2)
  105.                     if ((p1 and p2) and (pa < (1 - ndiff))) or d > zdiff or (id2 and id1 != id2) :
  106.                         a = 1 #a = 255
  107.         if a : seq_set_brush(contours, x, y, width, height, line_width)
  108. contours_array = array.array('B')
  109. contours_array.fromlist(contours)
  110. mask = Image.frombuffer("L", (width, height), contours_array)
  111. mask = mask.transpose(Image.FLIP_TOP_BOTTOM)
  112. mask.save(prefix + ".contour." + num + ".ppm", "PPM" )
  113. mask = mask.filter(ImageFilter.SMOOTH)
  114. mask = ImageOps.invert(mask)
  115. im1 = mask.convert("RGB" )
  116. im = Image.open(file)
  117. im = im.convert("RGB" )
  118. out = ImageChops.multiply(im, im1)
  119. out = out.resize((im1.size[0] / sampling, im1.size[1] / sampling), Image.ANTIALIAS)
  120. out.save(prefix + ".final." + num + ".tif", "TIFF" )
  121. os.system('cmd.exe /C "%MAYA_PLUG_IN_PATH%/it.exe" ' + prefix + ".final." + num + ".tif" )


Reply

Marsh Posté le 27-09-2004 à 02:34:44   

Reply

Marsh Posté le 27-09-2004 à 19:35:14    

PYTHON est pe pas assez performant pour ca tout court ?

Reply

Marsh Posté le 27-09-2004 à 19:42:41    

T'utilises la dernière version de Python ?
Sinon c'est vrai que les scripts c'est pas l'idéal pour du traitement d'images.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 27-09-2004 à 20:24:05    

Joel F a écrit :

PYTHON est pe pas assez performant pour ca tout court ?

toi t'es marrant : un bleu bite de matheux fait son premier programme. 150 lignes de python (on à qu'à dire qu'en C ça ferait sans doute 700 lignes), tout ça en un seul fichier. et bien offuscé en plus, même très bien. tout est bien illisible. on a gus qui fait des matrice dans un tableau ... tout ça est ridicule. python a des super bibliothèques de math (SciPy, Numarray, etc) de très très bonne facture, il suffit qu'un  amateur poste un message juste après avoir terminer son application pour la première fois, et hop tu perds tout rationnel ...

Reply

Marsh Posté le 27-09-2004 à 20:26:21    

HelloWorld a écrit :

T'utilises la dernière version de Python ?
Sinon c'est vrai que les scripts c'est pas l'idéal pour du traitement d'images.

mon ***, c'est du poulet : je fais de la transparence et de l'antialiasing en temps réel là dedans http://gdesklets.gnomedesktop.org/, je t'assure que ça marche aussi vite que le C, voir plus sur certains points grace à de meilleurs algorithmes.
 
 
et si ça vous suffit pas, un coup de JIT avec pysco, et on en parlera plus

Reply

Marsh Posté le 27-09-2004 à 20:27:20    

oui la derniere version !
 
bon je suis deg :(
pourtant je fais pas des calculs tres compliqué comme vous pouvez voire, le meme genre de calcul que pour une convolution (filtre par matrice 3x3).
 
Pour du 640x480, je dois calculer à 3x la résolution, ca fait environ 3Mo de données à traiter, pixel par pixel, sachant que pour chaque pixel j'accede aux pixels autour, ca fait dans les 30 millions d'acces mémoire pour une image (et encore en lecture seulement).
 
Dois-je donc me rabattre sur du compilé (c.. voire java), pour pouvoir traiter autant d'informations avec une performance correcte ??

Reply

Marsh Posté le 27-09-2004 à 20:52:16    

thekraken a écrit :

oui la derniere version !
 
bon je suis deg :(
pourtant je fais pas des calculs tres compliqué comme vous pouvez voire, le meme genre de calcul que pour une convolution (filtre par matrice 3x3).
 
Pour du 640x480, je dois calculer à 3x la résolution, ca fait environ 3Mo de données à traiter, pixel par pixel, sachant que pour chaque pixel j'accede aux pixels autour, ca fait dans les 30 millions d'acces mémoire pour une image (et encore en lecture seulement).
 
Dois-je donc me rabattre sur du compilé (c.. voire java), pour pouvoir traiter autant d'informations avec une performance correcte ??


 
On t'a dit d'utiliser SciPy et numarray ( et peut-être aussi PIL pendant que tu y es ) :o

Reply

Marsh Posté le 27-09-2004 à 21:08:00    

et on te dit surtout de profiler ton programme et de passer un  coup de psyco par dessus
 
la seule personne qui ne peut pas traiter autant d'informations avec une performance correcte, c'est toi.

Reply

Marsh Posté le 27-09-2004 à 21:12:26    

Taz : je fais pas de calcul de maths particuliers (que des opération de base..), le probleme c'est le grand nombre d'accès mémoire en python.
j'ai pas séparé mon script car il est tres court, et de toutes façon ca le fera pas aller plus vite, non ?
 
j'ai essayé de compiler le script optimisé (pyc, pyo..), et psyco aussi mais ça n'est pas plus rapide (meme un poil plus lent des fois).
 

Reply

Marsh Posté le 27-09-2004 à 21:15:33    

Au fait, psyco ne sert à rien si tout le code ne se trouve pas dans une fonction. Et jete un coup d'oeil du coté de ScyPy et numarray quand même

Reply

Marsh Posté le 27-09-2004 à 21:15:33   

Reply

Marsh Posté le 27-09-2004 à 21:16:10    

moi je dis que les accès tableau sont mal faits et font des page fault dans tout les sens. Ca serait aussi lent en C.


Message édité par schnapsmann le 27-09-2004 à 21:16:22

---------------
From now on, you will speak only when spoken to, and the first and last words out of your filthy sewers will be "Sir!"
Reply

Marsh Posté le 27-09-2004 à 21:23:19    

ouais.
 
quant à psyco, je crois qu'on est pas sur de l'utilisation que tu en fait ('import psyco' ne suffit pas hein)
 
et bordel de foin, spa compliqué de profiler tout ça !
 
 
et après, y a des trucs bidon dans ton code
 
range(-1, 1) j'ai jamais vu plus compliqué pour écrire (-1, 0)

Reply

Marsh Posté le 27-09-2004 à 21:38:48    

okok..
j'ai testé numarray, le profiling.. mais vu que j'avais pas mis dans une fonction ca peut pas etre optimisé. je test demain en profilant comme il faut, car pour le moment c toujours pareil.. j'ai bien testé numarray aussi..
effectivtement je peux bidouiller 2/3 trucs dans mon code comme le range mais ca changera pas trop le pb, et schnapsmann meme si peu y avoir des pagefault (code pas finit encore), c pas ca qui changera le pb de la vitesse, nivo algo je peut pas etre bcp plus rapide je pense.. ptet bien qu'en C ca serait lent aussi ;)
je reviens quand ca sera profilé comme il faut !

Reply

Marsh Posté le 28-09-2004 à 07:42:10    

Non, amha en C, tel que le programme est fait, ça serait quand même probablement bcp plus rapide.
 
Je connais pas trop Python, mais je pense que ce qu'il faut que tu fasses, c'est :
1. que tu optimises ta fonction normalize. Là, tu calcules bcp (trop) de sqrt à mon goût. Es-tu bien sûr que c'est nécessaire ? Les trois divisions, tu peux les remplacer par 3 multiplications. Ca ne va pas changer grand-chose, mais ça peut aider quand même.
2. des trucs du genre apply(ma fonction, mon tableau) partout où c'est possible, de façon à minimiser les opérations pixel par pixel. Dans ce genre de langage il faut minimiser les boucles imbriquées et utiliser au mieux leurs fonctionnalités natives de façon à bénéficier de la vitesse des opérations compilées en natif, en particulier la traversée d'un tableau. Cela implique de penser l'algo différemment / l'habitude.
3. as-tu utilisé les librairies correctement ? Si tu les as utilisées avec ton script (doubles boucles imbriquées, etc), c'est sûr que ça n'arrange rien. Mais la fonction produit vectoriel, il y a des chances qu'elle soit implémentée plus efficacement dans ce genre de librairie.
Et si y'a vraiment pas moyen de faire autrement que pixel par pixel (je pense notamment à une convolution), ben t'as aussi vite fait d'écrire la routine en C.


Message édité par el muchacho le 28-09-2004 à 07:57:10
Reply

Marsh Posté le 28-09-2004 à 09:57:40    

2) pas apply, ça a le surcout d'un appel de fonction, la syntaxe d'appel étendue est bien plus rapide. d'ailleurs c'est pas pas apply, mais map :o

Reply

Marsh Posté le 28-09-2004 à 21:20:27    

ok :jap:
 
Ceci dit c'est vrai qu'en y regardant de plus près, y'a un paquet de trucs à optimiser simplement dans le code, entre les divisions par des constantes, les calaculs de racines carrées à tout va, les boucles for (dx in -1, 1) imbriquées qui peuvent être déroulées, les multiples appels de fonctions qui n'ont guère lieu d'être, il doit y avoir moyen de diviser ses temps d'éxecution par 3.


Message édité par el muchacho le 28-09-2004 à 21:33:55
Reply

Marsh Posté le 28-09-2004 à 21:27:23    

Taz a écrit :

toi t'es marrant : un bleu bite de matheux fait son premier programme. 150 lignes de python (on à qu'à dire qu'en C ça ferait sans doute 700 lignes), tout ça en un seul fichier. et bien offuscé en plus, même très bien. tout est bien illisible. on a gus qui fait des matrice dans un tableau ... tout ça est ridicule. python a des super bibliothèques de math (SciPy, Numarray, etc) de très très bonne facture, il suffit qu'un  amateur poste un message juste après avoir terminer son application pour la première fois, et hop tu perds tout rationnel ...


 
c'etait juste une question  [:amandine75011]  [:joel f]

Reply

Marsh Posté le 28-09-2004 à 22:01:32    

ca y est a devient exploitable, merci pour les infos :)
 
j'ai galerré avec les profile, d'abord avec psyco mais je journal n'est pas tres revelateur, alors j'ai utilisé le module profile/stats, et la j'ai vu que c'était surtout l'appel massif aux fonctions qui prenait du temps (mais bien sur d'autres choses aussi n'allaient pas)
 
j'ai donc presque tout mis dans la meme fonction compute() et en plus j'ai simplifié les calculs a faire (quantisation de 0-255 vers -1,1 pour les normals, plus de normalisation, dot product en expression étendue).
 
je vous remets le nouveau code, il est pas trop long est plus lisible :
 

Code :
  1. import math
  2. #from numarray import *
  3. def seq_set_brush(pixels, x, y, width, height, size) :
  4.     len = size / 2
  5.     diff = ((size + 1.) % 2.) / 2.
  6.     for dx in range(- len, len + 1) :
  7.         for dy in range (- len, len + 1) :
  8.             fx = x + dx
  9.             fy = y + dy
  10.             if fx >= 0 and fy >= 0 and fx < width and fy < height :
  11.                 if (abs(dx) < len and abs(dy) < len) or diff == 0 :
  12.                     pixels[fx + fy * width] =  255
  13.                 else :
  14.                     color = int(pixels[fx + fy * width] + (255 * diff))
  15.                     if color > 255 : color = 255
  16.                     pixels[fx + fy * width] = color
  17. def compute(width, height, pixels, depths, ids, ndiff, zdiff, line_width) :
  18.     #take pixels, depths, ids sequences and output contour numarray
  19.     ndiff = 1. - ndiff;
  20.     contours = [0] * len(pixels)
  21.     #contours = zeros(len(pixels) )
  22.     for x in xrange(0, width):
  23.         if (x % 100 == 0) :
  24.             print "ALF_PROGRESS " + str(50 + int((float(x*height)/float(width*height))*50)) + "%"
  25.         for y in xrange(0, height):
  26.             p1 = pixels[x + y * width]
  27.             d1 = depths[x + y * width]
  28.             id1 = ids[x + y * width]
  29.             if d1 : d1 = d1 / 255.
  30.             computep = 0
  31.             for dx in (0, 1) :
  32.                 for dy in (0, 1) :
  33.                     if (dx or dy) :
  34.                         fx = dx + x
  35.                         fy = dy + y
  36.                         if fx >= 0 and fy >= 0 and fx < width and fy < height :
  37.                             p2 = pixels[fx + fy * width]
  38.                             d2 = depths[fx + fy * width]
  39.                             id2 = ids[fx + fy * width]
  40.                             if (d2) :
  41.                                 d2 = d2 / 255.
  42.                                 d = d2 - d1
  43.                                 if d < 0 : d = - d
  44.                             else :
  45.                                 d = d1
  46.                             if (p2 == p1) :
  47.                                 pa = 1
  48.                             else :
  49.                                 #normalize(p1)
  50.                                 if not computep and max(p1) : p1 = [(px - 128) / 128. for px in p1]
  51.                                 computep = 1
  52.                                 p2 = [(px - 128) / 128. for px in p2]
  53.                                 pa = sum([px*py for (px,py) in zip(p1, p2)]) #dot product                               
  54.                             if (pa < ndiff) or (d > zdiff) or (id1 != id2) :
  55.                                 seq_set_brush(contours, fx, fy, width, height, line_width)
  56.     return contours


 
 
je mets environ 25s (duron 1.8Ghz) pour traiter une image de 1600x1200 24bpp, sachant que le calcul est bien plus lourd qu'une convolution.. (de toutes façons le temps dépend du contenu de l'image)
 
j'ai essayé avec un filtre de detection de contour sur la normal map, mais ce n'est pas suffisemment precis, il faut qu'on puisse choisir les contours en fonction des normals, des profondeurs et des Ids, donc 3 maps a traiter, et le calcul n'est pas faisable en convolution proprement.
 
par contre j'ai un truc bizar, en utilisant numarrays, c'est 5x plus lent car il créer des objets numarray lors de la génération de list dans ce genre d'opérations :
p2 = [(px - 128) / 128. for px in p2]  
(d'apres ce que j'ai pu analyser, mais ce n'est ptet pas la cause de la lenteur)
 
je sais pas comment lui forcer de pas traiter ca, je voudrai utiliser numarray uniquement sur mon image de résultat (contours[]), du coup j'utilise pas numarray
 
par contre, du fait que l'image final soit générée a partir de 3 listes d'entrée hétérogènes, je ne vois pas trop comment optimiser tout ça avec des map(list,func), une idée ?
 
pour info, l'utilisation de psyco.bind() sur ma fonction compute divise presque par 3 le temps de calcul (24s vs 61s)


Message édité par thekraken le 28-09-2004 à 22:05:02
Reply

Marsh Posté le 28-09-2004 à 22:06:22    

thekraken a écrit :

ca y est a devient exploitable :)
 
par contre, du fait que l'image final soit générée a partir de 3 listes d'entrée hétérogènes, je ne vois pas trop comment optimiser tout ça avec des map(list,func), une idée ?
 
pour info, l'utilisation de psyco.bind() sur ma fonction compute divise presque par 3 le temps de calcul (24s vs 61s)


 
La syntaxe de map, ce n'est pas ce que tu as ecris mais ça :

Code :
  1. >>> help(map)
  2. map(function, sequence[, sequence, ...]) -> list


 
Comme ça, c'est très clair non ?

Reply

Marsh Posté le 28-09-2004 à 22:28:18    

#   for dx in (0, 1) :
#                 for dy in (0, 1) :
#                     if (dx or dy) :
 
 
déjà, ça tu peux dérouler ...
 
ou faire tou simplement
 
for dx, dy in ((1, 0), (0, 1), (1, 1))
 
 
faut que tu fasse gaffe que les list compréhension sont très puissante [] mais que ça crée un nouvelle liste complète à chaque fois, ce qui peut bouffer un peu de mémoire pour pas grand chose
 
 
n'hésite pas à faire des pré-calculs
plutot que d'évaluer 4 ou 5 fois ce genre de chose fx + fy * width  
 
ruse avec les propriétés des nombres
if color > 255 : color = 255  devient color &= 0xff
 
 
sauf preuve du contraire, dans ton cas, range est sans doute plus rapide que xrange

Reply

Marsh Posté le 28-09-2004 à 22:34:05    

Taz a écrit :


ruse avec les propriétés des nombres
if color > 255 : color = 255  devient color &= 0xff


 :heink:  :heink:

Reply

Marsh Posté le 28-09-2004 à 22:48:36    

vip merci j'avais meme pas pensé a ca tellement j'étais dedans..
enfin ca m'a fait gagné encore 2s (22s sur la meme image que t'alleur), c'est déjà ça de pris !
 
merci pour tout ;)

Reply

Marsh Posté le 28-09-2004 à 22:51:41    

tu devrais essayer avec les itertools sur cette portion
 
# p2 = [(px - 128) / 128. for px in p2]  
#                                 pa = sum([px*py for (px,py) in zip(p1, p2)])

Reply

Marsh Posté le 28-09-2004 à 23:12:15    

au fait, kristoph a raison, pour le
color &= 0xff
ce n'a pas le meme effet.. (modulo)
 
du coup j'ai mis
pixels[pos] = min(int(pixels[pos] + (255 * diff)), 255)

Reply

Marsh Posté le 28-09-2004 à 23:18:53    

ah oui, j'ai po fait attention. oops

Reply

Marsh Posté le 28-09-2004 à 23:54:13    

pour les itertools je vois pas trop, il faudrait passer de itérable à list (imap par exemple), alors que map() par exemple me permet de récupérer une list directement..
 
j'ai d'ailleurs essayé de remplacer les list comprehension par des map(lambda:,list), mais c'est beaucoup plus lent !! (50% plus lent)

Reply

Marsh Posté le 28-09-2004 à 23:56:39    

Si tu veux transformer un iterrable en list, il suffit de faire list(iter). Je ne vois pas trop pourquoi tu voudrais faire map(lamba:,list) sinon

Reply

Marsh Posté le 28-09-2004 à 23:58:43    

au fait, voila le genre de truc que ca permet de faire :
 
http://krakenleouf.free.fr/images/3stars.jpg
 
 
scene de base avec un shader façon dessin/peinture, le script calcul le contour des objets (outline autour des spheres ici). la tesselation des spheres est basique ici alors c'est normals s'il y a des petites cassures dans l'outline (on voit que c de la 3D comme ça ;) )

Reply

Marsh Posté le 29-09-2004 à 00:03:10    

dans
 
# p2 = [(px - 128) / 128. for px in p2]  
#                                 pa = sum([px*py for (px,py) in zip(p1, p2)])
 
 
il me semble que tu construits inutilement 3 listes  
 - p2
 - le résultat de zip
 - l'argument de sum

Reply

Marsh Posté le 29-09-2004 à 00:04:18    

par exemple moi j'ai essayé
p2 = map(lambda xp : (xp - 128) / 128., p2)
 
a la place de  
p2 = [(px - 128) / 128. for px in p2]
 
en itertools ca donnerait un truc genre
p2 = list(imap(lambda xp : (xp - 128) / 128., p2))
 
si j'ai bien compris, je connais pas bcp python, mais je vois pas pkoi le fait de passer par de iterateurs serait plus rapide ??
 
on parle peut etre pas de la meme utilisation ?

Reply

Marsh Posté le 29-09-2004 à 00:09:14    

les LC sont très souvent plus rapide que map.
 
quand aux iterateurs : techniquement ils sont plus lent, mais si t'es listes sont grosses, ça t'évite de les créer, ici, tu évites 3 listes temporaires. vois les itérateurs comme des générateurs, qui fournisse 1 élément à la fois. en fonction de la taille de tes listes, il faut faire des mesures, ça peut être intéressant
 
en gros ta transformation, faut pas repasser par la case list, sauf sum (qui retourne une liste donc c'est bon)
 
faut mesurer et voir


Message édité par Taz le 29-09-2004 à 00:14:12
Reply

Marsh Posté le 29-09-2004 à 00:12:00    

taz : les listes ce sont des vecteurs a 3 composantes, donc c'est pas bien grave d'utiliser des variables de calculs intermediaires ?
 
-pour l'arguement de sum, je suis obligé, il faut bien d'abord que je calcul le produit de chaque composant puis la somme des produits calculés.
-pour p1 et p2, ca m'evite d'ecrire une ligne de code de 200 caracteres, y a une autre solution ?
-pour zip je doit associé chaque composant des 2 listes, par concaténer les listes, je vois pas comment faire ça plus simplement..
 
je vois pas trop comment faire autrement, ptet que je connais pas assez python pour comprendre ces subtilités..

Reply

Marsh Posté le 29-09-2004 à 00:13:15    

ok je comprend pour les itérateurs, la c'est des vecteurs 3D donc c'est pas util a priori.
 
les LC ça tue ;)

Reply

Marsh Posté le 29-09-2004 à 00:18:11    

si c'est des vecteurs 3 éléments, je comprends pas pourquoi t'écris pas une jolie fonction toute simple et bien plus lisible ! surtout que c'est typiquement ce genre de petite fonction qui font déjà partie des bibli

Reply

Marsh Posté le 29-09-2004 à 00:27:13    

parceque, comme j'ai dis plus haut ("appel massif aux fonctions qui prenait du temps" ), c'est bcp plus rapide de passer par cette LC que par une fonction, interne ou déjà existante dans une lib..
 
j'ai fais les tests et les écarts sont non négligeables !
 
si les calculs étaient plus lourd que ca (ici c'est encore que quelques +*-), le temps d'appel d'une fonction de manière systématique (avec l'impilage des arguments..) serait rentabilisé par la longueur des calculs..
 
et puis ici j'utilise le calcul qu'1 et 2 fois dans ma boucle donc c'est pas génant pour l'écriture du script (je mets ce que c'est en commentaire et voila..)

Reply

Marsh Posté le 29-09-2004 à 03:56:27    

et alors ? entre créées 3 listes inutilement, appeler sum, appeler zip et appeler uniquement 1 seule fonction, tu sais plus compter ?
 
faut arrêter la paranoia du débutant : tu dis que les appels de fonctions sont lents, d'accord, maintenant faut l'appliquer :  
 
# p2 = [(px - 128) / 128. for px in p2]  
#                                 pa = sum([px*py for (px,py) in zip(p1, p2)])  
 
est clairement améliorable dans ton cas

Reply

Marsh Posté le 29-09-2004 à 13:27:50    

ollaaa je sais pas ce que j'ai merdé mais j'ai merdé !
j'ai du faire des erreurs avec les index dans le LC qui me faisaient croire que c'était plus rapide (débutant..)
 
en mettant
 
pp1 = [0, 0, 0]
pp1[0] = (p1[0] - 128) / 128.
pp1[1] = (p1[1] - 128) / 128.
pp1[2] = (p1[2] - 128) / 128.
 
pa = p1[0] * p2[0] + p1[1] * p2[1] + p1[2] * p2[2]
 
au lieu des LC c'est bien plus rapide  (fonctions ou pas fonctions, donc j'ai mis des fonctions ;) )
 
8s au lieu de 15s !!!
 
bon j'avoue la que j'ai bien merdé, ca m'apprendra a taffer tout fatigué.
 
merci d'avoir insisté et heureusement que j'ai retesté, ça m'intriguait qd meme !
 
du coup ca va, 8s pour traiter 3 images en 1280x1024 (soit 640x480 apres antialiasing), c'est tres correct en utilisation !
 


Message édité par thekraken le 29-09-2004 à 14:23:06
Reply

Marsh Posté le 01-10-2004 à 07:58:50    

Donc tu es passé d'une image 1280x1024 en 5 minutes à 3 images en 8 secondes et ce sans écrire une ligne de C ? Si oui, ça valait le coup d'optimiser.

Reply

Marsh Posté le 13-10-2004 à 16:11:47    

j'étais en vacances dc pas pu répondre plus tot..
 
non c'est le meme traitement (3 images à traiter à chaque fois), mais passé de plusieurs minutes a une 10aine de secondes pour la même taille d'image. Donc oui ça valait le coup et je pense qu'en C ça aurait pas été beaucoup plus rapide (et puis ca aurait été plus relou car la j'utilise PIL pour supporter plus de formats d'images facilement)..

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed