Optimisation traitement d'images - Python - Programmation
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.
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 ...
Marsh Posté le 27-09-2004 à 20:26:21
HelloWorld a écrit : T'utilises la dernière version de Python ? |
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
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 ??
Marsh Posté le 27-09-2004 à 20:52:16
thekraken a écrit : oui la derniere version ! |
On t'a dit d'utiliser SciPy et numarray ( et peut-être aussi PIL pendant que tu y es )
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.
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).
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
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.
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)
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 !
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.
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
Marsh Posté le 28-09-2004 à 21:20:27
ok
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.
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
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 :
|
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)
Marsh Posté le 28-09-2004 à 22:06:22
thekraken a écrit : ca y est a devient exploitable |
La syntaxe de map, ce n'est pas ce que tu as ecris mais ça :
Code :
|
Comme ça, c'est très clair non ?
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
Marsh Posté le 28-09-2004 à 22:34:05
Taz a écrit : |
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
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)])
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)
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)
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
Marsh Posté le 28-09-2004 à 23:58:43
au fait, voila le genre de truc que ca permet de faire :
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 )
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
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 ?
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
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..
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
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
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..)
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
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 !
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.
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)..
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 :