IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Traitement d'images Discussion :

Placage de texture en 2D : Transformation inverse


Sujet :

Traitement d'images

  1. #1
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut Placage de texture en 2D : Transformation inverse
    Bonjour à tous, je but sur un problème depuis quelques jour. (encore une fois mathématique, et vue que je n'avais pas choisie une branche S, je patoge un peu). J'ai fais des recherches sur le web mais je n'ai rien trouvé dans ce sens pour des transformations inverse cylindrique ou sphérique

    A l'heure actuelle j'ai 2 méthodes qui me permette de rendre une texture soit sphérique soit cylindrique.
    Afin d'éviter toute dispersion, je vais commencé par le placage de texture sur un cylindre.

    La formule de transformation de coordonnées cartésiennes vers cylindrique et vice versa (wiki et paul bourke):

    Si le point P a les coordonnées cylindriques ρ, φ, z alors ses coordonnées cartésiennes correspondantes sont :
    Si le point P a les coordonnées cartésiennes x, y, z alors ses coordonnées cylindriques correspondantes sont :

    Nom : coords2.gif
Affichages : 125
Taille : 1,8 Ko

    Voici ma texture d'origine

    Nom : 440px-LCLArchitecture.png
Affichages : 100
Taille : 58,3 Ko

    Maintenant, mon code de plaquage de texture sur un cylindre en 2D avec la possibilité de faire "tourner" sur l'axe x ou y suivant l'orientation du cylindre choisie

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    procedure CylindricalMappingFrom(Texture: TBZBitmap; OffsetX, OffsetY, Radius, CylinderLen: Integer; Const Horizontal: Boolean; Const Rotation: Single);
    var
      L, LL : Single;
      vx, vy, vz : Single;
      i, j, u, v : Integer;
      aColor : TBZColor;
     
      procedure RotZ(angle : Single; var x : Single; var y : Single);
      var
        x1, y1, c, s : Single;
      begin
         s := Sin(Angle);
         c := Cos(Angle);
         x1 := x * c - y * s;
         y1 := x * s + y * c;
         x := x1;
         y := y1;
      end;
     
    begin
      if Horizontal then
      begin
        L := (c2PI / Texture.Height);
        LL := (CylinderLen / Texture.Width);
      end
      else
      begin
        L := (c2PI / Texture.Width);
        LL := (CylinderLen / Texture.Height);
      end;
      for j := 0 to Texture.MaxHeight do
      begin
        vz :=  J * LL;
        for i := 0 to Texture.MaxWidth do
        begin
     
          if Horizontal then vx := (Radius * cos(i * L))
          else vx := -(Radius * cos(i * L));
     
     
          vy := (Radius * sin(i * L));
     
          if (Rotation <> 0) then RotZ(DegToRadian(Rotation), vx, vy);
     
          if (vy > 0.0) then // on dessine que les pixels visible
          begin
            aColor := Texture.getPixel(i,j);
     
            if Horizontal then
            begin
              u := OffsetX + Floor(vz);
              v := OffsetY + Radius + Floor(vx);
            end
            else
            begin
              u := OffsetX + Radius + Floor(vx);
              v := OffsetY + Floor(vz);
            end;
            // On dessine un carré de 3x3 pixel pour éviter au maximum les artefacts
            OwnerBitmap.setPixel(u, v, aColor);
     
            OwnerBitmap.setPixel(u - 1, v, aColor);
            OwnerBitmap.setPixel(u + 1, v, aColor);
     
            OwnerBitmap.setPixel(u, v - 1, aColor);
            OwnerBitmap.setPixel(u, v + 1, aColor);
     
            OwnerBitmap.setPixel(u - 1, v - 1, aColor);
            OwnerBitmap.setPixel(u + 1, v - 1, aColor);
     
            OwnerBitmap.setPixel(u - 1, v + 1, aColor);
            OwnerBitmap.setPixel(u + 1, v + 1, aColor);
          end;
        end;
      end;
    end;

    Le résultat n'est pas mauvais, mais n'est pas très bon, surtout suivant le ratio du "Radius/Longueur" avec les dimensions de la texture. C'est pour cela que je cherche à faire une transformation inverse pour obtenir un rendu de meilleur qualité.

    Résultat du code ci-dessus pour un cylindre horizontal (la texture tourne dans le sens vertical suivant la rotation)
    Nom : 2020-08-22_193225.jpg
Affichages : 94
Taille : 21,8 Ko

    Maintenant le code pour "essayer de faire" la transformation inverse (je cherche donc les coordonnées (i,j) dans la texture suivant le point (u,v) sur l'image de destination.

    Ici c'est juste l'orientation horizontal et sans prendre en compte la rotation

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    procedure CylindricalMappingFromInv(Const ATexture: TBZBitmap; OffsetX, OffsetY, Radius, CylinderLen: Integer; Const Horizontal: Boolean; Const Rotation: Single);
    var
     u, v, r2  : Integer;
     i, j, w, L, LL : Single;
     InColor : TBZColor;
     
    begin
      r2 := Radius + Radius;
      if Horizontal then
      begin
        L := (c2PI / Texture.Height);
        LL := (CylinderLen / Texture.Width);
        for v := OffsetY to (OffsetY + CylinderLen) - 1 do
        begin
          //u := (y / LL) - OffsetX;
          for u := OffsetX to (OffsetX + R2) - 1 do
          begin
             //------------------------------------
             //---> vz := (j / LL) - OffsetX;
             //---> u := OffsetX + Floor(vz);
     
             //u := OffsetX + (J * LL)
             //u -(J * LL) := OffsetX
             //-(J * LL) := OffsetX - u;
             //-J := (OffsetX - u) / LL;
             //-J := u
             // J := -u
     
     
             //---------------------------------
     
             i :=  ((OffsetX - v) / LL);
     
             //---------------------------------
             //--> vx := (Radius * cos(i * L))
             //--> v := OffsetY + Radius + Floor(vx);
     
             // v-vx := OffsetY + Radius;
             // -vx := (OffsetY + Radius - v)
             // vx := -(OffsetY + Radius - y) = (Radius * cos(i * L)
     
             // cos(I * L) = vx / Radius; = (u / sqrt(sqr(u) + sqr(v))
             //(I * L) = ArcCos(vx / Radius)
             // I :=  ArcCos(vx / Radius) / L;
             //---------------------------------
     
             w := (OffsetY - Radius - u) ;
             //j := ArcCos((u / sqrt(sqr(u) + sqr(v)))) / L;
             //j := (ArcCos(w / Radius) / L) ;
             //j := sqrt(sqr(u) + sqr(v));
     
             j := sqrt(sqr((OffsetX - u)) + sqr(w)); // / L ;
     
     
             // AXE ZX  - vue de haut
             //i :=  ((OffsetX - u) / LL);
             //j := sqrt(sqr((OffsetX - u)) + sqr(w)) ;
     
     
             //j := BZMath.arcTan2(w,(OffsetX - u));
     
             InColor := OwnerBitmap.GetSamplePixel(i, j, psmBicubic, 3, peaWarp);
             ATexture.setPixel(u,v, InColor);
          end;
        end;
      end;
    end;

    Mes essais ne sont pas bons, il me manque surement quelques chose ou c'est mon cheminement qui est mauvais.
    J'ai laissé en commentaire entre les //------------- ma façon dont j'ai posé le problème.
    Et j'ai laissé mes autres essais pour (i,j) également en commentaire.

    Nom : 2020-08-22_193618.jpg
Affichages : 98
Taille : 20,8 Ko

    Dans la transformation inverse, j'aimerai bien sur également prendre en compte la rotation

    Merci d'avance pour votre aide

    Cordialement

    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  2. #2
    Membre expérimenté

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 410
    Points : 1 327
    Points
    1 327
    Par défaut
    Bonjour Jérôme,

    Je ne suis pas sûr de bien comprendre la transformation exacte que tu veux faire (un dessin serait utile je crois) mais certaines formes de ton premier code m'ont interpelé (notamment l'ordre des boucles i et j sauf si je n'ai raté quelque chose). J'ai aussi créé des variables secondaires pour limiter les calculs. De même, je pense que les artefacts proviennent des floors qui provoquent des trous au dessus des valeurs mais pas en dessous (pour faire bien il faudrait doser la contribution entre ix = floor(x) et ix+1 par exemple avec P(ix+1)*(x-ix) et P(ix)*(ix+1-x)).

    Ceci étant, je pense que tu as raison de vouloir inverser le processus pour maîtriser les artefacts notamment mais je ne comprends pas encore suffisant l'objectif pour y contribuer.

    Code Pas : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    procedure CylindricalMappingFrom(Texture: TBZBitmap; OffsetX, OffsetY, Radius, CylinderLen: Integer; 
       const Horizontal: Boolean; const Rotation: Single);
    var
       aColor : TBZColor;
       L, LL, c, s   : Single;
       vx, vy, vz    : Single;
       rx, ci, si, Li: Single;                       // Li = i*L, ci = cos(Li), si = sin(Li)
       i, j, u, v    : Integer;
     
       procedure RotZ(var x, y : Single);
       var
          x1 : Single;
       begin
          x1 := x * c - y * s;
          y  := x * s + y * c;
          x  := x1;
       end;
     
    begin
       SinCos(DegToRadian(Rotation), s, c);
       if Horizontal then begin
          L  := c2PI / Texture.Height;
          LL := CylinderLen / Texture.Width;
          rx := Radius;
       end
       else begin
          L  := c2PI / Texture.Width;
          LL := CylinderLen / Texture.Height;
          rx := -Radius;
       end;
       Li := 0;
       for i := 0 to Texture.MaxWidth do begin
          SinCos(Li, si, ci);
          vx := Rx     * ci;                         // R*cos(2PIx/H)
          vy := Radius * si;                         // R*sin(2PIx/W)
          RotZ(vx, vy);                           
          if vy > 0.0 then begin                     // on ne dessine que les pixels visibles
             vz := 0.0;
             for j := 0 to Texture.MaxHeight do begin
                aColor := Texture.getPixel(i, j);
                if Horizontal then begin
                   u := OffsetX + Floor(vz);
                   v := OffsetY + Radius + Floor(vx);
                end
                else begin
                   u := OffsetX + Radius + Floor(vx);
                   v := OffsetY + Floor(vz);
                end;
                OwnerBitmap.setPixel(u,     v,     aColor);
                // A priori Floor produit des trous seulement au dessus des valeurs
                OwnerBitmap.setPixel(u + 1, v,     aColor);
                OwnerBitmap.setPixel(u,     v + 1, aColor);
                OwnerBitmap.setPixel(u + 1, v + 1, aColor);
                vz += LL;
             end;
          end;
          Li += L;
       end;
    end;

    Salut.
    Philippe
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  3. #3
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Bonjour Philippe
    Citation Envoyé par Guesset Voir le message
    Bonjour Jérôme,

    Je ne suis pas sûr de bien comprendre la transformation exacte que tu veux faire (un dessin serait utile je crois) mais certaines formes de ton premier code m'ont interpelé (notamment l'ordre des boucles i et j sauf si je n'ai raté quelque chose). J
    Voila un petit dessin, en espérant que cela soit plus clair

    Nom : transcylinv.png
Affichages : 58
Taille : 35,1 Ko

    [EDIT] Le dessin n'est pas tout a fait juste car la texture doit est tourné à 90 dans le sens anti-horaire. Mais cela pourrai êtreune option supplémentaire à rajouter pour choisir l'orientation du placage[/EDIT]

    Ce que je veux c'est à partir des coordonnées de la surface d'affichage (X, Y) retrouver les bonnes coordonnées (u, v) dans la texture. La rotation peut être modifier juste en choisissant un décalage cyclique en X ou Y dans la texture pour donner l'impression que le cylindre tourne autour de son axe X ou Y suivant l'orientation.

    Heu, parce que je commence par J ? j'associe en fait la plupart du temps I à X et J à Y.

    Citation Envoyé par Guesset Voir le message
    J'ai aussi créé des variables secondaires pour limiter les calculs. De même, je pense que les artefacts proviennent des floors qui provoquent des trous au dessus des valeurs mais pas en dessous (pour faire bien il faudrait doser la contribution entre ix = floor(x) et ix+1 par exemple avec P(ix+1)*(x-ix) et P(ix)*(ix+1-x)).
    C'est une des raisons pourquoi je souhaite faire la transformation inverse. Je vais tester cette solution

    Citation Envoyé par Guesset Voir le message
    Ceci étant, je pense que tu as raison de vouloir inverser le processus pour maîtriser les artefacts notamment mais je ne comprends pas encore suffisant l'objectif pour y contribuer.

    Salut.
    Philippe
    En fait il faut que je passe des coordonnées (X,Y) de la surface d'affichage qui représentent en fait les coordonnées cylindrique vers les coordonnées (u,v) dans la texture. Comme je l'avais fait pour les coordonnées Polaire <--> Cartésienne

    Merci pour cette version optimisée

    A+

    Jerôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  4. #4
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Voici un petit GIF de ce que donne le rendu de la transformation normale, si ça peut aider à comprendre


    NB : Bizarre l'animation n'est pas jouée dans le forum, le fichier est automatiquement convertit en JPEG

    Bref :



    A+

    Jérôme

    [EDIT] Un truc que je viens de remarquer, c'est que la rotation n'est pas continue dans le sens horizontal, hum ???? [/EDIT]
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  5. #5
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Je viens de trouver ce document

    Mais je suis largué, je ne comprend pas le à quoi correspond "f" et ce que veut dire le "^" sur les variables.
    Comment déterminer les valeur Xcyl et Ycyl et ce "f"

    A+

    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  6. #6
    Membre expérimenté

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 410
    Points : 1 327
    Points
    1 327
    Par défaut
    Bonjour Jérôme,

    Si je comprends bien l'animation :
    • R est une anamorphose en X (aX) et la longueur en Y (aY) après rotation d'un quart de tour ( x, y -> -y, x).
    • La rotation est un décalage verticale Yr (ou horizontal Xr) qui s'ajoute au décalage initial Xo, Yo (j'ai mis les deux pour n'avoir qu'une seule formule)

    Donc, sauf erreur (et en omettant les modulos):
    • U(X,Y) = -aY*(Y-Yo-Yr) avec 0 < aY <= 1 selon l'animation
    • V(X,Y) = aX*(X-Xo-Yr) avec 0 < aX <= 1 selon l'animation

    Je pense que l'on peut simplifier ainsi (en intégrant Xo et Yo comme valeurs initiales de Xr et Yr):
    • U(X,Y) = -aY*(Y-Yr)
    • V(X,Y) = aX*(X-Yr)

    D'où la réciproque :
    • X = V/aX + Xr
    • Y = -U/aY + Yr

    Comme on le voit, il faut éviter les anamorphoses qui réduisent à rien l'une des dimensions. U et V deviennent nos variables de boucles. On doit limiter 1/aX à W-1 et 1/ay à H-1 (aX*W > 1 et aY > H) si on ne veut pas tourner trop vite (c'est l'équivalent de se limiter à 2PI, ça ne sert à rien d'y ajouter 2KPI). On peut remplacer 1/aX et 1/aY par des entiers dX et dY en gardant une bonne précision par exemple 216.

    Esquisse :

    Code Pas : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    delta := 1/aX;   // ax, ay et delta sont des doubles mais tous les autres sont des entiers
    if delta > W then dX := round((2 <<16) * (delta - floor(delta/W)*W) else dX := round((2 << 16) * delta);
    X16 := Xr << 16;
    ... // idem pour Y
    for V := 0 to Vmax do begin
       X := X16 >> 16: // la partie absorbée, X16 and $FFFF, peut être utilisé pour l'interpolation linéaire
       if X >= W then X -= W else if X < 0 then X += W;
       ... // autre boucle similaire en U et Y (attention signe) mais avec tracé effectif
       X16 += dX;
    end

    Un Bresenham serait plus efficace mais ici on bénéficie directement d'un dosage pour l'interpolation linéaire en alpha/216
    On peut réintroduire des degrés mais c'est juste pour le fun de l'utilisateur.

    En espérant avoir compris l'objectif.

    Salut
    Philippe
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  7. #7
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Re

    J'ai presque rien pigé. Comment tu définis W, aX et aY ?

    Je ne comprend pas le commentaire "ax, ay et delta sont des doubles mais tous les autres sont des entiers" aX = Longueur du cylindre et aY = Rayon * 2, non ?
    Ensuite if delta > W then et if X >= W then, je pige pas, car pour moi if delta > W then ne sera jamais vérifié dans ce cas si W est un entier, à moins que sa valeur soit de 0.

    Je n'ai pas besoin de faire une interpolation à ce moment. (j'ai une fonction "GetSamplePixel" qui se charge de ça, lorsque je récupère le pixel dans la texture. Et ou je peux choisir la méthode d'interpolation "Neighbour", Bilinéaire, cubique, "SubSample", Moyenne, médiane, etc...) UV sont et restent des flottants dans mon cas.

    J'ai l'impression que ta solution ne prend pas en compte la distorsion cylindrique en haut et bas (avec l'orientation horizontale) En plus tu prends U et V (la position dans la texture) pour les boucles, alors que c'est l'inverse que je cherche.

    Dans ce sens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    R2 := Radius + Radius
    for y := OffsetY to ((OffsetY + R2)-1) do
    begin
     
      for x :=OffsetX to ((OffsetX + CylinderLen)-1) do
      begin
         // De coordonnée cylindrique
        psi := y - OffsetY;
        phi := x - OffsetX;     
     
        // Sachant que si psi  = Rayon alors Z = 1.0 ; si psi  < Rayon alors Z = tend de 0.0 à 1.0 et si  psi  > Rayon alors Z = tend de 1.0 à 0.0
        z := ????  
     
        // vers coordonnée cartésienne
        u := ????
        v := ????
        PixelTexture := GetSamplePixel(u,v);
        PixelSurface.SetPixel(x,y, PixelTexture);
      end;
    end;
    A+
    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  8. #8
    Membre expérimenté

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 410
    Points : 1 327
    Points
    1 327
    Par défaut
    Rebonjour Jérôme,

    Pour moi u et v sont sur le cylindre tandis que x et y sont dans l'image source, ax et ay sont les facteurs (alphas pour memo) qui semblent correspondent à Rayon et Longueur dans ton animation. La rotation n'opère ne fait qu'un décalage en x et y (avec rebouclage en cas de dépassement d'où le terme certainement) c'est pourquoi je l'ai identifiée par Xr et Yr (pour n'avoir qu'une seule rotation, il suffit de mettre l'autre à 0).

    La comparaison avec delta est peut être fausse car j'ai présumé d'un transtypage implicite (sinon remplacer par floor(delta) dans l'expression). Si ax est dans ]0, 1] alors delta = 1/ax est dans [1, oo[ et peut allègrement être > W (W pour Width). Or le seul décalage qui se voit est la valeur modulo W.

    L'utilisation d'entiers (avec l'astuce érodée du décalage par une puissance de 2) permet de n'avoir des floats que lors des phases d'initialisation. Les résidus de type X16 and $FFFF donnent directement (sans division les coefficients d'interpolation linéaire :
    • Pixel(V) := Pixel(X16 >> 16) + (Pixel(X16 >> 16 + 1) - Pixel(X16 >> 16))*(X16 and $FFFF)
    • Bien sûr il faut travailler en fait par composante (ou avec les SIMD où , comme par hasard, existe une multiplication qui ne garde que les 16 bits de poids fort c'est à dire fait la * et le décalage en même temps)

    Je me suis fait une idée peut être fausse sur la base de l'animation qui ne fait apparaitre ni sin ni cos.

    Il en serait autrement dans le cas d'une projection où la valeur de destination est, par exemple pour un cylindre vertical :
    • Ydst = Yequateur + round(coef*arctan((Ysrc-Ysrc_max/2)/R).
    • Le coef définit le facteur de taille cible (combinaison entre rayon et densité de points).
    • Ysrc_max/2 correspond à l'équateur dans l'image source.

    La fonction inverse sera un truc du genre :
    • Ysrc = Ysrc_max/2 + tan((Ydst - Yequateur)/coef)

    Je crois qu'un petit dessin ne serait pas de trop : je t'envoie ça dès que possible.

    Salut
    Philippe
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  9. #9
    Membre expérimenté

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 410
    Points : 1 327
    Points
    1 327
    Par défaut Illustration
    Un petit dessin :

    Nom : Projection cylindrique.png
Affichages : 49
Taille : 68,8 Ko

    Bonne soirée.
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  10. #10
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Bonjour Philippe,

    Citation Envoyé par Guesset Voir le message
    Rebonjour Jérôme,

    L'utilisation d'entiers (avec l'astuce érodée du décalage par une puissance de 2) permet de n'avoir des floats que lors des phases d'initialisation. Les résidus de type X16 and $FFFF donnent directement (sans division les coefficients d'interpolation linéaire :
    • Pixel(V) := Pixel(X16 >> 16) + (Pixel(X16 >> 16 + 1) - Pixel(X16 >> 16))*(X16 and $FFFF)
    • Bien sûr il faut travailler en fait par composante (ou avec les SIMD où , comme par hasard, existe une multiplication qui ne garde que les 16 bits de poids fort c'est à dire fait la * et le décalage en même temps)
    Ca c'est la partie que j'avais compris. Pour Les SIMD je ne maîtrise pas du tout avec les entiers. Je me pencherai dessus un de ces quatre.

    Citation Envoyé par Guesset Voir le message
    Il en serait autrement dans le cas d'une projection où la valeur de destination est, par exemple pour un cylindre vertical :
    • Ydst = Yequateur + round(coef*arctan((Ysrc-Ysrc_max/2)/R).
    • Le coef définit le facteur de taille cible (combinaison entre rayon et densité de points).
    • Ysrc_max/2 correspond à l'équateur dans l'image source.

    La fonction inverse sera un truc du genre :
    • Ysrc = Ysrc_max/2 + tan((Ydst - Yequateur)/coef)

    Je crois qu'un petit dessin ne serait pas de trop : je t'envoie ça dès que possible.
    Merci pour le dessin, j'arrive à visualiser, mais je n'arrive à rien, j'ai essayé d'implémenter ta formule

    • Ysrc = Ysrc_max/2 + tan((Ydst - Yequateur)/coef)


    Mais impossible de trouver la bonne valeur de Coef. J'ai essayé dans tous les sens, je suis dans les choux.

    Ici c'est une projection orthogonale d'un cylindre., je vais chercher de ce coté.

    Si non j'avais penser à déduire l'angle du "cercle" vu que l'on connait le Rayon et la position Y. Retrouver le X n'est pas compliquer. Avec un ratio Angle/YSrc_Max on pourrait déduire le YSrc
    sachant que angle variera de 0 à 180°. 0° = YSrc0, 90° = Yequateur = YSrcMax/2 et 180° = YSrcMax.

    Cordialement Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  11. #11
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    Je pense être sur la bonne voie. Pour plus simplicité, j'ai effectué les calculs sur un cylindre vertical

    Pour chaque ligne
    Calculer la distance pour chaque pixel par rapport l'axe vertical (le centre) c'est à dire le rayon
    Calculer l'angle correspondant, et utiliser cet angle pour déterminer une distance par rapport à l'axe vertical dans le bitmap source

    Voici mon code

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    procedure CylindricalMappingInv(Texture: TBZBitmap; OffsetX, OffsetY, Radius, CylLen: Integer);
    Var
      x, y, R2 : Integer;
      u, v, t, s : Single;
      DeltaX, DeltaY : Single;
      InColor : TBZColor;
    begin
     
      R2 := Radius + Radius;
      DeltaX := (c2PI / (Texture.Width));
      DeltaY := (Texture.Height / CylLen);
      v := 0;
      for y := 0 to (CylLen - 1) do
      begin
        for x := 0 to R2 do
        begin
          if (x < Radius) then t := x / Radius
          else t := (R2 -  X) / Radius;;
     
          s := 1.0 / (t * arcSin(t)) * DeltaX; // * c2PI;
          t := t * s;
          u := (t * Radius + Radius);
     
          InColor := Texture.GetSamplePixel(u, v, psmBilinear, 3, peaWarp);
          FDisplayBuffer.SetPixel(OffsetX + x, OffsetY + y, InColor);
        end;
        v := v + DeltaY;
      end;
    end;

    Voici le résultat



    Maintenant il faut que je trouve comment inverser correctement mes coordonnées U et V pour enlever cet effet de symétrie. Ou un meilleur moyen de calculer et d'ajuster les distances car
    ici c'est beaucoup trop étirer lorsque l'on se rapproche du centre. Une histoire de coefficient avec PI et mon DeltaX ? Prendre autre chose que ArcSin ?

    Par la suite La rotation autour de l'axe des y sera au final juste un décalage de la coordonnée U. Et il sera facile de déduire le rendu pour un cylindre horizontal.

    Merci d'avance de votre aide

    Cordialement

    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  12. #12
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Rebonjour

    Je n'abandonnerai pas ! , je persévère. Je suis au final repartie sur une page vierge et réfléchis un peu (ça m'arrive, de temps en temps )

    La solution est plus simple qu'il n'y parait mais ce n'est pas encore ça.

    Je m'explique, j'ai d'abord transformé mes coordonnées 2D (x,y) en Coordonnées 3D (x,y,z) afin de déduire les coordonnées du cylindre. J'ai ensuite appliqué la transformation inverse pour trouver les coordonnées de ma texture (U,V). Pas de soucis et le résultat est pas mal.

    Voici le code :

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    procedure TMainForm.CylindricalMappingInv(Texture: TBZBitmap; OffsetX, OffsetY, Radius, CylLen: Integer; Const Rotation: Single; Const IsHorizontal: Boolean);
    Var
      p, pc, pn  : TBZVector;
      x, y, R2 : Integer;
      u, v, z, s : Single;
      InColor : TBZColor;
    begin
      // pc.CreatePoint(Radius, CylLen * 0.5, 0);
      R2 := Radius + Radius;
      for y := 0 to (CylLen - 1) do
      begin
        for x := 0 to R2 do
        begin
     
          if x < Radius then z := x  else z := Radius - (x - Radius);
     
          // Comment utiliser "S" = ratio distance, correctement pour diminuer U vers les bords horizontaux
          s := ((z - Radius) / Radius); 
     
          p.CreatePoint(x - Radius,y,z);
          //p := p - pc;
          //p := p.Normalize;
     
          // Axe X
          //u := ArcTan2(Pn.Z,-Pn.Y);
          //v := (P.X / R2);
     
          // Axe Y
          u := ArcTan2(-p.x, p.z) ;
          v := p.y / CylLen;
     
          // Axe Z
          //u := ArcTan2(-Pn.X,-Pn.Y);
          //v := (P.Z / R2);
     
          u := 1.0 - ((u / c2PI) + 0.5);
     
          if (Rotation <> 0) then u := u + (1.0 / (360 / Rotation));
     
          if (u < 0.0) or (u > 1.0) then u := u - floor(u);
     
          InColor := Texture.GetSamplePixel(u * Texture.Width, v * Texture.Height, psmBilinear, 3, peaWarp);
          FDisplayBuffer.SetPixel(OffsetX + x, OffsetY + y, InColor);
        end;
      end;
    end;

    Et le résultat en image :



    Ma question, maintenant. Dans le code j'ai S := ((z - Radius) / Radius);. Mais comment utiliser ce "S" = ratio distance, correctement pour diminuer U vers les bords horizontaux. Afin de donner un effet de profondeur ?

    Cordialement

    Jérôme

    A+
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  13. #13
    Membre expérimenté

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    410
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 410
    Points : 1 327
    Points
    1 327
    Par défaut
    Bonjour Jérôme,

    S fait un ^ avec -1, 0, -1 avec 0 qui ne doit pas altérer u et -1 qui doit l'augmenter tout en restant dans 0..1.

    Une solution possible (à vérifier) : u := max(0, min((U-0.5)*(1-S) + 0.5, 1). Cela x2 l'élongation des bords (sauf en butée, un modulo sur la largeur de la source serait peut être préférable). En remplaçant S par 2-z/Radius, 1 - S devient S;

    Mais c'est un trompe l’œil, pas une vrai projection, et cela reste coûteux en temps de calcul.

    Bonne continuation.

    PS Ton message 11 semblait proche de la solution même si l'élongation est centrale au lieu d'être sur les bords cela devrait être assez facile à corriger.
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  14. #14
    Expert confirmé
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    septembre 2015
    Messages
    1 763
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : septembre 2015
    Messages : 1 763
    Points : 4 067
    Points
    4 067
    Billets dans le blog
    2
    Par défaut
    Bonjour Philippe,

    Citation Envoyé par Guesset Voir le message
    Bonjour Jérôme,

    S fait un ^ avec -1, 0, -1 avec 0 qui ne doit pas altérer u et -1 qui doit l'augmenter tout en restant dans 0..1.

    Une solution possible (à vérifier) : u := max(0, min((U-0.5)*(1-S) + 0.5, 1). Cela x2 l'élongation des bords (sauf en butée, un modulo sur la largeur de la source serait peut être préférable). En remplaçant S par 2-z/Radius, 1 - S devient S;

    Mais c'est un trompe l’œil, pas une vrai projection, et cela reste coûteux en temps de calcul.

    Bonne continuation.
    Oui c'est vrai c'est un trompe l'oeil, car avec cette formul c'est comme si on déroulai le cylindre à plat. Je me sert d'ailleurs de celle-ci pour trouver les uv de mes objets 3D lorsque je leur applique un mapping de texture cylindrique.

    Ta solution marche pas trop mal

    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
          s := 1.0 - ((z - Radius) / Radius);
          p.CreatePoint(x - Radius,y,z);
          u := ArcTan2(-p.x, p.z) ;
          v := p.y;
          u := 1.0 - ((u / c2PI) + 0.5);
          u := (u - 0.5) * s + 0.5;
          if (Rotation <> 0) then u := u + (1.0/ (360 / Rotation));
          if (u < 0.0) or (u > 1.0) then u := u - floor(u);

    Les seuls bémols ce sont les perfs qui chutent grave et la qualité qui va dépendre du ration Rayon/Largeur de la texture



    Citation Envoyé par Guesset Voir le message
    PS Ton message 11 semblait proche de la solution même si l'élongation est centrale au lieu d'être sur les bords cela devrait être assez facile à corriger.
    Je vais regarder et m'inspirer de ta solution que tu viens de me donner, et c'est vrai cela serait plus juste.

    Sinon, il faudrait découper la texture en bandes verticales et les faire coïncider à la courbure haut et bas du cylindre. Cela permettrai même un rendu pseudo 3D dans tous les axes, ci je ne me trompe pas

    Merci

    A+

    Jérôme
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  15. #15
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    décembre 2010
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2010
    Messages : 1 176
    Points : 2 280
    Points
    2 280
    Billets dans le blog
    9
    Par défaut Placage de texture en 2D : transformation inverse
    Bonjour,

    Tu cherches si j'ai bien compris à plaquer une image rectangulaire de contour (ABCD) sur un cylindre dont l'axe est parallèle à l'un des côtés, et à donner de cette construction spatiale une seconde image rectangulaire de contour (EFGH), de sorte qu'à tout point (M) de la partie visible de l'image initiale, de coordonnées locales (x1, y1), corresponde un autre point (M') de la seconde, de coordonnées locales (x2, y2).

    Nom : 2 images.png
Affichages : 82
Taille : 45,0 Ko

    Une telle transformation, une fois correctement ajustée, conduit naturellement à définir les coordonnées de (M') en fonction de celles de (M), donc à faire apparaître des résultats de la forme:
    (x2, y2) = F(x1, y1) ;
    cependant toute modification du contenu pictural d'une image exige d'exprimer les anciennes coordonnées en fonction des nouvelles, donc de parvenir à des relations du type:
    (x1, y1) = F-1(x2, y2) ,
    réciproques des précédentes.
    On n'a donc généralement pas le choix sur la procédure à suivre, sauf cas très particuliers.

    Autre remarque d'ordre général: le cylindre est comme le cône une surface développable, ce qui permet d'y inscrire des figures initialement planes sans modification des distances géodésiques; ce n'est pas le cas de la sphère, sur laquelle il faudra définir directement la texture envisagée.

    Voir aussi ce lien.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  16. #16
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    décembre 2010
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2010
    Messages : 1 176
    Points : 2 280
    Points
    2 280
    Billets dans le blog
    9
    Par défaut Placage de texture en 2D : transformation inverse
    Supposons les secondes directions (y'1y1, y'2y2) des deux images parallèles entre elles ainsi qu'à l'axe du cylindre, lequel se confond avec l'axe (w'w) d'un repère orthonormé (Ouvw).
    Nom : Placage.png
Affichages : 46
Taille : 8,9 Ko
    Les ordonnées des points conjugués (M, M') sont alors confondues: y1 = y2 ,
    ce qui restreint le problème à l'expression de (x1) en fonction de (x2).

    Le placage de l'image initiale sur le cylindre amène la superposition des coins extrêmes (A, B), de sorte que sa largeur correspond au périmètre de la section circulaire du cylindre; le rayon de celui-ci vérifie par conséquent:
    L = 2π.Rcyl .

    Il intervient par ailleurs deux relations impliquant l'angle (φ) apparaissant sur le schéma:
    a) La longueur de l'arc (AM) correspond à l'abscisse (x1) du point (M) définie par rapport au coin inférieur gauche (A) du rectangle initial; il vient donc:
    x1 = Rcyl(φ - φ0) , soit encore: φ - φ0 = 2π(x1/L) ;
    l'angle (φ0) définit la position des coins extrêmes (A, B) - début et fin de l'image initiale dans un plan horizontal, ici (uOv); on a en effet:
    # pour (A): x1 = 0 , d'où φ = φ0 ,
    # pour (B): x1 = L , d'où φ = φ0 + 2π ;
    b) Le point (I), placé à l'intersection de l'axe (Ou) avec la base horizontale (EF) de la seconde image, se situe au milieu de cette dernière, ce qui se traduit par la relation:
    x2 - L/2 = Rcyl.Sin(φ)
    si l'on attribue la même largeur totale aux deux images;
    du bornage naturel de la fonction sinus découle un encadrement de la seconde abscisse; on a en effet:
    # Sin(φ) >= -1 , d'où: x2 >= Rcyl(π - 1) = xmin ,
    # Sin(φ) <= +1 , d'où: x2 <= Rcyl(π + 1) = xmax .

    On obtient dans ces conditions, et en se limitant au demi-cercle visible
    donc ici situé à droite (-π/2 <= φ <= +π/2):
    φ = ArcSin((x2 - L/2)/Rcyl) = ArcSin(x2/Rcyl - π) ;
    il suffit alors de reprendre la première relation: x1 = Rcyl(φ - φ0)
    pour obtenir la coordonnée initiale.

    Calculs à vérifier, évidemment.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  17. #17
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    décembre 2010
    Messages
    1 176
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : décembre 2010
    Messages : 1 176
    Points : 2 280
    Points
    2 280
    Billets dans le blog
    9
    Par défaut Placage de texture en 2D : transformation inverse
    Deux options sont envisageables pour l'algorithme assurant le passage de la matrice du corps de la seconde image (Matrice_2) à celle de la première (Matrice_1)

    a) Une version courte procédant à la détermination directe de (x1) par arrondi; le résultat apparaît cependant décevant sur les bords de l'image, où la couleur locale peut varier rapidement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     PROCEDURE Calc_Mat_Im2(La, Ha: Z_32; VAR Ma1, Ma2: Tab_Pix);
       CONST DegRad = Pi / 180; Phi0 = DegRad * 180; D_Pi = 2 * Pi;
             Rmin = Pi - 1;     Rmax = Pi + 1;
             Pzero: Pixel = (0, 0, 0);
       VAR X1, X2, Ym:Z_32; Phi, Psi, r, Rcyl: Reel; Test: Bool; Px: Pixel;
       BEGIN
         Rcyl:= La / D_Pi;
         FOR Ym:= 0 TO (Ha - 1) DO
           FOR X2:= 0 TO (La - 1) DO
             BEGIN
               r:= X2 / Rcyl; Test:= ((r<Rmin) OR (r>Rmax));
               IF Test THEN Px:= Pzero
                       ELSE BEGIN
                              Phi:= ArcSin(r - Pi); Psi:= Phi - Phi0;
                              X1:= Round(Rcyl * Psi);
                              WHILE (X1<  0) DO Inc(X1, La);
                              WHILE (X1>=La) DO Dec(X1, La);
                              Px:= Ma1[X1, Ym]
                            END;
               Ma2[X2, Ym]:= Px
             END
       END;
    b) Une version moins courte effectuant une interpolation sur les carrés des indices de couleur; on prendra garde aux facéties de la fonction (Trunc(x)) pour les valeurs négatives de l'argument (je m'y suis laissé prendre ):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
     FUNCTION CombLinAxBy(Ca, Cb: Reel; Ix, Iy: Byte): Byte;
       VAR u, v, w: Reel;
       BEGIN
         u:= Ca * Ix; v:= u * Ix; // v:= Ca * Ix^2
         u:= Cb * Iy; w:= u * Iy; // w:= Cb * Iy^2
         Result:= Round(Sqrt(v + w))
       END;
    
     FUNCTION Couleur(v: Reel; PxA, PxB: Pixel): Pixel;
       VAR k: Byte; w: Reel; Px: Pixel;
       BEGIN
         w:= 1 - v;
         FOR k:= 1 TO 3 DO Px[k]:= CombLinAxBy(w, v, PxA[k], PxB[k]);
         Result:= Px
       END;
    
     PROCEDURE Corr_Mod(VAR i: Z_32; La: Z_32);
       VAR j: Z_32;
       BEGIN
         j:= i;                       WHILE (j<0) DO Inc(j, La);
         WHILE (j>=La) DO Dec(j, La); i:= j
       END;
    
     PROCEDURE Calc_Mat_Im2_A(La, Ha: Z_32; VAR Ma1, Ma2: Tab_Pix);
       CONST DegRad = Pi / 180; Phi0 = DegRad * 105; D_Pi = 2 * Pi;
             Rmin = Pi - 1;     Rmax = Pi + 1;
             Pzero: Pixel = (0, 0, 0);
       VAR X1a, X1b, X2, Ym:Z_32; Delta, Phi, Psi, r, Rcyl, s: Reel;
           Test: Bool; Px: Pixel;
       BEGIN
         Rcyl:= La / D_Pi;
         FOR Ym:= 0 TO (Ha - 1) DO
           FOR X2:= 0 TO (La - 1) DO
             BEGIN
               r:= X2 / Rcyl; Test:= ((r<Rmin) OR (r>Rmax));
               IF Test THEN Px:= Pzero
                       ELSE BEGIN
                              Phi:= ArcSin(r - Pi);
                              Psi:= Phi - Phi0; s:= Rcyl * Psi;
                              IF (s>0) THEN BEGIN
                                              X1a:= Trunc(s); X1b:= X1a + 1
                                            END
                                       ELSE BEGIN
                                              X1b:= Trunc(s); X1a:= X1b - 1
                                            END;
                              Delta:= s - X1a;
                              Corr_Mod(X1a, Larg_Image);
                              Corr_Mod(X1b, Larg_Image);
                              Px:= Couleur(Delta, Matrice_1[X1a, Ym],
                                           Matrice_1[X1b, Ym])
                            END;
               Ma2[X2, Ym]:= Px
             END
       END;
    La rotation s'observe pour des valeurs successives du paramètre (φ0); voici ce que l'on obtient pour
    φ0 = 0, 15, 30, 45, 60, 75, 90, 105 ° ,
    par la seconde version:
    Nom : F0=00_15_30_45°_670x483.png
Affichages : 41
Taille : 46,9 Ko
    Nom : F0=60_75_90_105_670x483.png
Affichages : 43
Taille : 64,2 Ko


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

Discussions similaires

  1. placage de textures
    Par xelif dans le forum Moteurs 3D
    Réponses: 2
    Dernier message: 17/04/2008, 22h17
  2. Analyse de texture avec la transformée en ondelettes
    Par ant6ares dans le forum Scilab
    Réponses: 1
    Dernier message: 22/01/2008, 12h50
  3. Réponses: 5
    Dernier message: 18/12/2006, 17h02
  4. Placage de texture
    Par Teapot dans le forum OpenGL
    Réponses: 22
    Dernier message: 10/09/2006, 13h41
  5. prob de placage de texture en 2d
    Par lordheavy dans le forum OpenGL
    Réponses: 3
    Dernier message: 15/08/2006, 23h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo