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

Langage Delphi Discussion :

Placer un TImage dans une zone de pixel de même couleur


Sujet :

Langage Delphi

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2006
    Messages : 39
    Points : 28
    Points
    28
    Par défaut Placer un TImage dans une zone de pixel de même couleur
    Bonjour,

    J'ai une zone (de taille et de forme variable) et j'aimerai y placer un composant Timage (rectangulaire) qui occuperai l'espace des pixels d'une couleur donnée. Dans quelle direction dois-je partir ?

    Exemple : J'ai un cercle de 50*50 alors mon Timage sera de 50*50 carré au milieu. Si mon cercle change ou devient une autre forme, cela reviendrai à redimensionner et a replacer le Timage au centre de la "tâche" de pixel.

    Merci pour votre aide précieuse

    inc002

  2. #2
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Salut,

    Cela nécessite de parcourir le canvas sur lequel se trouve "l'espace des pixels d'une couleur donnée" ... "de taille et de forme variable" jusqu'à trouver son bord, ensuite de suivre ce bord à la trace pour en déterminer les coordonnées afin d'en calculer la taille et la position du centre de la "tâche" de pixels et du TImage.

    A cet effet tu peux utiliser une mire de 3x3 cases:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    type      TMire     = record                           
                           M : array[-1..1,-1..1] of byte; 
                           S : byte;                       
                          end; // S = nombre de points "de couleur donnée" dans la Mire
    var       Mire    : TMire;
    ensuite tu actualises le contenu de cette mire en parcourant le canvas de façon à placer dans cette mire des "0" si la couleur diffère de la "couleur donnée" et des "1" lorsque la couleur du point correspondant est égale à la couleur donnée. Voiçi un bout de code qui effectue ceci en parcourant un BitMap (pour l'utiliser tel quel , suffit de créer un BitMap à partir du contenu du canvas en question) :
    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
     
    const     MaxPixelCount   = 50001; //<à augmenter ou à diminuer selon besoins
     
    type      ppRGBArray  =  ^tTRGBArray;
              tTRGBArray  =  ARRAY[0..MaxPixelCount-1] OF TRGBTriple;
     
    var      maCouleurCible : TColor;
     
    function  LisScanlinesVersMire(bmp : TBitMap; xc,yc : integer) : TMire;
    //          Nécessite que le Bmp soit au préalable déclaré Bmp.pixelFormat := pf24bit;
    //          xc,yc = coordonnées du point courant correspondant à la case centrale de la mire 
    var       Ligne : ppRGBArray;
              co,li,h,w : integer;
              cl    : TColor;
    begin     for co:=-1 to 1 do for li:=-1 to 1 do Result.M[co,li]:=0;
              Result.S:=0;
              with bmp do
              begin h:=bmp.height; w:=bmp.width;
                    for li:=-1 to 1 do
                    begin if (yc+li>=0) and (yc+li<=h-1) then
                          begin Ligne := ScanLine[yc+li];
                                for co:=-1 to 1 do
                                begin if (xc+co>=0) and (xc+co<=w-1) then
                                      begin with Ligne[xc+co] do
                                            begin cl:=RGB(rgbtRed,rgbtGreen,rgbtBlue);
                                                  if cl=maCouleurCible then
                                                  begin Result.M[co,li]:=1;
                                                        inc(Result.S);
                                                  end;
                                            end;
                                      end; //if (xc
                                end; // for co
                          end; // if (yc
                    end; // for li
              end; // with bmp
    end; // LisScanlinesVersMire
    ... et ensuite tu crées un procedure avec des boucles imbriquées pour parcourir le BitMap en actualisant la Mire M:=LisScanlinesVersMire(bmp,x,y); jusqu'à ce que cette Mire renvoie M.S>1 et à partir de ce moment comme la mire contient au moins un point de la "couleur donnée" on déplace la mire d'un cran de sorte que ce point corresponde au centre de la mire ce qui a comme conséquence que la mire contient au moins deux points de la "couleur donnée" dont un au centre. Donc si par exemple le deuxième point est situé au Nord-Est de la mire suffit de déplacer la mire d'un cran en direction du Nord-Est et ainsi de suite en se guidant à l'aide du contenu des 8 cases périphériques de la mire dans le style "je viens de l'Ouest et jai un point de la bonne couleur au Nord donc je fais un pas vers le Nord". Une mire de 3x3 cases suffit pour suivre ainsi à la trace des courbes continues épaisses d'un seul pixel. (Faut mémoriser les coordonnées de la trajectoire au fur et à mesure de l'avancement de la mire pour le calcul de la taille et du centre du TImage qu'on veut y placer).

    L'intérêt de cette méthode est qu'à partir du moment où la mire est "accrochée" à la trajectoire on n'a plus besoin de balayer toute la surface du BitMap puisque la zone à balayer se réduit à une plage large de 3 pixels et de longueur égale à celle de la trajectoire : du coup c'est hyper-rapide, on peut même se payer le coup d'un léger ralentissement en utilisant canvas.Pixels[xc,yc] à la place de Scanline en modifiant la function LisScanlinesVersMire() à cet effet.

    A+

    EDIT : Par contre je n'ai pas pigé l'intérêt consistant à placer un Timage au centre de la "tâche" de pixel.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2006
    Messages : 39
    Points : 28
    Points
    28
    Par défaut
    Merci de votre réponse très complète.

    Pour l' EDIT, je vais vous le dire

    J'ai un PaintBox dans lequel je dessine les phases de la lune suivant la date. Celui-ci est parfaitement implémenté mais je veux inclure une image sur le croissant de la lune visible(dans le cadre d'un travail de diplôme).

    Pour ma question, comment tranforme t'on le contenu d'un PaintBox en BitMap?
    Je sais faire l'inverse (exemple dans l'aide de Delphi 7) mais là je suis un peu perdu

    Finalement je n'ai pas très bien saisi le développement de la dernière partie de la solution mais je m'accroche.

    Merci encore pour l'aide que vous nous apportez tous !

    EDIT : Non, rien...

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2006
    Messages : 39
    Points : 28
    Points
    28
    Par défaut
    Rebonjour,

    J'ai enfin réussi a copier le contenu d'un PaintBox dans un Timage, l'exemple suivant sauvegarde le fichier sur le disque:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var
      B: TBitmap;
      R: Trect;
    begin
      B := Tbitmap.Create;
      B.Width := Pbox.Width;
      B.Height := Pbox.Height;
      R := Rect(0, 0, Pbox.Width, Pbox.Height);
      B.Canvas.CopyRect(R, Pbox.Canvas, R);
      //B.SaveToFile('c:\monfichier.bmp');
      Image1.Picture.Assign(B);
      B.free;
    Je continue maintenant le parcours de la solution que vous m'avez apporté et je vous tiens au jus !

  5. #5
    Modérateur

    Homme Profil pro
    Ingénieur retraité
    Inscrit en
    Octobre 2005
    Messages
    2 396
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur retraité

    Informations forums :
    Inscription : Octobre 2005
    Messages : 2 396
    Points : 3 266
    Points
    3 266
    Par défaut
    Bonjour,

    1) A propos de :
    J'ai un PaintBox dans lequel je dessine les phases de la lune suivant la date. Celui-ci est parfaitement implémenté mais je veux inclure une image sur le croissant de la lune visible(dans le cadre d'un travail de diplôme).
    ... dommage de ne l'avoir pas dit dès le début car dans ce cas il y a une autre piste beaucoup plus simple à envisager :
    - lors du dessin d'une phase de la lune on mémorise immédiatement la taille et la position du centre de la zone de pixels de couleur donnée donc celles du TImage,
    - Y'a plus qu'à donner au TImage la taille et la position ainsi déterminée.

    2) Concernant :
    Finalement je n'ai pas très bien saisi le développement de la dernière partie de la solution mais je m'accroche.
    ... c'est à partir de quelle ligne que t'as pas bien saisi ?

    3) Infos complémentaires concernant la solution avec la mire de 3x3 cases :
    - comme la mire se remplit de "0" et de "1" cela conduit au maximum à 8*8*8 = 512 combinaisons possibles, compte tenu de son utilisation la mire doit rester centrée sur la trajectoire donc on fait un While M.M[0,0]=1 ce qui supprime toutes les combinaisons dont la case centrale comporte un "0" et ramène le nombre de combinaisons intéressantes à 8*4*8 = 256.

    Sur ces 256 combinaisons possibles on peut n'avoir besoin que d'une vingtaine pour suivre une trajectoire dépourvue d'angles inférieurs à 90° et dépourvue de croisements comme une ellipse, une sinusoïde, une parabole, etc.
    Mais le problème s'allonge lorsqu'on se trouve face aux combinaisons concernant les croisements et les pointes d'angles (pointes d'un croissant de lune).
    Exemple : avec des traits épais d'un seul pixels la pointe d'un angle de 1° reste épaisse d'un seul pixel sur une longueur de 26 pixels puis épaisse de 2 pixels sur une longueur de 49 pixels ce qui déborde largement de la mire et nécessite de compléter la mire par un bout de code qui va "sonder" le BitMap au-delà des 9 cases de la mire. C'est relativement facile lorsque la pointe en question comporte un bord horizontal ou vertical mais ça devient la galère avec des pointes orientées suivant n'importe quelle direction.

    J'ai en chantier une appli de reconnaissance de trajectoires présentes sur BitMap où j'utilise le principe de la mire de 3x3 cases et sur les 2280 lignes qu'elle comporte à ce jour, la function RecoTrajectoire qui regroupe la cascade des "if then ... else ..." d'examen des combinaisons fait à elle seule déjà 1334 lignes et il reste des combinaisons à coder pour traiter tous les cas de croisements et de pointes. Par contre ça couvre déjà pas mal de cas de trajectoires.

    4) Conclusion :Tout ça pour dire que si tu peux mémoriser la taille et la position du centre de la zone de pixels de couleur donnée immédiatement lors du dessin de la phase de la lune ton problème sera résolu beaucoup plus simplement.

    A+

Discussions similaires

  1. [AC-2007] Comment placer dans une zone de texte une expression numérique
    Par AndréPe dans le forum IHM
    Réponses: 3
    Dernier message: 08/08/2013, 10h10
  2. Placer le curseur lorqu'on clique dans une zone de texte
    Par la_chevre dans le forum SWT/JFace
    Réponses: 3
    Dernier message: 17/08/2010, 14h15
  3. Sélection valeur par défaut dans une zone de liste
    Par Cécile154 dans le forum IHM
    Réponses: 2
    Dernier message: 15/02/2005, 18h20
  4. Comment afficher les toolTipText dans une zone de statut ?
    Par nicok01 dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 28/01/2005, 13h32
  5. Tabulation dans une zone SELECT
    Par jfphan dans le forum ASP
    Réponses: 4
    Dernier message: 03/10/2003, 15h30

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