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

 Delphi Discussion :

Manipulation laborieuse des pixels d'un bitmap vs les pixels de la form


Sujet :

Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut Manipulation laborieuse des pixels d'un bitmap vs les pixels de la form
    Bonjour,

    Ça fait bien longtemps que je n'étais pas venu poster une question ici, plutôt habitué ces derniers temps au bistrot forum Lazarus , mais là, je retourne aux origines.
    Contexte : D7perso tournant sur w2K sp4 (virtualisé dans une machine Linux mais ça, on s'en fiche).

    Le problème : la compréhension de l'écriture des pixels d'un bitmap vs la même écriture dans le canvas d'une form.

    Je suis parti du sympathique article dont Paul TOTH m'a récemment fourni le lien, j'ai vu la jolie image en bas de la page, et je me suis employé à refaire la même chose jusqu'à arriver au même résultat, ce qui ne fut pas trop compliqué grâce au copier/coller.
    Ensuite, j'ai voulu refaire la même chose dans un TImage, en passant par un TBitmap intermédiaire, et c'est là que ça se complique.

    Comme j'avais des soucis, pour essayer de les cerner j'ai commencé par changer la couleur mais une couleur uniforme dans un carré, pour voir les défauts, laisse tomber !, alors j'ai changé la taille du canvas et du carré je suis passé au rectangle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const
      IMAGE_WIDTH  = 256;
      IMAGE_HEIGHT = 128;//256;
    et là, tout de suite, j'ai relevé que la note de Paul, sur sa page, en date du 29/05/2013, semble erronée ! Ben oui, Paul, regarde les images (note : les images présentées dans ce post sont toutes réduites de moitié) :
    Nom : rouge_yx_xy.jpg
Affichages : 471
Taille : 6,5 Ko à gauche le mode yx conseillé , à droite le mode xy d'origine

    En plus, en utilisant le mode d'origine (Pixels[x, y]), j'affiche bien l'image présentée en bas de la page web.
    Car oui, en mettant [y, x], je ne retrouvais pas l'image et je me suis dit que Paul n'avait pas fait de nouvelle capture malgré la modif du 29/05.
    Nom : paul_xy_yx.jpg
Affichages : 533
Taille : 19,2 Ko à gauche le mode xy d'origine , à droite le mode yx conseillé

    Et ça n'est jamais bon de faire des suppositions sur ce qu'ont fait (ou pu faire) les autres : en informatique, àmha, il faut des certitudes, sinon on avance en plein brouillard...
    Paul, message perso, il serait bon que tu clarifies ce point.


    Ceci étant dit, le problème que je rencontre est résumé ainsi : écrire des pixels colorés sur le canvas de la form est simple et très joli, voir ci-dessus ; écrire ces mêmes pixels sur le canvas d'un TBitmap est (devrait être ?) aussi simple mais affiche des abominations :
    Nom : bads.jpg
Affichages : 453
Taille : 8,7 Ko

    J'ai tout essayé de ce que je connais : inverser x et y, inverser le sens de balayage (de for variable = 0 to valeur-1 do à for variable = valeur-1 downto 0 do), commencer le balayage d'abord avec la width ou d'abord avec la height, pf24bit ou pf32bit, plusieurs méthodes de recopie dans l'image d'affichage, dans tous les cas c'est la cata !
    D'où ce post, dans l'espoir d'idées lumineuses...

    Ah, le code (pour tester, une TImage à la taille des constantes données plus haut) sur une form et zou !) :
    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
    procedure TForm1.FormCreate(Sender: TObject);
    var
      x, y: Integer;
      SrcBmp: TBitmap;
    begin
      DoubleBuffered := True; // rajouté par moi
    {  // 3 lignes direct du site sans changer une virgule
      for x := 0 to IMAGE_WIDTH - 1 do
        for y := 0 to IMAGE_HEIGHT - 1 do
          pixels[y, x] := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16);
    }
      SrcBmp := TBitmap.Create;
      with SrcBmp do begin
        SrcBmp.PixelFormat:=pf32bit;
        //SrcBmp.PixelFormat:=pf24bit;
        SrcBmp.Width := IMAGE_WIDTH;
        SrcBmp.Height := IMAGE_HEIGHT;
      end;
      with SrcBmp.Canvas do
        for x := 0 to IMAGE_WIDTH-1 do
    //    for x := IMAGE_WIDTH-1 downto 0 do
    //      for y := IMAGE_HEIGHT-1 downto 0 do
          for y := 0 to IMAGE_HEIGHT-1 do
    //        Pixels[x, y] := clRed; // ça c'est bon ! Ah mais quand même...
    //        Pixels[x, y] := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16);
            Pixels[x, y] := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16) or $FF000000;
    
    // essais d'affichage, tous identiques
    //  image1.Canvas.Draw(0, 0, SrcBmp);
    //  image1.Picture.Assign(SrcBmp);
      image1.Picture.Graphic := SrcBmp;
    end;
    Je ne mets pas celui du FormPaint, c'est celui de Paul, juste que je lui rajoute un Exit; au début, quand j'active le couple bitmap et image.
    Ce FormPaint inclut en bas qq lignes pour écrire sur la form, chose qui ne m'intéresse pas pour l'instant.

    Quelqu'un va pouvoir m'expliquer pourquoi je ne peux pas manipuler simplement les pixels d'un bitmap ?

    Mille mercis par avance...

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Parce qu'il faut clamper tes valeurs (*), ou faire des modulo (**) (<- en gros si c'est supérieur à 255 il faut revenir à 0)

    * ->
    Si Color < 0 -> Color = 0
    Si Color > 255 -> Color = 255


    ** ->
    Color = (Color % 256)

  3. #3
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Citation Envoyé par foetus Voir le message
    Parce qu'il faut clamper tes valeurs (*),

    * ->
    Si Color < 0 -> Color = 0
    Si Color > 255 -> Color = 255
    Euh, comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    //      pixels[y, x] := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16);
        begin
          aColor := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16);
          if aColor < 0 then aColor := 0;
          if aColor > 255 then aColor := 255;
          pixels[y, x] := aColor;
        end;
    Parce que ça donne ça, et je ne trouve pas ça terrible-terrible...
    à gauche avant la modif, au centre ton idée, et à droite ton idée en utilisant le bitmap :

    Nom : foetus_info.jpg
Affichages : 533
Taille : 55,8 Ko


    Ah, travailler avec Pixels[x, y] quand l'objet est rectangulaire me génère un Access Violation ! , et je ne sais pas encore pourquoi (je viens de le découvrir maintenant).

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Euh, comme ça ?
    Mais non voyons

    Reprenons: Il y a plusieurs formats de couleurs (RGB, RGBA, HSV, ...) mais en Delphi c'est du BGR.

    Une couleurs BGR est codée sur 4 octets, et l'octet le plus à gauche c'est 0, le 2ième c'est le bleu, le 3ième le vert (Green) et le 4ième (le plus à droite) le rouge.

    Et les valeurs vont de 0 à 255 pour chaque composante.

    Il faut faire ceci:
    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
     
           blue, red, green: Integer;
        begin
          blue := (x + x);
          green := (x - y);
          red := (x + y);
     
          if blue < 0 then blue := 0;
          if blue > 255 then blue := 255;
     
          if green < 0 then green := 0;
          if green > 255 then green := 255;
     
          if red < 0 then red := 0;
          if red > 255 then red := 255;
     
          aColor := 0x00000000;
          aColor := red or (green shl 8) or (blue shl 16);
     
          pixels[y, x] := aColor;
        end;
    Mais ton calcul c'est de la m^rd^ parce que (x + y) ou (x + y) dépassera souvent 255 et tu auras du noir
    D'où le modulo qui permet de "faire un tour"


    Citation Envoyé par Jipété Voir le message
    je ne sais pas encore pourquoi (je viens de le découvrir maintenant).
    Il ne faut pas taper hors buffer

  5. #5
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 934
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 934
    Par défaut
    Citation Envoyé par Jipété Voir le message
    j'ai relevé que la note de Paul, sur sa page, en date du 29/05/2013, semble erronée
    Cela concerne le tableau de couleurs utilisé pas SetDIBitsToDevice et non la propriété Pixels du canvas. Peut-être aurait-il fallu l'appeler autrement pour éviter la confusion
    La seule chose qui me semble être incorrect est le remplissage de ce tableau qui devrait être de IMAGE_HEIGHT -1 downto 0 puisque le premier pixel est en bas à gauche.

  6. #6
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Cela concerne le tableau de couleurs utilisé pas SetDIBitsToDevice et non la propriété Pixels du canvas. Peut-être aurait-il fallu l'appeler autrement pour éviter la confusion
    x 1000 !

    Citation Envoyé par Andnotor Voir le message
    La seule chose qui me semble être incorrect est le remplissage de ce tableau qui devrait être de IMAGE_HEIGHT -1 downto 0 puisque le premier pixel est en bas à gauche.
    Comme ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        for x := 0 to IMAGE_WIDTH-1 do
          for y := IMAGE_HEIGHT-1 downto 0 do
            Pixels[x, y] := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16);
    ça donne l'image de gauche, déjà présentée :
    Nom : bads.jpg
Affichages : 468
Taille : 8,7 Ko

  7. #7
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 934
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 934
    Par défaut
    En fait le remplissage du tableau est correct puisqu'il est inversé ensuite à l'utilisation par -IMAGE_HEIGHT (je parle toujours de SetDIBitsToDevice).

  8. #8
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    Alors, déjà mon article a pour but de montrer qu'un tableau de TColor est plus simple à manipuler que des ScanLines...et c'est surtout beaucoup plus rapide que la propriété Pixels[] de TBitmap ! Ce dernier présent un seul avantage, c'est que tu n'as pas à te préoccuper du PixelFormat, tu donnes une couleur RGB et le bitmap se débrouille avec. En ScanLine tu dois tenir compte du format pour savoir comment définir un pixel, avec mon tableau (tel qu'il est déclaré) c'est forcément du 32Bits.

    ensuite le xy/yx c'est en effet pour mon tableau puisque tableau[a, b] c'est tableau[a * width + b], on a donc bien tableau[y, x]

    comme indiqué dans l'article "SetDIBitsToDevice(Bmp.Canvas.Handle,..." permet de dessiner dans un TBitmap sans problème.

    finalement pour éviter les problèmes de "clamp" tu peux utiliser TBitmap.Pixels[x, y] : =RGB(r, g, b);" les paramètres étant des Byte tu ne dépasseras pas 255, mais du coup 256 donnera 0, c'est comme si tu faisais un modulo 256 sur chaque valeur...ou comme le propose foetus tu bornes la valeur entre 0 et 255.

    Je ne reviens pas sur la notion de canal alpha déjà évoquée sur le forum Lazarus
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  9. #9
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Merci à vous trois pour vos pistes, vos tentatives, vos renseignements, etc.

    Avec tout ça, j'en suis là : à gauche l'écriture sur le canvas de la form, à droite dans le TImage chargé par le TBitmap de travail...

    Nom : nouvelessai.jpg
Affichages : 480
Taille : 12,1 Ko

    J'ai trituré l'image de droite dans tous les sens, pas moyen d'arriver à trouver le même positionnement de couleurs que sur l'image de gauche.
    C'est pour moi le plus perturbant.

    Pas mal, ton idée, foetus, mais du coup on perd toute la géométrie du dessin de Paul, et le rendu des couleurs, même si on reste dans les mêmes tons. Je ne pense pas que ça soit la bonne solution.

    Bien tenté, Andnotor, mais j'ai essayé les 4 combinaisons possibles et c'est toujours pareil, la couleur blanche toujours opposée au rouge, se colle en haut à droite (à condition d'inverser xy par rapport au dessin sur canvas : si pas d'inversion elle se colle en bas à gauche et terminé !) et n'en démord pas !
    Oui, on va dire que je prends l'écriture sur le canvas de la form (avec le texte) comme référence, et j'aimerais bien avoir, un jour..., un bitmap représentant le même dessin (sans le texte). Mission impossible ?
    Ou c'est lié au fait qu'on mélange les x et les y des déplacements avec le paramétrage des couleurs ?

    En tout état de cause, ayant créé une procédure commune aux deux affichages de ces couleurs, je m'attendais à retrouver les mêmes couleurs, éventuellement pas aux mêmes endroits. Mais là ça fait beaucoup de changements pour une procédure identique...
    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
    begin
      DoubleBuffered := True;
    {$IFDEF FORMCANVAS}
      for x := 0 to IMAGE_WIDTH - 1 do
        for y := 0 to IMAGE_HEIGHT - 1 do
    {$ELSE}
      SrcBmp := TBitmap.Create;
      with SrcBmp do begin
        SrcBmp.PixelFormat:=pf32bit;
        //SrcBmp.PixelFormat:=pf24bit;
        SrcBmp.Width := IMAGE_WIDTH;
        SrcBmp.Height := IMAGE_HEIGHT;
      end;
      with SrcBmp.Canvas do
    //    for x := 0 to IMAGE_WIDTH-1 do // blanc en haut à droite
        for x := IMAGE_WIDTH-1 downto 0 do // blanc en haut à droite
    //      for y := IMAGE_HEIGHT-1 downto 0 do  // blanc en haut à droite
          for y := 0 to IMAGE_HEIGHT-1 do    // blanc en haut à droite
    {$ENDIF}
     
    // les couleurs, communes aux deux cibles :
        begin
          blue := (x + x); green := (x - y); red := (x + y);
          if blue < 0 then blue := 0; if blue > 255 then blue := 255;
          if green < 0 then green := 0; if green > 255 then green := 255;
          if red < 0 then red := 0; if red > 255 then red := 255;
    {$IFDEF FORMCANVAS}
          Pixels[y, x] := red or (green shl 8) or (blue shl 16);
    {$ELSE}
    //      Pixels[x, y] := red or (green shl 8) or (blue shl 16);
          Pixels[y, x] := red or (green shl 8) or (blue shl 16);
    {$ENDIF}
        end;
     
    {$IFNDEF FORMCANVAS}
      image1.Visible := True;
      image1.Canvas.Draw(0, 0, SrcBmp);
    //  image1.Picture.Assign(SrcBmp);
    //  image1.Picture.Graphic := SrcBmp;
    {$ENDIF}
     
    end;
    Pas plus pour le moment.

  10. #10
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    il faut réfléchir un peu ... et sortir les maths

    En haut à gauche, c'est du noir RGB(0, 0, 0)
    En bas à gauche, c'est du bleu RGB(0, 0, 255)
    En haut à droite, c'est blanc RGB(255, 255, 255)
    En bas à droite, c'est du rose RGB(255, 0, 255)

    Donc:
    • Le rouge est incrémenté de gauche à droite de 0 à 255, quelle que soit la ligne
    • Le vert est incrémenté en cercle centré sur le coin supérieur droit (plus on se rapproche et plus on tend vers 255)
    • Le bleu est incrémenté en cercle inverse centré sur le coin supérieur gauche (plus on s'éloigne et plus on tend vers 255)

  11. #11
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Citation Envoyé par foetus Voir le message
    il faut réfléchir un peu ... et sortir les maths -- snip --
    Tu sais quoi ? Tout ce que tu as dit je le sais !
    Le seul problème c'est de passer ça dans le bitmap...

    Je me suis inspiré de ce que Paul disait, et j'ai fait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    {$IFDEF FORMCANVAS}
          Pixels[y, x] := rgb(red, green, blue);
    {$ELSE}
    //      Pixels[y, x] := rgb(red, green, blue);
          Pixels[x, y] := rgb(red, green, blue);
    {$ENDIF}
    J'ai même viré ces histoires de shl pour y voir clair, c'est rigolo j'ai une image de base (celle avec le texte, le $IFDEF FORMCANVAS) pleine de triangles colorés, et ensuite j'ai inversé le $DEFINE et j'ai joué avec le bitmap et les 4 possibilités de balayage : | downto to | downto downto | to to | to downto.
    La boucle extérieure travaille avec IMAGE_WIDTH et l'intérieure avec IMAGE_HEIGHT, je réalise après coup que j'aurais pu tester l'inverse également. Bon, je poste ça et j'y retourne... [EDIT] : c'était pas la peine, ça n'a rien changé, je retombe sur les même images A et B.
    downto tout le monde aura compris que c'est la boucle for big downto 0 quand to c'est l'inverse, for 0 to big.

    J'ai rajouté l'option xy / yx, ça donne 8 possibilités et voilà les résultats :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
       |   EXT  INT|   EXT    INT  |EXT INT| EXT  INT  |
       | downto to | downto downto | to to | to downto |
    yx |     A     |       B       |   A   |     B 
    xy |     A     |       B       |   A   |     B
    Il y a donc 4 images A identiques, et 4 images B identiques. Et voilà à quoi ça ressemble :
    Nom : essaibytes.jpg
Affichages : 538
Taille : 30,9 Ko

    À gauche vous aurez reconnu l'image de base, et au centre et à droite les images bitmap, A puis B.

  12. #12
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    il y a quelque chose qui me chagrine dans tes explications

    1) Form.Canvas ou Bitmap.Canvas, ça reste un Canvas que tu peux passer en paramètre d'une fonction commune qui se fiche de savoir si c'est une fiche ou bitmap.

    2) Pixel[x, y] := f(x, y)...qu'importe l'ordre dans lequel tu calcules les pixels (to/downto) vu que la couleur d'un pixel ne dépend que de sa position.

    3) tes deux images de droites subissent une rotation à 90° l'un part rapport à l'autre à cause du [x, y] et [y, x]

    4) la différence couleur vient de RGB(). Dans mon code il y a des débordements:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      couleur := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16)
      couleur := RGB(x + y, (x - y) + (x + y) div 256, (x + x) + ((x - y) + (x + y) div 256) div 256);
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  13. #13
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    il y a quelque chose qui me chagrine dans tes explications

    3) tes deux images de droites subissent une rotation à 90° l'un part rapport à l'autre à cause du [x, y] et [y, x]
    Il y a plusieurs choses que je ne capte pas dans ton retour :

    il a fallu que je fasse subir une rotation de 90° anti-horaire à celle du centre, en effet, puis un effet miroir selon l'axe horizontal pour basculer ce qui était en haut en bas.
    Du coup, oui, les deux images de droite se retrouvent identiques, mais en aucun cas similaires à celle de gauche, qui est le but à atteindre.
    Nom : rotationpaul.jpg
Affichages : 544
Taille : 43,4 Ko

    Citation Envoyé par Paul TOTH Voir le message
    4) la différence couleur vient de RGB(). Dans mon code il y a des débordements:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      couleur := (x + y) or ((x - y) shl 8 ) or ((x + x) shl 16)
      couleur := RGB(x + y, (x - y) + (x + y) div 256, (x + x) + ((x - y) + (x + y) div 256) div 256);
    Les débordements j'ai dû les éliminer en utilisant des bytes comme tu l'as plus tôt suggéré car ce nouveau code me produit exactement les mêmes images et couleurs que celui d'il y a quelques heures.


    Citation Envoyé par Paul TOTH Voir le message
    2) Pixel[x, y] := f(x, y)...qu'importe l'ordre dans lequel tu calcules les pixels (to/downto) vu que la couleur d'un pixel ne dépend que de sa position.
    La couleur d'un pixel, pour moi, dépend surtout de ce qu'on a mis dans ses bytes R G B et éventuellement A. Non ?

    Citation Envoyé par Paul TOTH Voir le message
    1) Form.Canvas ou Bitmap.Canvas, ça reste un Canvas que tu peux passer en paramètre d'une fonction commune qui se fiche de savoir si c'est une fiche ou bitmap.
    Oui, sauf que dans ton code le boulot pour "redescendre" sur le canvas de la fiche cette Array de TColor est fait par SetDIBitsToDevice.
    Je pourrais essayer de lui faire manger de la cible genre TBitmap ou TImage, à cette fonction Windows, mais mon souci, c'est qu'elle n'existe pas dans Lazarus, qu'un forum a suggéré d'utiliser BitBlt, que je n'y arrive pas dans ton code (normal, BitBlt veut un handle to source device context comme source, et pas une array de pixels), alors imagine dans Lazarus, et c'est comme ça que je me retrouve ici à poser mes questions incompréhensibles...
    Désolé...

    Merci en tout cas pour l'implication, et je m'en vais creuser une nouvelle piste, la transformation d'une array de pixels en bitmap, me semble avoir des posts là-dessus...

  14. #14
    Membre émérite
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Par défaut
    Salut,

    avec ce code j'obtiens bien le même résultat que l'original :
    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
    ...
    var // j'ai juste modifié la variable pixels en apixels pour pouvoir l'utiliser plus bas ...
      apixels: array[0..IMAGE_HEIGHT - 1, 0..IMAGE_WIDTH - 1] of TColor; // hauteur puis largeur, et non l'inverse
    procedure TForm4.Button2Click(Sender: TObject);
    var
      x, y: Integer;
      SrcBmp: TBitmap;    
    begin
      DoubleBuffered := True; // rajouté par moi
      SrcBmp := TBitmap.Create;
      with SrcBmp do begin
        SrcBmp.PixelFormat:=pf32bit;
        SrcBmp.Width := IMAGE_WIDTH;
        SrcBmp.Height := IMAGE_HEIGHT;
      end;
     
      with SrcBmp.Canvas do
      for y := 0 to IMAGE_HEIGHT-1 do
        for x := 0 to IMAGE_WIDTH-1 do
          with PRGBQuad(@aPixels[y, x])^ do
            Pixels[x, y] := RGB(rgbRed, rgbGreen, rgbBlue);
      image1.Picture.Graphic := SrcBmp;
    end;

  15. #15
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Oui, mais dans cette ligne (with PRGBQuad(@aPixels[y, x])^ do), pourquoi l'arrobase et l'accent circonflexe ?
    Pourquoi ne peut-on faire sans, indépendamment des cris scandalisés du compilo ?
    Et pourquoi [y, x] sur cette ligne et [x, y] sur celle de dessous ?
    Et pourquoi l'idée d'utiliser ça ne m'est-elle pas venue ? Ça ou un PRGBTriple ? À cause du 32 bits ? Voir ci-dessous...
    (non, là j'ai la réponse : c'est tellement mal foutu ces choses que ce n'est pas mémorisable, enfin, en ce qui me concerne.)

    C'est ça qu'il faut m'expliquer, pour m'éviter de revenir vous embêter avec des questions tordues.

    D'ailleurs, j'en ai deux, pour demain :
    1- comment utiliser correctement les 24 et 32 bits ? Parce que par exemple le code de Cirec arrive en 32 et compile bien sous Windows2000 avec D7 (pas bien jeune, tout ça), compile bien aussi sous un Debian récent dans un Lazarus pas trop vieux mais là, rien n'est affiché tant que je ne redescends pas en 24 bits.
    Et ça me gonfle de faire des choses sans savoir pourquoi surtout quand, dans d'autres codes, c'est l'inverse qu'il faut faire...

    2- regardez cette image (réduite de moitié) :
    Nom : compar_times.jpg
Affichages : 519
Taille : 30,8 Ko

    j'ai poussé les constantes de Cirec à 480-480 puisque l'image de gauche est à 640-480 ; ensuite j'ai exécuté, et l'image de droite a pris 1510 millisecondes pour être affichée (monstrueux !) quand celle de gauche n'a mis que 3 millisecondes, avec un code "optimisé" pour les accès à Scanline de chez efg, "optimisé" entre guillemets car un code basique travaillant sur les mêmes dimensions s'est affiché en seulement 2 millisecondes.


    Bon, on verra ça dans les jours qui viennent...

  16. #16
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 934
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 934
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Oui, mais dans cette ligne (with PRGBQuad(@aPixels[y, x])^ do), pourquoi l'arrobase et l'accent circonflexe ?
    Juste pour compliquer un peu ! PRGBQuad(@aPixels[y, x])^ égale TRGBQuad(aPixels[y, x])

    Mais c'est pas très logique tout cela

    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA (TRGBQuad) et non en RGBA (TColor), les rouge et bleu sont inversés. Le résultat est joli mais faux !
    On se retrouve ainsi avec un tableau de TColor qui est convertit en TRGBQuad (histoire d'inverser rouge et bleu) pour être reconvertit en TColor (SrcBmp.Pixels) qui va au final être implicitement reconvertit en TRGBQuad pour le stockage... Outre la lenteur de travailler pixel par pixel, c'est difficile de faire plus compliqué !

    Donc commencez par normaliser tout cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var
      aPixels: array[0..IMAGE_HEIGHT -1, 0..IMAGE_WIDTH -1] of TRGBQuad;
    Un transtypage au remplissage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    aPixels[y, x] := TRGBQuad((x + y) or ((x - y) shl 8 ) or ((x + x)shl 16));
    //ou
    dword(aPixels[y, x]) := (x + y) or ((x - y) shl 8 ) or ((x + x)shl 16);
    Puis travaillez aussi sur le bitmap en TRGBQuad (ScanLine).
    Pas besoin de boucle si le standard Windows considérant le premier pixel en bas à gauche est appliqué. Une simple copie mémoire suffit :
    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
    var
      SrcBmp: TBitmap;
    begin
      SrcBmp := TBitmap.Create;
      try
        SrcBmp.PixelFormat := pf32bit;
        SrcBmp.Width       := IMAGE_WIDTH;
        SrcBmp.Height      := IMAGE_HEIGHT;
     
        CopyMemory(SrcBmp.ScanLine[SrcBmp.Height -1], @aPixels, IMAGE_HEIGHT *IMAGE_WIDTH *SizeOf(TRGBQuad));
     
        img_Result.Picture.Graphic := SrcBmp;
      finally
        SrcBmp.Free;
      end;
    end;
    L'image résultante sera inversée par rapport à SetDIBitsToDevice puisque la hauteur de ce dernier est définie en négative. Donc soit la remettre en positif, soit inverser le remplissage de SrcBmp.
    Toujours une copie mais cette fois-ci ligne par ligne :
    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
    var
      SrcBmp: TBitmap;
      y :integer;
    begin
      SrcBmp := TBitmap.Create;
      try
        SrcBmp.PixelFormat := pf32bit;
        SrcBmp.Width       := IMAGE_WIDTH;
        SrcBmp.Height      := IMAGE_HEIGHT;
     
        for y := 0 to IMAGE_HEIGHT -1 do
          CopyMemory(SrcBmp.ScanLine[y], @aPixels[y], IMAGE_WIDTH *SizeOf(TRGBQuad));
     
        img_Result.Picture.Graphic := SrcBmp;
      finally
        SrcBmp.Free;
      end;
    end;
    Non ?


  17. #17
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Salut à tous,

    alors là, Andnotor, tu m'en bouches un coin ! Quelle analyse ! Et quel résultat ! ! !
    Pour faire court et simple et rapide, une image de 480x480 met moins d'une milliseconde (je n'ai pas modifié le compteur, dont la résolution est la milliseconde), c'est quand même fantastique, par rapport aux 1500 d'hier soir !
    (Ah, tiens, j'ai aussi testé en mode rectangle 640x480 ce matin à la fraîche [hier j'avais peur des AV qui rodent sournoisement, ] : 2 secondes pour l'afficher ))

    Un grand bravo, un grand merci !
    Non mais, quelle équipe sur ce forum, champions du monde !

    Maintenant, mon petit retour :

    Citation Envoyé par Andnotor Voir le message
    Juste pour compliquer un peu ! PRGBQuad(@aPixels[y, x])^ égale TRGBQuad(aPixels[y, x])
    Tu ne compliques rien du tout, au contraire, c'est très bien : tu simplifies l'écriture (dans l'ide), tu simplifies donc sa lecture et sa compréhension. Moi ça me va.

    Citation Envoyé par Andnotor Voir le message
    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA (TRGBQuad) et non en RGBA (TColor), les rouge et bleu sont inversés.
    Indépendamment du fait qu'il n'y a pas un seul mot sur ce "détail" dans msdn (), c'est le "par conséquent" qui me choque : toutes (parce qu'in fine tout est API dans le monde Windows, nan ?) les API's graphiques sont comme ça ? Première fois que j'en entends parler...

    J'aimerais bien une petite précision sur ce point.


    Citation Envoyé par Paul TOTH Voir le message
    SetDIBitsToDevice est déclarée dans l'unité Windows (plus exactement dans func.inc), normal c'est une API Windows.
    Oui, Paul, ch'sais bien, les gens de Lazarus/FreePascal en ont pourtant traduit tout plein, mais pas toutes...

    D'ailleurs, impossible de tester le code de ce matin sous Debian, Lazarus ne connait pas "CopyMemory",
    Va encore falloir retourner le web à la recherche de l'instruction-miracle !

    Bonne journée (va falloir que je bouge) et encore merci pour les lumineuses idées matinales

  18. #18
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 772
    Par défaut
    Citation Envoyé par Jipété Voir le message
    J'aimerais bien une petite précision sur ce point.
    Peut-être que je vais répondre à côté de la plaque: mais le BRG est hérité des CPU 16bits et du little/ big endian

    La couche alpha n'existait pas qu'il n'y avait pas de carte graphique.
    Si tu lis la documentation d'Embarcadero, il y a 3 niveaux de transparence: aucune, full (*), partial (**)

    Et donc en 16bits , une couleur sur 24 bits 0x112233 pouvait être soit 0x112233 soit 0x00332211.
    Donc Microsoft avait le choix entre le RGB ou le BGR.

    * -> On prend un point (souvent le coin supérieur gauche ou le point(0, 0)) et tous les points qui ont cette couleur sera remplacé par la couleur du fond

    ** -> c'est la vraie transparence: elle varie de 0 à 255. Ensuite, je ne rappelle jamais c'est dans quel sens si on parle d'opacité ou de transparence
    Mais comme par défaut Delphi travaille en bmp, elle ne sera pas supportée.

    Et même avec les extensions png de Delphi/ Embarcadero, je trouve que ce n'est pas terrible

  19. #19
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 132
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 132
    Par défaut
    Citation Envoyé par foetus Voir le message
    Peut-être que je vais répondre à côté de la plaque
    Tout à fait, oui

    La demande de précision portait sur le fait que
    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA
    Moi je ne vois pas le rapport entre le fait que SetDIBitsToDevice soit une API (puisque tout est API chez Ouinouin), et que du coup (= par conséquent) elle travaille en BGRA.

    Je ne vois pas le lien de cause à effet, et surtout je n'ai rien vu en gros en gras en rouge et clignotant dans msdn...

    Et sinon, juste pour toi et concernant ce canal Alpha, Transparent = 0 et Opaque = 255

    Nom : rainbow_transp.jpg
Affichages : 567
Taille : 8,4 Ko

    Dans cet exemple, l'arc-en-ciel a une transparence de 192.
    Valà,

  20. #20
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 934
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 934
    Par défaut
    Citation Envoyé par Jipété Voir le message
    D'ailleurs, impossible de tester le code de ce matin sous Debian, Lazarus ne connait pas "CopyMemory",
    Va encore falloir retourner le web à la recherche de l'instruction-miracle !
    Pas besoin d'aller si loin

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 31/03/2015, 15h36
  2. bibliothèques pour lire les pixels d'un bitmap
    Par nonozor dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 28/08/2008, 00h15
  3. Lire les pixels de grandes images sans les ouvrir
    Par psicot dans le forum Multimédia
    Réponses: 1
    Dernier message: 16/04/2007, 18h59
  4. Manipuler avec des classes
    Par poussinphp dans le forum FMOD
    Réponses: 3
    Dernier message: 03/06/2006, 18h20
  5. Réponses: 14
    Dernier message: 04/01/2006, 14h40

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