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

Composants FMX Delphi Discussion :

Comment rendre une image en nuance de gris (monochrome) [Windows]


Sujet :

Composants FMX Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut Comment rendre une image en nuance de gris (monochrome)
    Bonjour,

    je voudrai griser une image ou, plus exactement, sauvegarder une image jpg en nuance de gris.
    Sur l'écran, je peux bien sûr appliquer l'effet TMonochromeEffect (c'est bien ce que je cherche à obtenir) mais comment le faire directement sur un fichier sans passer par la case TImage+effet actif ?

    J'ai bien un début de code
    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
     
    function ConvertBitmapToGrayscale(const aBitmap: TBitmap): TBitmap;
    var
      X: Integer;
      Y: Integer;
      C,Gray: TAlphaColor;
      bitdata1, bitdata2: TBitmapData;
      pxFormat : TPixelFormat;
    begin
      pxFormat:=aBitmap.PixelFormat;
      Result := TBitmap.Create(Round(aBitmap.Width), Round(aBitmap.Height));
      if (aBitmap.Map(TMapAccess.maRead, bitdata1) and
        Result.Map(TMapAccess.maWrite, bitdata2)) then
      begin
        try
          for X := 0 to aBitmap.Width - 1 do
            for Y := 0 to aBitmap.Height - 1 do
            begin
              begin
              // obtention de la couleur du source
              // transformation en grisé (en vcl sans alpha ce serait      Gray := Round(0.30 * R + 0.59 * G + 0.11 * B);  
              // modification du pixel dans la cible
              end;
            end;
        finally
          aBitmap.Unmap(bitdata1);
          Result.Unmap(bitdata2);
        end;
      end;
    end;
    Mais les manipulations d'images et moi cela fait deux (voir plus) de plus je me demande s'il n'y a pas plus simple que de passer par scanline (après tout FMX passe par des moteur de rendu graphique comme GDI pour windows)
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  2. #2
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 726
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    Bonjour,
    Citation Envoyé par SergioMaster Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    // transformation en grisé (en vcl sans alpha ce serait  Gray := Round(0.30 * R + 0.59 * G + 0.11 * B);
    il existe deux autres formules, je t'invite à jeter un coup d'œil à The Gimp, si tu peux :

    Nom : désaturer.png
Affichages : 739
Taille : 26,5 Ko

    dynamiquement, changer d'option change le rendu de l'image, affichée derrière cette fenêtre (et, perso, je ne trouve pas ça confortable : à l'heure de nos grands écrans, mettre le rendu des 3 options côte à côte serait plus agréable pour comparer).

    Je te donne les 3 formules, qui sont bien connues :

    Lightness
    The graylevel will be calculated as
    Lightness = ½ × (max(R,G,B) + min(R,G,B))

    Luminosity
    The graylevel will be calculated as
    Luminosity = 0.21 × R + 0.72 × G + 0.07 × B
    la tienne, rajoutée ici pour comparaison :
    Luminosity = 0.30 × R + 0.59 × G + 0.11 × B

    Average
    The graylevel will be calculated as
    Average Brightness = (R + G + B) ÷ 3

    (je ne sais plus où j'ai trouvé ça, peut-être dans l'aide de Gimp)

    Citation Envoyé par SergioMaster Voir le message
    je me demande s'il n'y a pas plus simple que de passer par scanline (après tout FMX passe par des moteurs de rendu graphique comme GDI pour windows)
    À mon avis, "plus simple" sera une macro qui, dessous, travaillera avec scanline. Il n'y a pas mieux, et c'est vrai que c'est un peu ardu au début pour s'y mettre.
    Mais si j'y suis arrivé, tu dois pouvoir y arriver aussi !
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  3. #3
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Merci,

    j'en suis à ce code (avec déchet)
    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
    procedure TfrmMain.btnGriserClick(Sender: TObject);
    var
      bd1, bd2 : TBitmapData;
      w, h , x, y     : Integer;
      p1, p2     : PAlphaColorArray;
      nuancegris : Talphacolor;
      rgba : TAlphaColorRec;
      Hue,Sat,Lum : Single;
    begin
      OpenDialog1.Filter := 'JPEG Image|*.jpg';
      if OpenDialog1.Execute then
      begin
        Image1.Bitmap.LoadFromFile(OpenDialog1.FileName);
        w := Image1.Bitmap.Width;
        h := Image1.Bitmap.Height;
        Image2.Bitmap.SetSize(w, h);
        try
          Image1.Bitmap.Map(TMapAccess.Read, bd1);
          Image2.Bitmap.Map(TMapAccess.Write, bd2);
          for y := 0 to (h - 1) do
          begin
            p1 := PAlphaColorArray(bd1.GetScanline(y));
            p2 := PAlphaColorArray(bd2.GetScanline(y));
            for x := 0 to (w - 1) do
            begin
              nuancegris:=p1[x];
              RGBtoHSL(nuancegris,hue,sat,lum);
              rgba.Color:=nuancegris;
              // Luminosity = 0.21 × R + 0.72 × G + 0.07 × B
              lum:=0.21*rgba.R + 0.72 * rgba.G+ 0.07* rgba.B;
              p2[x] := HSLtoRGB(hue,sat,lum);
            end;
          end;
     
          finally
            Image1.Bitmap.Unmap(bd1);
            Image2.Bitmap.Unmap(bd2);
          end;
      end;
    end;
    si j'obtiens un truc interessant digne du pointillisme
    Nom : Capture.PNG
Affichages : 728
Taille : 122,6 Ko
    je me suis planté quelque part
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  4. #4
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Un petit code retrouvé :
    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
    procedure TForm1.Button2Click(Sender: TObject);
    type
      TRGBTripleArray = ARRAY[Word] of TRGBTriple;
    var
      x, y, H, S, L, Hmin, Hmax, Hmoy, Hnew: integer;
      P: ^TRGBTripleArray;
      TheColor: TColor;
    begin
      Image1.Picture.LoadFromFile(Fichier);
      // recherche de la teinte moyenne
      Hmin := Maxint;
      Hmax := -(Maxint-1);
      for y := 0 to Image1.Picture.Height-1 do begin
        P := Image1.Picture.Bitmap.ScanLine[y];
        for x := 0 to Image1.Picture.Width-1 do begin
          RGBTripleToHSL(P[x], H, S, L);
          Hmin := Min(Hmin, H);
          Hmax := Max(Hmax, H);
        end;
      end;
      ShowMessage( IntToStr(Hmin) + ' / ' + IntToStr(Hmax) );
      Hmoy := ( Hmin + Hmax ) div 2;
      ShowMessage( IntToStr(Hmoy) );
      // choix d'une nouvelle teinte
      if not ColorDialog1.Execute then exit;
      TheColor := ColorDialog1.Color;
      Hnew := GetHValue(TheColor);
      ShowMessage(IntToStr(Hnew));
      // application de la nouvelle teinte
      for y := 0 to Image1.Picture.Height-1 do
        for x := 0 to Image1.Picture.Width-1 do begin
          RGBtoHSLRange(Image1.Canvas.Pixels[x, y], H, S, L);
          if Hnew = 0 then
            S := 0; // pour le gris
          Image1.Canvas.Pixels[x, y] := HSLRangeToRGB(Hnew, S, L);
        end;
     
    end;
    Le gris s'y obtient en ne conservant que la luminosité (teinte et saturation à 0)
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  5. #5
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Tu dois pouvoir simplifier ton code comme suit pour ne conserver que la luminosité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            for x := 0 to (w - 1) do
            begin
              nuancegris := p1[x];
              RGBtoHSL(nuancegris, hue, sat, lum);
              p2[x] := HSLtoRGB(0, 0,lum);
            end;
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 453
    Points : 24 864
    Points
    24 864
    Par défaut
    En utilisant la Moyenne = Cumul / 3 : Griser une couleur et sa variante ScanLine
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Merci,
    Entre temps, je n'avais pas rafraichi mon navigateur, j'ai trouvé au moins une solution grace à ce blog

    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
    procedure TfrmMain.btnGriserClick(Sender: TObject);
    var
      bd1, bd2 : TBitmapData;
      w, h , x, y     : Integer;
      p1, p2     : PAlphaColorArray;
     
    var
      bd1, bd2 : TBitmapData;
      w, h , x, y     : Integer;
      p1, p2     : PAlphaColorArray;
     
     
      function grayscaled(aColor : Talphacolor) : Talphacolor;
      var
        H,S,L : Single;
      begin
        // https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
        RGBToHSL(aColor,H,S,L);
        H:=(maxvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B]) + minvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B])) / 2;
        result:=HSLToRGB(H,S,L);
      end;
     
    begin
      OpenDialog1.Filter := 'JPEG Image|*.jpg';
      if OpenDialog1.Execute then
      begin
        Image1.Bitmap.LoadFromFile(OpenDialog1.FileName);
        w := Image1.Bitmap.Width;
        h := Image1.Bitmap.Height;
        Image2.Bitmap.SetSize(w, h);
        try
          Image1.Bitmap.Map(TMapAccess.Read, bd1);
          Image2.Bitmap.Map(TMapAccess.Write, bd2);
          for y := 0 to (h - 1) do
          begin
            p1 := PAlphaColorArray(bd1.GetScanline(y));
            p2 := PAlphaColorArray(bd2.GetScanline(y));
            for x := 0 to (w - 1) do
            begin
              p2[x]:=grayscaled(p1[x]);
            end;
          end;
     
          finally
            Image1.Bitmap.Unmap(bd1);
            Image2.Bitmap.Unmap(bd2);
          end;
      end;
    end;
    résultat nickel
    Nom : Capture.PNG
Affichages : 730
Taille : 94,9 Ko

    J'ai plus qu'à en faire une fonction propre (surchargée sur un TBitmap, avec sauvegarde ou non selon mes besoins)
    je vais quand même tester les autres propositions du billet (par curiosité) et vos dernières propositions
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 453
    Points : 24 864
    Points
    24 864
    Par défaut
    C'est ColorToByteLuminance
    H ne doit pas dépasser 240
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    @tourlourou dernière proposition nickel et simple (pas de calcul)
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  10. #10
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 726
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    Citation Envoyé par tourlourou Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ...
      for y := 0 to Image1.Picture.Height-1 do
        for x := 0 to Image1.Picture.Width-1 do begin
          RGBtoHSLRange(Image1.Canvas.Pixels[x, y], H, S, L);
          if Hnew = 0 then
            S := 0; // pour le gris
          Image1.Canvas.Pixels[x, y] := HSLRangeToRGB(Hnew, S, L);
        end;
     
    end;
    Coucou, Yves (je pensais bien te retrouver par là, )

    Pal mal ton code, mais Image1.Canvas.Pixels[x, y] c'est épouvantablement lent, dès que l'image commence à avoir une taille sympathique, genre 200x200.


    Citation Envoyé par SergioMaster Voir le message
    J'ai plus qu'à en faire une fonction propre
    Je me permets d'insister pour faire, comme sur ma copie d'écran, un système de choix car, à l'usage, selon l'image un rendu sera plus intéressant qu'un autre.
    Alors pourquoi se limiter ?
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  11. #11
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Je me permets d'insister pour faire, comme sur ma copie d'écran, un système de choix car, à l'usage, selon l'image un rendu sera plus intéressant qu'un autre.
    Alors pourquoi se limiter ?
    Je pourrais effectivement surcharger aussi ma fonction pour le faire mais l'objectif n'est pas de faire un gimp, juste de griser des images d'une liste quand celles-ci sont les images "par défaut".
    Je sais, je ne suis pas très explicite, j'ajouterai l'image écran de l'application dès que j'aurais rajouté ce traitement.
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  12. #12
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 726
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    J'enfonce le clou, j'ai regardé ton lien (mêmes formules que celles que j'ai données dans mon premier post) puis les commentaires des gens (dommage, plein de liens morts...) et j'y ai relevé ça (le gras c'est moi) :
    Citation Envoyé par Matej
    21 April 2011 at 02:55

    I did some testing with all three mentioned methods and discovered that Luminosity method is best if picture is not too blue. So I tried this:

    1. for every pixel I first check if blue component is greater than green and red

    2. if it IS I use Lightness method (or Average – both are good) … if NOT I use Luminosity method for current pixel.
    et dans l'avant-dernier post un lien qui montre bien les résultats gris parfois minables selon la couleur et la méthode utilisée...
    EDIT : et j'aime bien son avant-dernière phrase :
    Citation Envoyé par Jason Summers
    Note that while this formula produces arguably the best possible results from an objective technical perspective, that doesn’t mean its results always look the best subjectively.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  13. #13
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Salut JP !

    Image1.Canvas.Pixels[x, y] c'est épouvantablement lent,
    Tu as bien raison, mais c'était un code pour tester le principe dans un bouton : pas besoin d'optimisation à ce stade !
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  14. #14
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Bonjour, pour faire "plaisir" à Jipété

    une unité FMX
    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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    unit ImageUtils;
     
    interface
     
    uses
      System.SysUtils, System.UITypes, System.UIConsts , System.Math,
      FMX.Types, FMX.Graphics, FMX.Utils;
     
      type Talgorithm = (algnone,algluminosity,algaverage,alglightness);
     
      function ConvertToGrayscale(const aBitmap: TBitmap; const aMethod : TAlgorithm=algnone) : TBitmap;
     
    implementation
     
     
    function Colortogray(const aColor : Talphacolor; const aAlgo : TAlgorithm=algnone) : Talphacolor;
      var
        H,S,L : Single;
        C : TAlphacolorRec;
        // https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
      begin
        RGBToHSL(aColor,H,S,L);
        c.Color:=acolor;
        case aAlgo of
          algluminosity: begin  // erreur
                           L:=0.21*c.R + 0.72*c.G + 0.07*c.B; 
                           Exit(HSLToRGB(H,S,L));
                         end;
          algaverage: begin
                        var mean : integer := (c.R + c.G + c.B) div 3;
                        c.R:=mean;
                        c.G:=mean;
                        c.B:=mean;
                        Exit(c.Color);
                      end;
          alglightness: begin
                          H:=(maxvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B]) +
                            minvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B])) / 2;
                         Exit(HSLToRGB(H,S,L));
                        end;
          else Exit(HSLtoRGB(0,0, L));
        end;
     
      end;
     
    function ConvertToGrayscale(const aBitmap: TBitmap; const aMethod : TAlgorithm=algnone): TBitmap;
    var
      X, Y: Integer;
      bd1, bd2: TBitmapData;
      p1, p2: PAlphaColorArray;
    begin
      Result := TBitmap.Create(Round(aBitmap.Width), Round(aBitmap.Height));
      if (aBitmap.Map(TMapAccess.Read, bd1)
         and Result.Map(TMapAccess.Write, bd2)) then
      begin
        try
          for Y := 0 to (aBitmap.Height - 1) do
          begin
            p1 := PAlphaColorArray(bd1.GetScanline(Y));
            p2 := PAlphaColorArray(bd2.GetScanline(Y));
            for X := 0 to (aBitmap.Width - 1) do
            begin
               p2[X] := Colortogray(p1[X],aMethod);
            end;
          end;
        finally
          aBitmap.Unmap(bd1);
          Result.Unmap(bd2);
        end;
      end;
    end;
    end.
    et son test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure TfrmMain.btnGriserClick(Sender: TObject);
    begin
      if OpenDialog1.Execute then
      begin
        Image1.Bitmap.LoadFromFile(OpenDialog1.FileName);
        image2.Bitmap:= ConvertToGrayscale(Image1.Bitmap);
        image3.Bitmap:= ConvertToGrayscale(Image1.Bitmap,TAlgorithm.algluminosity);
        image4.Bitmap:= ConvertToGrayscale(Image1.Bitmap,TAlgorithm.algaverage);
        image5.Bitmap:= ConvertToGrayscale(Image1.Bitmap,TAlgorithm.alglightness);
      end;
    end;
    j'ai toujours un problème avec le calcul sur la luminosité (si quelqu'un voit où je merde il aura le , trop tôt pour )
    c'est quand même dingue que ce soit l'algo le plus utilisé que je n'arrive pas à mettre en place
    Nom : Capture.PNG
Affichages : 708
Taille : 282,7 Ko
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bonjour, pour faire "plaisir" à Jipété

    Tu verras qu'un jour ou l'autre ça te sera utile !
    Une fiche avec 3 TImage, chacune affichant le résultat d'un calcul, et tu pourras choisir en connaissance de cause.
    (Ah, si j'avais le temps...)

    Citation Envoyé par SergioMaster Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
          algluminosity: begin  // erreur
                           L:=0.21*c.R + 0.72*c.G + 0.07*c.B; 
                           Exit(HSLToRGB(H,S,L));
                         end;
    j'ai toujours un problème avec le calcul sur la luminosité (si quelqu'un voit où je merde il aura le , trop tôt pour )
    En première approche ultra-rapide et non testée, je dirais de remplacer L par H dans ton calcul. C'est une couleur, une teinte (H = Hue = teinte) pour les pixels que tu veux obtenir.
    Et ce H doit rentrer dans la fourchette 0...360, si ma mémoire est bonne.

    Regarde ton code pour
    Citation Envoyé par SergioMaster Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          alglightness: begin
                          H:=(maxvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B]) +
                            minvalue([TAlphacolorRec(aColor).R,TAlphacolorRec(aColor).G,TAlphacolorRec(aColor).B])) / 2;
                         Exit(HSLToRGB(H,S,L));
                        end;
    Bon dimanche et bons codes,

    EDIT : au fait, à propos de formules et de celle qui te préoccupe, as-tu bien lu cette page ? Elle est redoutable...
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  16. #16
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Bonjour
    Citation Envoyé par Jipété Voir le message
    EDIT : au fait, à propos de formules et de celle qui te préoccupe, as-tu bien lu cette page ? Elle est redoutable...
    Oui, j'avais lu
    Citation Envoyé par Jipété Voir le message
    C'est une couleur, une teinte (H = Hue = teinte)
    C'était bien ça ! Confusion entre nom de méthode et valeur à toucher

    reste maintenant un problème : une fuite de mémoire
    Nom : Capture.PNG
Affichages : 701
Taille : 6,3 Ko

    Vu les traitements prévus, (encore quelque erreurs sur la taille de l'image si c'est le bon coloris)
    Nom : Capture.PNG
Affichages : 701
Taille : 110,2 Ko
    cela ne va pas le faire, il va falloir que je trouve un moyen de libérer ça , cela dit, je craignais une multiplication des pertes, ce n'est pas le cas et se limite à ces mêmes fuites

    @Jipété tu vois, pas besoin de plusieurs méthodes de calcul de gris pour ces miniatures
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  17. #17
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Fuite de mémoire résolue. Cela ne venait pas de l'unité, mais de son utilisation.
    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
    procedure TfrmMain.btnGriserClick(Sender: TObject);
    var
      lbm: TBitmap;
    begin
      if OpenDialog1.Execute then
      begin
        Image1.Bitmap.LoadFromFile(OpenDialog1.FileName);
        lbm:=ConvertToGrayscale(image1.Bitmap);
        try
          Image2.Bitmap:=lbm;
        finally
          lbm.Free;
        end;
        lbm:=ConvertToGrayscale(Image1.Bitmap,Talgorithm.algluminosity);
        try
          Image3.Bitmap:=lbm;
        finally
          lbm.Free;
        end;
        lbm:=ConvertToGrayscale(Image1.Bitmap,Talgorithm.algaverage);
        try
          Image4.Bitmap:=lbm;
        finally
          lbm.Free;
        end;
        lbm:=ConvertToGrayscale(Image1.Bitmap,Talgorithm.alglightness);
        try
          Image5.Bitmap:=lbm;
        finally
          lbm.Free;
        end;
      end;
    end;
    j'en ai profité pour ajouter une surcharge à la fonction

    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
     
      function ConvertToGrayscale(const aBitmap: TBitmap; const aMethod : TAlgorithm=algnone) : TBitmap; overload;
      function ConvertToGrayscale(const FileName : String; const aMethod : TAlgorithm=algnone) : TBitmap; overload;
     
    implementation
    ...
     
    function ConvertToGrayscale(const FileName : String; const aMethod : TAlgorithm=algnone): TBitmap;
    var
      X, Y: Integer;
      bd1 : TBitmapData;
      p1 : PAlphaColorArray;
    begin
      if not FileExists(FileName) then exit(nil);
      result:=TBitmap.CreateFromFile(FileName);
      if Result.Map(TMapAccess.ReadWrite, bd1) then
       begin
        try
          for Y := 0 to (Result.Height - 1) do
          begin
            p1 := PAlphaColorArray(bd1.GetScanline(Y));
            for X := 0 to (Result.Width - 1) do
            begin
               p1[X] := Colortogray(p1[X],aMethod);
            end;
          end;
        finally
          Result.Unmap(bd1);
         end;
       end;
    end;
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  18. #18
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 726
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 726
    Points : 15 126
    Points
    15 126
    Par défaut
    Bonsoir,

    Citation Envoyé par SergioMaster Voir le message
    @Jipété tu vois, pas besoin de plusieurs méthodes de calcul de gris pour ces miniatures
    Certes, mais un jour lointain, peut-être...

    Dans l'attente, je me suis un peu pris la tête, mais ce sujet m'intéresse, alors en avant :

    Nom : compar5gris-iw.jpg
Affichages : 665
Taille : 41,8 Ko

    de haut en bas puis de gauche à droite on a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     lightness;    // ½ × (max(R,G,B) + min(R,G,B))
     luminosity;   // 0.21 × R + 0.72 × G + 0.07 × B
     luminosergio; // 0.30 × R + 0.59 × G + 0.11 × B
     entropymine;  // (0.2126 × R^2.2 + 0.7152 × G^2.2 + 0.0722 × B^2.2)^1/2.2
     average;      // (R + G + B) ÷ 3
    Voili voilou,
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  19. #19
    Membre expert
    Avatar de Charly910
    Homme Profil pro
    Ingénieur TP
    Inscrit en
    Décembre 2006
    Messages
    2 344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur TP
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 344
    Points : 3 122
    Points
    3 122
    Par défaut
    Bravo Jipété ! entropymine je ne connaissais pas et ça à l'air de donner d'excellents résultats.

    Je vais le mettre dans ma petite application de traitement d'images et de filtres.

    A+
    Charly

  20. #20
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 037
    Points : 40 941
    Points
    40 941
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    cela étant, je me fais incendier par un internaute qui m'écrit qu'il ne faut pas utiliser HSL
    The algorithms in that link are okay.

    Apart from that your grayscale algorithm is horribly inefficient (and wrong). Why use HSLToRGB when you know that for grayscale R=G=B and why use RGBToHSL when you already operate directly on the RGB values...? It's your implementation of them that's a problem. Just get rid of all the HSL stuff and you should be fine.


    The formula you call "luminosity" is using the Rec 709 coefficients for "luminance" used in HDTV video.

    I recommend you read these two sections:

    https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
    https://en.wikipedia.org/wiki/HSL_and_HSV#Disadvantages
    et franchement, s'il critique, il n'offre pas vraiment de correction que je comprenne

    Tout ça pour une sorte de "warning" sur mes listes d'images . "si l'image ne correspond pas à l'article alors l'image du modele est grisée" c'était tout ce que je voulais au départ.
    Je n'ai pas assez fouillé dans les sources pour lire comment était codé TMonochromeEffect cela dit je sais obtenir le Filtre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    uses FMX.Filter;
     
    var  F : Tfilter;
    ...
       F:=TfilterManager.FilterByName('TMonochromeEffect');
    sans toutefois savoir l'appliquer
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 12/12/2014, 21h15
  2. Comment convertir une image RGB en niveaux de gris ?
    Par Imène_23 dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 07/08/2011, 14h50
  3. [HTML] Comment rendre une image cliquable?
    Par Nixar dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 11/03/2008, 09h58
  4. Comment rendre une partie d image noire?
    Par nouha_79 dans le forum Images
    Réponses: 1
    Dernier message: 13/11/2007, 16h39
  5. Comment rendre une image vidéo nette ?
    Par Le Débutant dans le forum Vidéo
    Réponses: 2
    Dernier message: 14/11/2006, 12h00

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