Forum général.général Projeter une image le long d'un chemin

Posté par (page perso) .
Tags : aucun
0
18
mai
2012

Bonjour,

J'ai une image qui a un aspect allongé, comme une longue tige, genre 2000x60 pixels. J'aimerais la déformer de manière à ce qu'elle suive la forme décrite par une courbe de Bézier.

J'ai essayé avec le filtre « Distorsion/Courber » de Gimp mais le résultat ne me satisfait pas. La tige déformée est beaucoup plus épaisse que l'originale.

J'ai cherché dans ImageMagick, sans succès.

J'ai voulu écrire l'algo, mais c'est plus dur que je ne le pensais.

Et maintenant je suis à cours d'idée. Connaissez-vous un outil pour faire cela ?

  • # Essaye peut être

    Posté par . Évalué à 3.

    Bonjour,

    essaye peut être Inkscape.

    Je ne sais pas du tout si c'est possible avec.

    Tiens-nous au courant, c'est intéressant.

    Bonne journée
    G

  • # Déformation par cage

    Posté par . Évalué à 4.

    As-tu essayé la version 2.8 de Gimp ? il existe un outil de déformation par cage (directement dans les icones de la fenêtre principale) qui fait ce que tu veux. Tu dessines une « cage » (un polygone) autour d'une sélection. Puis tu bouges les nœuds du polygone et ça déforme l'image à l'intérieur.

    Si tu vas voir la dépêche récente concernant Gimp 2.8, il y a un lien vers une vidéo qui fait la démonstration de cet outil. https://linuxfr.org/news/gimp-2-8-est-sorti-une-fenetre-unique#toc_5

    • [^] # Re: Déformation par cage

      Posté par (page perso) . Évalué à 2.

      J'ai essayé avec la transformation par cage de Gimp 2.8 mais je n'arrivais pas à obtenir une belle courbure. L'épaisseur de la tige variait par endroit.

      J'ai peut-être une autre piste mettant l'image à déformer dans le presse-papier puis en sélectionnant l'opération « tracer le chemin » sur ma courbe, en utilisant l'outil « Clone » définit sur l'image du presse-papier. Je n'ai pas encore pu essayer ça.

      • [^] # Re: Déformation par cage

        Posté par (page perso) . Évalué à 1.

        Et je confirme que tracer le chemin avec l'outil « clone » ne donne pas un bon résultat. La tige n'est pas inclinée selon la pente de la courbe.

  • # Long cat is looooooong !

    Posté par . Évalué à 0.

    J'ai une image qui a un aspect allongé, comme une longue tige, genre 2000x60 pixels.

    Une image comme celle-ci ?

    http://images2.wikia.nocookie.net/__cb20081222171126/uncyclopedia/images/9/91/Loooooooooooooooooooooooooooooooooooooooooongcat.JPG

  • # Et Blender ?

    Posté par . Évalué à 1.

    Peut-être que Blender pourrait te venir en aide.

    Tu actives l'addon "Import Image as Plane" qui crée un mesh de type plan proprement texturé avec ton image et aux bonnes dimensions XY. Tu subdivide le plan plusieurs fois pour pouvoir le déformer, tu le déforme selon ta volonté (avec un modificateur courbe de bézier (modificateur curve) ou avec une cage de déformation (modificateur lattice)).

    Pour terminer, tu rends ta scène avec une caméra en mode orthographique. Dans l'onglet Matériau, choisi le mode "shadeless" et pense à demander un rendu RGBA, ce qui remplacera le fond par de la transparence.

  • # Algo

    Posté par . Évalué à 1.

    J'ai voulu écrire l'algo, mais c'est plus dur que je ne le pensais.

    Qu'est-ce qui t'a posé problème? Il y a une imprécision dans ton problème: est-ce que la hauteur de l'image déformée varie ou reste constante?

    Dans le premier cas, il n'y a rien de difficile, dans le second c'est un peu plus dur (il faut reparamétrer la courbe par sa longuer d'arc et je ne sais pas le faire plus intelligemment qu'en utilisant une intégrale que je ne sais pas calculer — donc utilisant des méthodes numériques).

    Si la cas 1 t'intéresse je peux te donner plus de détails.

    • [^] # Re: Algo

      Posté par (page perso) . Évalué à 2.

      La hauteur de mon image est constante, mais ça me semble plus simple que si elle variait, non ?

      Pour éclaircir les choses, voici une illustration de ce que je veux.

      Titre de l'image

      Je pars de la tige bleu/vert/rouge à gauche et je veux la tordre de manière à ce que le haut suive la courbe bleue, en la répétant éventuellement jusqu'à avoir rejoint les deux bouts de la courbe. Le résultat attendu est en bas.

      Mes courbes ont toutes ce genre de forme : soit décroissante, soit croissante. J'ai récupéré l'équation des courbes de Bézier sur Wikipédia. La première difficulté est de calculer le pas d'incrément du paramètre t de l'équation. Je triche déjà en profitant des propriétés de mes courbes pour déterminer t en fonction du x pour lequel je veux le y.

      Une fois que j'ai le point (x, y) de ma courbe dans l'image résultat, il faut que je colle un bout de l'image source « sous » le point. C'est la que les difficultés commencent. Il faut déjà que je retrouve l'abscisse correspondant à mon t dans l'image initiale, en calculant la longueur de la courbe entre son origine et le point (x, y).

      Il faut aussi que je calcule l'orientation de la courbe pour mon t courant.

      Ensuite, si je colle une colonne de pixels de mon image source sous mon point dans la direction orthogonale à la courbe, je vais avoir des trous. Il faut plutôt que je prenne les points sous la courbe et que je retrouve à quel point ils correspondent dans l'image source.

      Enfin, les points qui correspondent au bas de l'image source vont avoir tendance à se superposer dans la projection. Il faut que je mélange les couleurs dans le résultat.

      Finalement tout ce que j'arrive à produire est un bandeau gris moche.

      • [^] # Re: Algo

        Posté par . Évalué à 3. Dernière modification le 20/05/12 à 12:12.

        Voilà ce que je te propose:

        Tu as ton plan de départ A qui contient des pixels et ton plan d'arrivée B qui contient des pixels, pour décrire la transformation j'introduis des plans A' et B' dont les points ont des vraies coordonnées en nombre réels, et je suis le chemin: A → A' → B' → B.

        A → A'

        Tu regardes chaque point de ton image (point de A) comme un point de A' avec des coordonnées entières, et marqué d'une couleur, cela te fait un ensemble P de points.

        A' → B'

        Avec «ta triche» tu sais présenter ta courbe comme y = f(x), tu passes de A' à B' en envoyant le point (ξ,η) sur le point (ξ,η+f(ξ)), sans toucher à sa couleur. Cela te fait un ensemble Q de points colorés, qui est dans B' mais dont les coordonnées ne sont pas de nombres entiers (à cause du terme f(ξ)).

        B' → B

        Pour pousser B' sur B on regarde chaque point β de B (B est en mode pixel) et on se pose la question «de quelle couleur faut il le colorier?» Pour cela tu peux choisir plusieurs méthodes.

        La plus simple consistant à choisir la couleur du point de Q qui est le plus proche de β — sauf si β est assez loin de Q, auquel cas il reste sans couleur.

        Une autre méthode consiste à faire une «moyenne» des couleurs des points les plus proches de β. Par exemple, tu peux prendre tous les points situés à distance au plus d de β et leur affecter un coefficient de type 1/(1 + (distance à β)²) qui donne un plus fort poids au points proches de β. À la fin β est colorié par la moyenne des couleurs de ses voisins, pondérée par nos coefficients.

        Ce que veux dire moyenne pour les couleurs n'est pas tout à fait clair, mais je pense que si tu fais la moyenne des coordonnées RGB ou CMYK, tu obtiens un résultat raisonnable.

        Conclusions

        La partie la plus dure est probablement B' → B, et si tu représentes Q par une liste, cela peut commencer à durer un petit peu longtemps de chercher les points proches de β pour chaque β! Par exemple si to image de base fait w par h et ton image d'arrivée W par H, la méthode naïve te donne whWH calculs de distance et un petit nombre de moyennes à calculer. Pour gagner un peu de temps tu peux utiliser un strucure récurrente de type

        bout_de_plan (x0, y0, x1, y1):
        niveau: nombre entier
        case: liste de points
        a: bout_de_plan (une moitié de (x0, y0, x1, y1))
        b: bout_de_plan (l'autre moitié de (x0, y0, x1, y1))

        L'insertion d'un point β se fait:
        — dans la case si le niveau est plus grand qu'un seuil fixé (la profondeur de ta structure)
        — dans la case si le disque de centre β de rayon d n'est pas contenu entièrement dans a ou dans b.
        — dans le bout de pan a si le disque de centre β de rayon d est contenu entièrement dans a
        — dans le bout de pan b si le disque de centre β de rayon d est contenu entièrement dans b

        La recherche d'un point β se fait comme l'insertion, on regarde où on doit ranger β pour voir s'il y est déjà ou point.

        La recherche des points à distance au plus d de β se fait dans la case contenant β, c'est ici qu'on gagne du temps.

        Pour construire la structure tu pars d'un bout de plan qui correspond soit à ton A' soit à ton B' puis tu le coupes en 2 dans le sens de la hauteur pour obtenir a et b, chacun est ensuite coupé en 2 dans le sens de la largeur pour obtenir 4 autres bout de plan et ainsi de suite. Si tu choisis une profondeur N cela coupe le plan en 2N+1 cases pour des images une profondeur entre 8 et 12 devrait suffire.

        Bon courage! :)

        • [^] # Re: Algo

          Posté par (page perso) . Évalué à 2.

          Je pense qu'il y a une difficulté qui n'est pas levée. La courbe n'a pas la même équation sur la projection de la partie haute de la source et sur la projection de la partie basse. En d'autres termes, la transformation de la ligne de pixels en bas de la source ne suit pas l'équation de la courbe. Je ne vois pas dans ta solution comment cela se résout.

          Le fait de te répondre précédemment m'a donné quelques idées, et j'obtiens enfin un résultat suffisant :

          Titre de l'image

          Je triche toujours sur certains points et du coup l'algo est très lent, mais c'est toujours plus rapide que de dessiner à la main :)

          Pour calculer la longueur de la courbe entre l'origine et le point à l'instant t, je somme les distances par un pas de \epsilon = 0.00001. Ça se traîne.

          Pour calculer la tangente à l'instant t, je calcule la direction par rapport au point à t - \epsilon et par rapport à t + \epsilon, et je prends la direction moyenne.

          Je ne fais pas de mélange de couleurs. Pour chaque point dans la destination je prends le meilleurs point dans la source.

          Je ne suis pas très fier de la tête de l'algo mais je suis content du résultat !

          • [^] # Re: Algo

            Posté par . Évalué à 2.

            La courbe n'a pas la même équation sur la projection de la partie haute de la source et sur la projection de la partie basse. En d'autres termes, la transformation de la ligne de pixels en bas de la source ne suit pas l'équation de la courbe.

            Je ne comprend absolument pas ce que tu veux dire… tu peux me le dire avec des x et des y? :)

            Pour calculer la longueur de la courbe entre l'origine et le point à l'instant t, je somme les distances par un pas de \epsilon = 0.00001. Ça se traîne.

            — mémorise des valeurs, disons tous les 1000 calculs, tu te souviens de la valeur, ce qui t'évite de faire plus de 1000 calculs. Dans ton exemple tu passerait de

            N(N-1)/2 avec N = 100 000

            opérations à

            100 N(N-1)/2 avec N = 1000

            opérations (environ), soit 100 fois moins.

            Pour calculer la tangente à l'instant t, je calcule la direction par rapport au point à t - \epsilon et par rapport à t + \epsilon, et je prends la direction moyenne.

            Là c'est maladroit parceque tu disposes de x(t) et de y(t) et que la dérivée est simeplement (x'(t), y'(t)) (2 multiplications de moins et pas de division!)

            • [^] # Re: Algo

              Posté par (page perso) . Évalué à 1.

              Je ne comprend absolument pas ce que tu veux dire… tu peux me le dire avec des x et des y? :)

              En mettant de côté la répétition de la source dans la destination, pour un point (x, 0) dans l'image source, il n'y a qu'un point qui corresponde dans l'image destination. Ce point est pile sur la courbe. Par contre, pour (x, 60) il y a plusieurs points qui correspondent dans la destination, tous à distance 60 de la courbe. Du coup, l'équation qui décrit la projection de la ligne 60 n'est pas la même que celle qui décrit la projection de la ligne 0.

              Je ne suis pas sûr d'être clair…

              • [^] # Re: Algo

                Posté par . Évalué à 2.

                Je ne suis pas sûr d'être clair…

                Effectivement! :)

                la répétition de la source dans la destination

                qu'est-ce que tu veux dire?

                il n'y a qu'un point qui corresponde dans l'image destination

                Je ne comprend pas de quelle correspondance il s'agit — cela à voir avec la méthode que tu utilsies, pas celle que je t'ai proposé c'est ça?

                • [^] # Re: Algo

                  Posté par (page perso) . Évalué à 1.

                  Je reviens sur les illustrations pour m'exprimer. Voici l'exemple :

                  Titre de l'image

                  Le motif à répéter est en haut à droite, il est volontairement plus haut que large pour accentuer l'effet. La courbe contre laquelle le motif est projeté est en blanc.

                  la répétition de la source dans la destination

                  qu'est-ce que tu veux dire?

                  Le motif a une largeur bien inférieure à la longueur de la courbe. Il est donc répété le long de la courbe.

                  Pour l'autre point, tu proposes dans ta solution d'utiliser l'équation y = f(x) de la courbe pour aller de A' dans B'. Cette transformation ne transforme correctement que les points du haut du motif, c'est à dire ceux qui se retrouveront pile sur la courbe. Les points du bas suivent une autre courbe/équation. Ici cette autre courbe est visible en jaune.

                  Je disais que les points du bas du résultat, ici vers la courbe jaune, n'ont pas qu'un seul candidat dans l'image source. Cela se voit bien dans le second virage où les points violets se rapprochent. En accentuant la courbure ils se superposeraient. De même, les points du bas du motif n'ont pas qu'une seule projection dans le résultat. Cela est visible dans la partie en haut à gauche de la courbe jaune, où les points violets sont écartés.

                  En tout cas, merci pour tes commentaires ; je suis content du résultat.

                  • [^] # Re: Algo

                    Posté par . Évalué à 2. Dernière modification le 22/05/12 à 22:41.

                    Cette transformation ne transforme correctement que les points du haut du motif, c'est à dire ceux qui se retrouveront pile sur la courbe. Les points du bas suivent une autre courbe/équation. Ici cette autre courbe est visible en jaune.

                    J'avais fait seulon ton premier dessin, dans le second ce qui tu veux me semble plus clair.

                    Il faut que tu envoies le point (ξ,η) sur le point (ξ,f(ξ)) + η N(ξ) où N(ξ) est le vecteur unitaire normal à la courbe (dans l'orientation habituelle du plan) N(ξ) = (-f'(ξ),1)/SQRT(1 + f´(ξ)²).

                    Je disais que les points du bas du résultat, ici vers la courbe jaune, n'ont pas qu'un seul candidat dans l'image source.

                    C'est pour cela que le plus simple est probablement de déterminer la couleur en faisant une moyenne comme je te le propose dans B' → B !

  • # OpenGL

    Posté par (page perso) . Évalué à 2.

    Tu dessines ta "courbe" comme un plan qui a la forme que tu veux, puis tu mappes ton image dessus comme une texture, et basta, non ?

    • [^] # Re: OpenGL

      Posté par (page perso) . Évalué à 1.

      C'est déjà difficile de dessiner la courbe en OpenGL. Sur l'image que j'ai postée plus haut, avec le bandeau noir, je saurais calculer des sommets de quads pour longer la courbe blanche, mais je ne saurais pas les calculer pour la courbe jaune. Le calcul des coordonnées dans la texture ne me semble pas évident non plus, et en plus il faudra que je découpe le bandeau en parties convexes.

      On est très loin d'un « basta » avec ça. Autant tenter Blender, mais là encore ça ne serait pas évident de tracer la courbe jaune.

      • [^] # Re: OpenGL

        Posté par (page perso) . Évalué à 2.

        Dans mon idée, tu traces une courbe un plan pour Z=0, ensuite, tu dupliques la courbe pour Z=5 par exemple, donc ça te fait un bandeau.
        Tu mappes ta texture dessus, de manière on ne peut plus régulière, ce qui est simple.
        Ensuite, et c'est pour ça que j'ai parlé d'OpenGL (mais Blender, c'est pareil), tu n'as qu'à changer l'angle de vue, et la perspective (i.e. les "déformations") se fait toute seule !

        Ou alors j'ai pas compris ce que tu veux faire…

        • [^] # Re: OpenGL

          Posté par (page perso) . Évalué à 3.

          Ha, je crois que j'ai compris enfin, et ma réponse n'est donc apparemment pas adaptée à tes besoins…
          Tu veux pas changer de besoins ? :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.