Un petit truc bricolé rapidement sous matlab, ça simule l'équation complexe de Ginzburg-Landau (une équation classique en physique), c'est un système de diffusion-réaction qui fait de bien jolis dessins en 2D :
http://www.youtube.com/watch?v=qive3x0rzRg
http://codeinthehole.com/tutorials/cgl/index.html
Bref ici je prend comme condition initial des caractères et je les laisse évoluer un moment, voilà ce que ça donne :
Dites moi si vous voulez le code. Ca serait assez facilement implémentable dans processing, mais c'est un peu lent.
Hors ligne
Chouettes résultats, ça ressemble un peu à des lettres ornementales anciennes, en particulier sur cannibal. Envoies le code, je ne connais pas matlab mais je suis intéressé par tenter une transcription sur processing.
Hors ligne
Le résultat est assez séduisant : il évoque une forme d'empreinte.
Hors ligne
Voila, c'est relativement simple, mais il faut ne pas oublier que A est une variable complexe. Si jamais je peux expliquer plus en détails.
dt = 0.004; Nt = 1000; E = 350; Nx = 1000; dx = E/Nx; A = zeros(Nx,Nx); %letter as initial cond A = initLetter; i = sqrt(-1); alpha = 4; D = 0.4; beta = 6; %diffusion H = [0 1 0; 1 -4 1; 0 1 0;]; H = D*H / dx^2; for t=1:Nt D2A = imfilter(A,H); A = A + dt*(A +(1+i*alpha).*D2A - (1-i*beta)*( abs(A).^2 ).*A ); end imagesc(real(A))
Hors ligne
Aussi le .* est une multiplication élément par élément, c'est équivalent a une double boucle de 1 a Nx.
Hors ligne
Assez facile à implémenter dans processing, c'est vite dit Je bloque sur plusieurs trucs, et ce que j'ai pu trouver sur le net sur java et les complexes ne m'a pas vraiment éclairé... Je ne comprends pas vraiment comment on fait des calculs avec ces nombres (et processing). En tout cas, matlab, c'est drolement efficace pour ce genre de trucs.
Bon, si tu as le temps de jeter un oeil, je veux bien de tes conseils éclairés ou des liens pour mieux comprendre comment on passe du plan complexe au plan réel, quelques questions en vrac :
A = initLetter; ça consiste bien à charger les pixels d'un caractère dans A ?, Et avec quel ordre de grandeur : 0-255 ?
i = sqrt(-1); c'est bien ce qui définit la partie imaginaire des complexes, mais java n'a pas d'imagination...
D2A = imfilter(A,H); c'est bien une matrice convolution H appliquée sur A ?, H n'est pas composée de nombres complexes, est ce que cette matrice n'agit que sur la partie réelle de A ?
A = A + dt*(A +(1+i*alpha).*D2A - (1-i*beta)*( abs(A).^2 ).*A ); me laisse perplexe, j'imagine qu'il faudrait faire une fois cette équation pour la partie réelle et une fois pour la partie imaginaire, mais en fait je suis dans le flou....
Voila mon code dans l'état, et l'image depuis laquelle je suis parti :
Hors ligne
T'es pas trop loin du résultat je crois. Mais c'est vrai que les nombres qui n'existent pas c'est un peu emmerdant des fois
citation :
A = initLetter; ça consiste bien à charger les pixels d'un caractère dans A ?, Et avec quel ordre de grandeur : 0-255 ?
Oui c'est pour fixer la condition initiale, je me souviens plus trop de l'échelle mais c'est plutôt entre zéro et 1.
citation :
i = sqrt(-1); c'est bien ce qui définit la partie imaginaire des complexes, mais java n'a pas d'imagination...
Ouais, c'est un truc spécifique à matlab.
citation :
D2A = imfilter(A,H); c'est bien une matrice convolution H appliquée sur A ?, H n'est pas composée de nombres complexes, est ce que cette matrice n'agit que sur la partie réelle de A ?
Oui c'est un convolution, c'est l'opérateur de diffusion mais c'est une sorte de filtre qui moyenne (floute) l'image.
En fait le truc c'est qui faut tout décomposer en partie réel et imaginaire et faire les calculs sur chaque partie, c'est ce que tu as commencé à faire en déclarant tes deux matrices A et I.
Pour la diffusion il faut passer chaque matrice indépendamment dans le filtre parce que l'opérateur de diffusion (la deuxième dérivée) est linéaire. C'est à dire que la deuxième dérivée spatiale d'un nombre complexe z= x+i*y (donc x est la partie réel de z et y la partie imaginaire) est égale à la dérivée de x plus i fois la dérivée de y.
Ensuite il faut faire la même chose avec l'équation, exprimé chaque terme comme z = x + iy et calculer la partie réelle et imaginaire. C'est un peu plus compliqué parce que c'est non-linéaire. Par exemple si tu multiplie deux nombres complexes z = x+iy et p = u+iv :
z p = (xu - yv) + i(vx + uy)
Faut aussi savoir que la valeur absolue de z est égale à la racine de x^2 + y^2.
Pour l'équation, en reprenant ta notation (sans les [][]) ça me donne :
A = A + dt * ( A + D2A - aalpha*D2I - (pow(A,2) + pow(I,2))*(A +beta*I)
I = I + dt * ( I + D2I + aalpha*D2A -(pow(A,2) + pow(I,2))*(I - beta*A)
Pas sur que ça soit juste mais ça me semble pas trop mal.
C'est sur que c'est plus simple dans matlab... ça risque d'être très lent aussi, y'a vraiment beaucoup de boucles.
Un autre problème qui peut arriver c'est quand le dt est trop grand l'équation "explose" et tu va te retrouver avec des valeurs infinies.
Hors ligne
Merci, tu m'as tiré de l'impasse
Je suis arrivé à quelque chose, j'ai rajouté différents modes de mapping des valeurs brutes et ça change beaucoup le résultat graphique, on peut "trouver" pas mal de choses en les modifiant. Mais comme tu disais, c'est très très lent! Du coup, il faut le nourrir avec de petites images...
J'essaierais bien en couleur, mais ce sera encore plus lent. Sinon, en changeant les paramètres on peut effectivement tout faire sauter, je suppose que les calculs doivent donner des "Not a Number", des carrés noirs apparaissent et grossissent jusqu'à remplir l'image.
Quelques images faites au fur et à mesure
Hors ligne
La classe !
Je sais pas si on peut faire quelque chose pour accélérer le truc. Peut-être utiliser filter(BLUR, 6) : http://processing.org/reference/filter_.html
Ou alors utiliser GLGraphics :
http://glgraphics.sourceforge.net/
Hors ligne
alors là je dis : chapeau bas !
en utilisant gl ça peut en effet aller plus vite, mais faut remettre les mains dans le cambouis...
en tout cas bel algorithme !
Hors ligne
Merci,
C'est surement possible d'accélérer tout ça, peut-être aussi en tapant directemetn dans le tableau de pixels avec loadpixels() plutot qu'en utilisant point(). D'ailleurs je viens de relire la doc de point() et il est conseillé d'utiliser P2D comme renderer, je viens de faire l'essai
Avec le code plus haut, 100 générations sont calculées en 37'5
Avec le code + P2D, 100 générations sont calculées en 13'3
Presque 3 fois plus rapide! Il suffit de remplacer size(400, 400); par size(400, 400, P2D); dans le setup()...
Hors ligne
Ca va plutôt vite je trouve !
Je vais regarder ça un peu plus en détail ce week-end. C'est vraiment marrant ces équations, y'a une richesse incroyable alors que l'équation est relativement simple.
Dernière modification par Staross (2010-11-12 19:31:03)
Hors ligne
Juste pour dire qu'avec GEM il est possible d'avoir un peu le même genre de rendu, et ce en temps réel, super fluide, grâce à GLSL. C'est un effet que j'utilise beaucoup en live et qui est basé sur l'exemple :
Gem / Examples / glsl / framebuffer_and_shader.pd (Cyrille Henry)
(Bon c'est un peu HS mais si vous voulez voir le bidule suffit que je retrouve le patch...)
Dernière modification par rep (2010-11-12 20:42:27)
Hors ligne
Pages: 1 2