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

API, COM et SDKs Delphi Discussion :

[Graphique] Comment compter les couleurs d'une image ?


Sujet :

API, COM et SDKs Delphi

  1. #1
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut [Graphique] Comment compter les couleurs d'une image ?
    Bonjour,

    Comment peut on compter le nombre de couleurs que l'on a sur une image ?

    Bien sur, il y a la solution de "scanner" tous les pixels mais je voudrais quelque chose qui soit plus instantanné...

    Merci de votre aide

    David.

    Titre modifié.
    Merci de lire les règles du forum.

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Salut.

    Je vais supposer que tu veux compter le nombre de couleurs uniques.

    Y'a pas d'autre méthode que le scan complet, à l'exception d'une seule : dans le cas d'une image basée sur une palette, tu peux compter les couleurs uniques de la palette.

    En effet, le nombre de couleurs "réelles" de l'image ne peut en aucun cas excéder cette valeur. Cependant, c'est quand même du bricolage : ça ne te donne qu'une borne maximale, et pas du tout le nombre "réel" de couleurs.

    Après, il existe plusieurs manières d'optimiser ce comptage, mais l'optimisation ne porte que sur la manière de stocker/ranger les couleurs déjà rencontrées. Le scan pixel par pixel reste de rigueur.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Membre confirmé
    Avatar de lil_jam63
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    447
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 447
    Points : 600
    Points
    600
    Par défaut
    Tu charges ton image dans unTBitmap et tu fais un case of sur la propriété pixelFormat, un truc dans ce genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    case tonBitmap.pixelFormat of
        pf1Bit: showMessage('L'image est en N/B);
        pf8Bit: showMessage('L'image possède 16 couleurs); 
        ... // F1 pour plus de renseignements
     end;
    j'ai pas delphi sous la main donc pas testé.
    ----------------------------------------------------
    Avant de poster, pensez à utiliser les différents outils à votre disposition:
    Google, la FAQ et le moteur de recherche.

  4. #4
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut
    Justement, je voulais compter les couleurs pour definir ma palette...

  5. #5
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Pour pinailler un peu : lil_jam63, ça c'est la profondeur de couleurs, pas le nombre de couleurs... ;-)
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  6. #6
    Membre confirmé
    Avatar de lil_jam63
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    447
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 447
    Points : 600
    Points
    600
    Par défaut
    C'est pour ça que je lui ai proposé ça, j'ai compris qu'il cherchait la profondeur de couleur et non pas le nombre de couleurs différentes
    ----------------------------------------------------
    Avant de poster, pensez à utiliser les différents outils à votre disposition:
    Google, la FAQ et le moteur de recherche.

  7. #7
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut
    Pourtant il me semble que c'est "Mac LAK" qui me repond à ma question sans pour autant me donner la solution magique...

    Je veux savoir "combien il y a de couleurs effectives différentes utilisées son mon image". Je sais que si j'ai une image 4 bits il y aura 16 couleurs maxi mais sur mon image on pourrait en trouver que 3... C'est ca que je veux savoir.

    Bref... ca change rien, je fais devoir faire du point par point selon "Mac LAK"

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par yoghisan
    Pourtant il me semble que c'est "Mac LAK" qui me repond à ma question sans pour autant me donner la solution magique...
    Je ne te la donne pas parcequ'elle n'existe pas, tout simplement...

    Par contre, je te signale quand même que faire cette opération est franchement rapide, c'est pas tout à fait comme si tu devais le faire à la main avec un papier et un crayon, non plus.

    Citation Envoyé par yoghisan
    Bref... ca change rien, je fais devoir faire du point par point selon "Mac LAK"
    Ouaip. C'est exactement la même chose que pour un calcul d'histogramme, il faut parcourir l'image.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #9
    Expert confirmé
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Points : 4 219
    Points
    4 219
    Par défaut
    Salut!
    A mon avis, le code ressemblera à 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
    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
    Const
      Canceled: Boolean = True;
     
     
    Procedure TForm1.StartButtonClick(Sender: TObject);
    Var
      bmp: TBitmap;
      x, y, i: Integer;
      r, g, b: Integer;
      p: PByteArray;
      pal: Array Of TColor;
      col: TColor;
      found: Boolean;
     
    Begin 
     
      Canceled := False;
      OpenPictureDialog1.Filter := 'Fichiers BMP (*.bmp)|*.bmp;'; 
      If Not (OpenPictureDialog1.Execute) Then 
        Exit;
      bmp := TBitmap.Create; 
      bmp.LoadFromFile(OpenPictureDialog1.FileName); 
     
      SetLength(pal, 1);
      Gauge1.MaxValue := bmp.Height;
      For y := 0 To bmp.Height - 1 Do 
      Begin 
     
        Gauge1.Progress := (y + 1);
        Application.ProcessMessages;
        If(Canceled) Then
          Break;
     
        p := bmp.ScanLine[y];
        For x := 0 To bmp.Width - 1 Do
        Begin 
          r := p[x * 3]; 
          g := p[x * 3 + 1];
          b := p[x * 3 + 2];
          col := RGB(r, g, b); 
          found := False; 
     
          For i := Low(pal) To High(pal) Do
            If (pal[i] = col) Then 
            Begin 
              found := True;
              Break; 
            End;
     
          If Not (found) Then
          Begin
            SetLength(pal, High(pal) + 2);
            pal[High(pal)] := col;
          End; 
     
        End;
     
      End;
     
      bmp.Free;
      If Not(Canceled) Then
        ShowMessage(IntToStr(High(pal)) + ' couleurs trouvées');
      Gauge1.Progress := 0;
     
    End;
     
     
    Procedure TForm1.CancelButtonClick(Sender: TObject);
    Begin
      Canceled := True;
    End;
    Il faudrait aussi prévoir à ne pas dépasser les ressources si l'image comprend un nombre élevé de couleurs...
    Plus il y aura de couleurs, plus la recherche sera longue (et proportionnelle à la taille de l'image). Il faudrait éventuellement réfléchir à une méthode d'optimisation pour la recherche des couleurs (avec les valeurs rgb par exemple). En fait, ça dépendra surtout du type d'image que tu comptes analyser, à+

    De retour parmis vous après 10 ans!!

  10. #10
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut
    Merci à tout le monde pour cette aide toujours aussi rapide et de bonne qualité.
    Merci sub0, je vais regarder ton code de plus près.

  11. #11
    Expert confirmé
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Points : 4 219
    Points
    4 219
    Par défaut
    En réalité, je pense qu'il doit exister une autre méthode plus rapide utilisée par les programmes d'édition d'image comme Paint Shop Pro par exemple pour les fonctions de diminution du nombre de couleurs. Le code ci-dessus avec une image en 1024x768 contenant 60000 couleurs environ a pris beaucoups trop de temps (surtout vers la fin). C'est pour cette raison que je pense qu'il faut optimiser la recherche des couleurs dans le tableau dynamique, en utilisant directement les valeurs rgb par exemple... à+
    De retour parmis vous après 10 ans!!

  12. #12
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Voilà un algo optimisé. Par contre, j'ai privilégié une implémentation claire à un truc efficace mais immonde à lire.

    Il est basé sur un classement bit à bit des couleurs, permettant ainsi de les stocker dans un arbre binaire de même hauteur que le nombre de bits par pixel, et dont le nombre de feuilles terminales indique le nombre de couleurs uniques.

    En rajoutant, sur les feuilles terminales, le nombre de pixels de la couleur correspondante, on peut obtenir l'histogramme très facilement avec le même algorithme. Là, j'ai eu la flemme de l'implémenter.

    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    // Rajouter manuellement ces unités.
    Uses Windows, SysUtils, Graphics ;
     
    // Calcule le nombre de couleurs d'une image BMP.
    // Paramètres : Nom du fichier BMP sur le disque dur.
    procedure TTestForm.LakCountColors ( Const FileName: String ) ;
     
    // Impératif : l'évaluation booléenne complète DOIT être désactivée.
    {$B-}
    Const
         // Profondeur de couleur maximale pour l'arbre.
         Depth = 24  ;
     
    Type
        // Structure de comptage des couleurs.
        PColorCell = ^TColorCell ;
        TColorCell = Record
            Child : Array[0..1] Of PColorCell ;
            End                               ;
        // Tableaux d'accès aux scanlines en mode 32 bits.
        PCardinalArray = ^TCardinalArray ;
        TCardinalArray = Array[0..8191] Of Cardinal ;
     
        // Vérifie l'existence d'une cellule, l'alloue si nécessaire.
        Function CheckCell ( Cell : PColorCell ; Const Child : Integer ; Var Created : Boolean ) : PColorCell ;
        Begin
             Created:=(Cell.Child[Child]=Nil);
             If (Created) Then
                Begin
                New(Result);
                FillChar(Result^,SizeOf(Result^),0);
                Cell.Child[Child]:=Result;
                End;
             Result:=Cell.Child[Child];
        End;
     
        // Crée un arbre vide.
        Function CreateTree : PColorCell ;
        Begin
             New(Result);
             FillChar(Result^,SizeOf(Result^),0);
        End;
     
        // Détruit l'arbre
        Procedure DestructTree ( Var Root : PColorCell ) ;
        Begin
             If Not Assigned(Root) Then
                Exit ;
             DestructTree(Root.Child[0]);
             DestructTree(Root.Child[1]);
             Dispose(Root);
        End;
     
        // Cherche une couleur dans l'arbre, ajoute le noeud si nécessaire.
        Procedure SearchAndAdd ( Root : PColorCell ; Color : Cardinal ; Var RealSize : Cardinal ) ;
        Var
           Curr    : PColorCell ;
           I       : Integer    ;
           Created : Boolean    ;
        Begin
             Curr:=Root ;
             // On calcule sur Depth bits.
             For I:=1 To Depth Do
                 Begin
                 // Détermination du bit, parcours de l'arbre en fonction du bit.
                 Curr:=CheckCell(Curr,(Color And 1),Created);;
                 // Décalage de la couleur.
                 Color:=Color Shr 1 ;
                 End;
             // Au dernier bit, on vérifie si la cellule a été créée ou pas.
             // Si oui, c'est une nouvelle couleur.
             If Created Then
                Inc(RealSize);
        End;
     
    Var
       Bmp      : TBitmap        ;
       Root     : PColorCell     ;
       ClrCount : Cardinal       ;
       X, Y, R  : Cardinal       ;
       H, W, C  : Cardinal       ;
       P        : PCardinalArray ;
    Begin
         // Chargement de l'image.
         Bmp:=TBitmap.Create;
         Bmp.LoadFromFile(FileName);
         // L'astuce est ici : on convertit en 32bpp pour booster le parcours des scanlines.
         Bmp.PixelFormat:=pf32bit;
     
         // Initialisation
         ClrCount:=0;
         Root:=CreateTree;
     
         Progress.Position:=Progress.Min;
         H:=Bmp.Height-1;
         W:=Bmp.Width;
         Progress.Max:=H;
         // Parcours ligne à ligne.
         For Y:=0 To H Do
             Begin
             Application.ProcessMessages;
             P:=Bmp.ScanLine[Y];
             // Parcours pixel par pixel
             X:=0;
             While (X<W) Do
                   Begin
                   C:=P[X];
                   // On cherche les pixels identique contigüs : pas la peine de répéter pour rien une recherche.
                   R:=X+1;
                   // ATTENTION : Ce code requiert d'avoir désactivé l'évaluation booléenne complète.
                   // Sinon, lorsque R=W, il y a Access Violation sur P[R].
                   While ((R<W) And (P[R]=C)) Do
                         Inc(R);
                   SearchAndAdd(Root,C,ClrCount);
                   X:=R;
                   End;
             Progress.StepIt;
             End;
         DestructTree(Root);
         ColorCount.Text:=IntToStr(ClrCount);
         Bmp.Free;
         Progress.Position:=Progress.Min;
    end;
    Pour donner une idée : sur ma machine (Xeon 2.8GHz), pour une image 1024x768 contenant 95.893 couleurs uniques, le code de Sub0 a pris 2 minutes et 2 secondes. Le mien a pris 1300 ms, et on peut encore améliorer les points suivants :
    - Réduire et améliorer la consommation mémoire en allouant un tas local Windows et/ou utiliser un tableau dynamique de TColorCell en lieu et place du tas habituel. Ca permet d'accélérer les allocations et surtout la destruction de l'arbre.
    - Réduire le nombre de procédures (un saut et un transfert de paramètre inutile, c'est long).
    - Utiliser les préchargement de cache.
    - Supprimer la conversion 32 bits (c'est rapide, mais bon...)
    - Virer le Application.ProcessMessages, la TProgressBar et les appels VCL de manière générale (suffisamment rapide pour que ça soit inutile, j'ai gagné plus de 200 ms sur le test précité).

    Avec un bon profiler pour voir les goulets d'étranglement, je pense pouvoir tomber à 500 ms pour une image de test comme celle précitée.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  13. #13
    Expert confirmé
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Points : 4 219
    Points
    4 219
    Par défaut
    Trop fort!

    J'ai rien pigé, mais c'est pas grave!

    à+
    De retour parmis vous après 10 ans!!

  14. #14
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Sub0
    Trop fort!


    Citation Envoyé par Sub0
    J'ai rien pigé, mais c'est pas grave!
    En fait, c'est plus simple qu'il n'y paraît, c'est une optimisation lourde du même principe que tu as utilisé.

    - Etape 1 : Utiliser les couleurs comme des entiers 32 bits (type RGBQUAD casté en Cardinal). Ca fonctionne comme les codes couleur HTML.
    - Etape 2 : Trier le tableau des couleurs trouvées. Recherche par dichotomie, insertion triée des couleurs. La complexité tombe en log2n sur la recherche (au lieu de n).
    - Etape 3 : Réduire les structures lourdes.

    En fait, pour classer une couleur dans un système existant, il y a deux grandes méthodes : le tableau, et l'arbre.
    Le tableau dynamique pose le problème de sa complexité de parcours, et surtout de sa réallocation, qui est très très longue... On gagne beaucoup de temps en incrémentant la taille par "gros" blocs, par exemple 128 éléments, et en maintenant une variable supplémentaire contenant la taille "utile" du tableau (alors que Length(Tab) renvoie la taille "réelle"). Mais ça reste quand même très lent d'accès dès que la taille devient trop importante (tu as dû remarquer le "hang" sur la Gauge à un certain stade de ton algo, je pense).

    L'autre solution est l'arbre, donc. Or, utiliser un arbre sur les entiers 32 bits est idiot (c'est pire qu'un tableau !), et l'utiliser sur les composantes R, G et B n'est pas mieux (hauteur : 3, mais l'arbre est 256-aire !!).
    En poussant le raisonnement jusqu'au bout, on arrive à classer par bits.

    Utiliser les bits composant le mot de 32 bits (réduit aux 24 utiles) permet d'avoir un arbre binaire pour la recherche et le classement, et ça, c'est rapide. On extrait les bits par un masque sur celui de poids faible, et on fait un décalage binaire à chaque étape pour "avancer" dans les bits.
    A chaque étape, on mémorise si l'on a dû créer une cellule pour continuer à parcourir l'arbre ou pas. Tant que ce sont des bits "intermédiaires", ça n'a pas d'importance, mais pour le dernier, ça indique si l'on a créé une feuille ou pas => si oui, c'est une nouvelle couleur, donc on incrémente le compteur de couleurs. Dans le cas d'un calcul d'histogramme, on rajouterai dans la feuille le compteur d'occurrences de la couleur.
    Le paramètre RealSize permet d'éviter d'avoir à reparcourir l'arbre pour compter les feuilles.

    Après, comme je l'ai dit, l'algo peut non seulement être optimisé, mais aussi amélioré en calculant l'histogramme au passage, et en prenant en compte la profondeur initiale de l'image (de 4 bpp à 32 bpp) de manière à pouvoir compter les images de n'importe quel TBitmap, car il n'est pas nécessaire de connaître le format précis des pixels pour utiliser cet algo : la taille (en bits) de ces pixels suffit.

    Voilà ! ;-)
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  15. #15
    Expert confirmé
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Points : 4 219
    Points
    4 219
    Par défaut
    Je vais lire ton explication tranquillement...

    Je poste juste la méthode que j'ai trouvé.
    Je ne sais pas si elle plus rapide, mais elle me semble plus facile à comprendre.
    J'imagine que tu vas vouloir comparer la rapidité, alors j'ai supprimé la progressbar!
    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
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    Unit Unit1;
    Interface
    Uses Windows, Messages, SysUtils, Classes, Graphics, Controls,
         Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, ExtDlgs;
     
    Type
      TForm1 = Class(TForm)
        StartButton: TButton;
        OpenPictureDialog1: TOpenPictureDialog;
        Procedure StartButtonClick(Sender: TObject);
      End;
     
    Var
      Form1: TForm1;
     
     
    {----------------------------------------------------------------}
    {                       }Implementation{                         }
    {----------------------------------------------------------------}
    {$R *.DFM}
     
    Const
      MaxPixelCount = 65536;
     
    Type
      // For pf24bit Scanlines
      pRGBTripleArray = ^TRGBTripleArray;
      TRGBTripleArray = Array[0..MaxPixelCount - 1] Of TRGBTriple;
     
     
    {----------------------------------------------------------------}
    { Count number of unique R-G-B triples in a pf24bit Bitmap.
    { Use 2D array of TBits objects -- when (R,G) combination occurs
    { for the first time, create 256-bit array of bits in blue dimension.
    { So, overall this is a fairly sparse matrix for most pictures.
    { Tested with pictures created with a known number of colors, including
    { a specially constructed image with 1024*1024 = 1,048,576 colors.
    { efg, October 1998.
    {----------------------------------------------------------------}
    Function CountColors(Const Bitmap: TBitmap): Integer;
    Var
      Flags: Array[Byte, Byte] Of TBits;
      i, j, k: Integer;
      rowIn: pRGBTripleArray;
     
    Begin
      // Be sure bitmap is 24-bits/pixel
      Assert(Bitmap.PixelFormat = pf24Bit);
     
      // Clear 2D array of TBits objects
      For j := 0 To 255 Do
        For i := 0 To 255 Do
          Flags[i, j] := Nil;
     
      // Step through each scanline of image
      For j := 0 To Bitmap.Height - 1 Do
      Begin
        rowIn := Bitmap.Scanline[j];
        For i := 0 To Bitmap.Width - 1 Do
        Begin
          With rowIn[i] Do
          Begin
     
            If Not Assigned(Flags[rgbtRed, rgbtGreen]) Then
            Begin
              // Create 3D column when needed
              Flags[rgbtRed, rgbtGreen] := TBits.Create;
              Flags[rgbtRed, rgbtGreen].Size := 256;
            End;
     
            // Mark this R-G-B triple
            Flags[rgbtRed, rgbtGreen].Bits[rgbtBlue] := TRUE
          End
        End
      End;
     
      Result := 0;
      // Count and Free TBits objects
      For j := 0 To 255 Do
      Begin
        For i := 0 To 255 Do
        Begin
     
          If Assigned(Flags[i, j]) Then
          Begin
            For k := 0 To 255 Do
              If Flags[i, j].Bits[k] Then
                Result := Result + 1;
            Flags[i, j].Free;
          End
     
        End
      End
     
    End;
     
     
    {----------------------------------------------------------------}
    Procedure TForm1.StartButtonClick(Sender: TObject);
    Var
      bmp: TBitmap;
    Begin
      OpenPictureDialog1.Filter := 'Fichiers BMP (*.bmp)|*.bmp;';
      If Not (OpenPictureDialog1.Execute) Then
        Exit;
      bmp := TBitmap.Create;
      bmp.LoadFromFile(OpenPictureDialog1.FileName);
      ShowMessage(IntToStr(CountColors(bmp)) + ' couleurs trouvées');
      bmp.Free;
    End;
     
     
    {----------------------------------------------------------------}
    End.
    De retour parmis vous après 10 ans!!

  16. #16
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Pas grave, je l'ai rajoutée pour vérifier...
    En effet, elle est plus rapide, elle renvoie le résultat en (environ) 200 ms. Elle fonctionne sur le principe du cube de couleurs. C'est la solution "idéale" en terme de traitement d'image, mais le problème est la taille prohibitive d'un cube "complet" (16 Mo au bas mot !!), ou la lourdeur de gestion d'un cube optimisé (listes chaînées hyper lourdes).

    La "faille" de cet algo est son incapacité à calculer un histogramme, par contre, et sa limitation à 24 bpp [on peut toujours convertir dynamiquement le bitmap, cependant). Mais si seul le décompte des couleurs compte, c'est bien suffisant.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  17. #17
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut Comment compter les couleurs d'une image ? suite...
    Bonjour,

    Je viens de poser récemment cette question et merci à ceux qui m'ont répondu mais je n'ai rien compris à ce qu'ils ont fait... ils sont partis dans un délire de performance où j'ai été complétement largé.

    http://www.developpez.net/forums/vie...287093&start=0

    C'est trop loin de mes connaissances.

    A l'origine, j'ai ecrit ce code qui peurrait me suffire
    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
     
    TCouleurImage = record
      NbrCouleur: integer;
      Couleur: array[1..1000] of TColor; // maxi 16777216
    end;
     
    Function CompterCouleurBmp(Bmp: TBitMap): TCouleurImage;
    var BmpTemp: TBitMap;
        i, j: integer;
        Couleur: TColor;
    begin
      BmpTemp := TBitMap.Create;
      BmpTemp.assign(Bmp);
     
      result.NbrCouleur := 0;
      FormCompteurCouleur := TFormCompteurCouleur.Create(nil);
      FormCompteurCouleur.Show;
      FormCompteurCouleur.Gauge.MaxValue := BmpTemp.Width*BmpTemp.Height;
      for i:=0 to BmpTemp.Width-1 do begin
        for j:=0 to BmpTemp.Height-1 do begin
          FormCompteurCouleur.Gauge.Progress := FormCompteurCouleur.Gauge.Progress+1;
          Couleur := BmpTemp.Canvas.Pixels[i,j];
          if not ((Couleur=ClWhite) or (Couleur=ClBlack))
            then begin
              inc(result.NbrCouleur);
              result.Couleur[result.NbrCouleur] := Couleur;
              RemplacerCouleurBmp(BmpTemp, Couleur, ClWhite);
            end;
        end;
      end;
      FormCompteurCouleur.Destroy;
      BmpTemp.Free;
    end;
    En moyenne, j'ai une image de 1000*750 avec 200 couleurs et il me faut 6 à 7 secondes pour exécuter la fonction.

    Je veux améliorer ce code pour qu'il soit plus rapide mais surtout pour approfondir mes connaissances.

    J'ai donc commencé à m'intérésser au notion abordée dans le précedent article, c'est-à-dire, ScanLine mais c'est dur...
    Pour l'instant, j'ai écrit ca
    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
     
    Const
      MaxPixelCount = 65536;
     
    Type
      pRGBTripleArray = ^TRGBTripleArray;
      TRGBTripleArray = Array[0..MaxPixelCount - 1] Of TRGBTriple;
     
    Function CompterCouleurBmp2(Bmp: TBitMap): TCouleurImage;
    var BmpTemp: TBitMap;
        x, y: integer;
        Ligne: pRGBTripleArray;
        Couleur: TColor;
    begin
      BmpTemp := TBitMap.Create;
      BmpTemp.assign(Bmp);
     
      result.NbrCouleur := 0;
      FormCompteurCouleur := TFormCompteurCouleur.Create(nil);
      FormCompteurCouleur.Show;
      FormCompteurCouleur.Gauge.MaxValue := BmpTemp.Width*BmpTemp.Height;
     
      for y:=0 to BmpTemp.Height-1 do begin
        Ligne := BmpTemp.ScanLine[y];
        for x:=0 to BmpTemp.Width-1 do begin
          Couleur := Ligne[x] ???;
          if not ((Couleur=ClWhite) or (Couleur=ClBlack))
            then begin
              inc(result.NbrCouleur);
              result.Couleur[result.NbrCouleur] := Couleur;
              RemplacerCouleurBmp(BmpTemp, Couleur, ClWhite);
            end;
     
          FormCompteurCouleur.Gauge.Progress := FormCompteurCouleur.Gauge.Progress+1;
        end;
      end;
     
      FormCompteurCouleur.Destroy;
      BmpTemp.Free;
    end;
    J'ai lu quelques articles et vu quelques programmes, c'est dur à comprendre alors mes questions sont :

    Certains utilise
    pByteArray = ^TByteArray;
    TByteArray = ARRAY[0..32767] OF BYTE;
    et d'autre
    pRGBTripleArray = ^TRGBTripleArray;
    TRGBTripleArray = Array[0..MaxPixelCount - 1] Of TRGBTriple;

    Quand on utise Byte et TRGBTriple;

    Pourquoi MaxPixelCount varie de 9999 à 65535 en fonction des programmes ?

    Comment avec Ligne[i] j'arrive a savoir la couleur de mon pixel ?
    Faut-il obligatoirement décomposer en RGB et comment fait on ?

    Merci pour celui ou ceux qui prendront de temps de repondre à un inculte comme moi...

  18. #18
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut Syntaxe : déclaration de variable et initialisation
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    var Espace: Array[Byte, Byte, Byte] Of Boolean;
        R, G, B: Byte;
    begin
      for R:=0 to 255 do
        for G:=0 to 255 do
          for B:=0 to 255 do
            Espace[R, G, B] := False;
    end;
    Ce code ne marche pas et ca me troue...
    Ce qui est bizarre c'est que la déclaration de la variable est acceptée mais l'initialisation plante !?!?!?

    Il y a un moyen de contourner simplement le probleme ?

    Merci, David.

  19. #19
    Membre régulier Avatar de yoghisan
    Profil pro
    Inscrit en
    Février 2004
    Messages
    172
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 172
    Points : 113
    Points
    113
    Par défaut
    Je fais comme ca

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var espace: array[0..16777215] of boolean;
      for R:=0 to 255 do 
        for G:=0 to 255 do 
          for B:=0 to 255 do          
            Espace[ ColorToRGB( RGB(R,G,B) ) ] := False;
    mais il y a surement mieux... dites le moi...

    Merci.

  20. #20
    Expert confirmé
    Avatar de Sub0
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2002
    Messages
    3 573
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 573
    Points : 4 219
    Points
    4 219
    Par défaut
    Comme ce genre de tableau provoque un EStackOverflow, on utilise un tableau d'objet "Bleu" possédant deux dimensions (Rouge et Vert) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Flags: Array[Byte, Byte] Of TBits;
    Dans la suite du code, on crée l'objet "Bleu" ayant une adresse "Rouge" et une adresse "Vert".
    La différence est que la création est dynamique et s'effectue hors de la pile, dans la RAM...
    Par exemple, il serait possible d'utiliser un tableau dynamique pour contourner le problème :
    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
      Espace: Array Of Array Of Array Of Boolean;
      R, G, B: Byte;
    Begin
      For R := 0 To 255 Do
      Begin
        SetLength(Espace, R + 1);
        For G := 0 To 255 Do
        Begin
          SetLength(Espace[R], G + 1);
          For B := 0 To 255 Do
          Begin
            SetLength(Espace[R, G], B + 1);
            Espace[R, G, B] := False;
          End;
        End;
      End;
    End;
    De retour parmis vous après 10 ans!!

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

Discussions similaires

  1. [serieux] Changer les couleurs d'une image
    Par TabrisLeFol dans le forum La taverne du Club : Humour et divers
    Réponses: 5
    Dernier message: 14/12/2006, 13h27
  2. comment récupérer les dimensions d'une image
    Par sirius25 dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 07/08/2006, 15h47
  3. [VB.Net] Comment récupérer les proprietes d'une image ?
    Par Cirdan Telemnar dans le forum VB.NET
    Réponses: 2
    Dernier message: 29/06/2006, 16h15
  4. Réponses: 3
    Dernier message: 10/03/2006, 14h15
  5. Comment compter les doublons d'une colonne?
    Par Dnx dans le forum Langage SQL
    Réponses: 8
    Dernier message: 07/11/2005, 10h50

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