Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

FILTRE DE NETTETÉ D'UN BITMAP


Information sur la source

Catégorie :Graphique Classé sous : netteté, accentuation, graphique Niveau : Initié Date de création : 11/02/2007 Date de mise à jour : 15/02/2007 09:34:31 Vu / téléchargé: 3 132 / 616

Note :
8 / 10 - par 1 personne
8,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (16)
Ajouter un commentaire et/ou une note

Description

Petite procédure permettant de modifier la netteté d'une image bitmap avec paramètre d'intensité de correction.
La correction peut être positive (accentuation) ou négative (adoucissement).
N'ayant trouvé aucune source en Delphi faisant cela, je suis parti du code "module d'application de filtres graphiques" déposé par w413x, que je remercie ici, en l'adaptant à un filtre d'accentuation sur une matrice de 3 * 3 pixels.

 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

13 février 2007 19:57:03 :
Mise à jour 13/02/07 : optimisation du code proposée par f0xi. Le temps de traitement est amélioré d'au moins 35%.
15 février 2007 09:34:31 :
Correction déclaration type TPixel (inversion Red et Blue). Pas vu cette erreur pcq elle est sans incidence sur le filtre. Sorry.

Commentaires et avis

signaler à un administrateur
Commentaire de f0xi le 12/02/2007 01:48:12 administrateur CS

pas mal du tout, mais on peu augmenter les performances un chouilla.


ici, avec l'image de l'exemple on passe de 109..120ms a 42..61ms :


const
  MaxImageSize = 32767; { max : image 32767x32767 }

type
  TPixel = record
    Blue  : Byte;
    Green : Byte;
    Red   : Byte;
  end;
  pPixelArray = ^TPixelArray;
  TPixelArray = array[0..MaxImageSize] of TPixel;
  TScanline   = array[0..MaxImageSize] of pPixelArray;
  TFilter     = array[0..8] of integer;

procedure BmpAccentuation(Src,Dest : TBitmap; const Correction: integer);
var
  Filter : TFilter;
  SelPix : TPixel;
  ScanSrc,
  ScanDest : TScanline;

  I,
  NewR,NewG,NewB,
  PosX, PosY,
  mX, mY,
  dX, dY,
  Diviseur,
  WM,HM,
  Cor2 : integer;

const
  PC_dYToI : array [-1..1] of byte = (1,4,7);

begin
   Dest.Assign(Src);

   if Correction = 0 then exit;

   Cor2      := Correction shl 2;

   Filter[0] := -Correction;
   Filter[2] := Filter[0];
   Filter[6] := Filter[0];
   Filter[8] := Filter[0];
   Filter[1] := 0;
   Filter[3] := 0;
   Filter[5] := 0;
   Filter[7] := 0;
   Filter[4] := Cor2 + 128;

   Diviseur  := Filter[4] - Cor2;

   WM       := Src.Width-1;
   HM       := Src.Height-1;

   for I := 0 to HM do begin
       ScanSrc[I]  := Src.Scanline[I];
       ScanDest[I] := Dest.Scanline[I];
   end;

   for PosY := 0 to HM do
       for PosX := 0 to WM do begin

           NewR := 0;
           NewG := 0;
           NewB := 0;

           for dY := -1 to 1 do begin

               mY := PosY + dY;
               if (mY < 0) or (mY > HM) then mY := PosY;
               I := PC_dYToI[dY];

               for dX := -1 to 1 do begin
                   mX := PosX + dX;
                   if (mX < 0) or (mX > WM) then mX := PosX;

                   SelPix := ScanSrc[mY,mX];

                   I := I + dX;

                   NewR := NewR + SelPix.Red   * Filter[I];
                   NewG := NewG + SelPix.Green * Filter[I];
                   NewB := NewB + SelPix.Blue  * Filter[I];
               end;
           end;

           NewR := NewR div Diviseur;
           if NewR > 255 then NewR := 255 else if NewR < 0 then NewR := 0;

           NewG := NewG div Diviseur;
           if NewG > 255 then NewG := 255 else if NewG < 0 then NewG := 0;

           NewB := NewB div Diviseur;
           if NewB > 255 then NewB := 255 else if NewB < 0 then NewB := 0;

           with ScanDest[PosY, PosX] do begin
                Red   := NewR;
                Green := NewG;
                Blue  := NewB;
           end;
      end;
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  Jpg: TJpegImage;
begin
  Jpg     := TJpegImage.Create;

  try
    OrigBmp := TBitmap.Create;
    Jpg.LoadFromFile('ImageTest.jpg');

    OrigBmp.Assign(Jpg);
    OrigBmp.PixelFormat:= pf24bit;
  finally
    Jpg.Free;
  end;

  Image1.Picture.Bitmap.Assign(OrigBmp);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Origbmp.Free;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  BmpAccentuation(OrigBmp, Image1.Picture.Bitmap, Trackbar1.Position);
end;

signaler à un administrateur
Commentaire de ThWilliam le 12/02/2007 12:49:47

Salut f0xi,

Merci pour ton appréciation et surtout pour tes conseils.
Je vais en tenir compte pour une prochaine mise à jour.
De ton code, j'ai du supprimer la ligne 'I := PC_dYToI[dY];' et remplacer la ligne 'I := I + dX' par le code original: 'I := 4 + (dY * 3) + dX;' : sinon il y a un effet de bord, l'image "bougeant" de droite à gauche dès qu'on corrige.

A +
Thierry

signaler à un administrateur
Commentaire de f0xi le 12/02/2007 16:06:37 administrateur CS

mmm bizarre, je n'avais pas ce soucis ...

mais je pense que j'ai merder dans mon tableau de precalc

j'aurais du faire :

IRat : array[-1..1,-1..1] of byte = (0,1,2,3,4,5,6,7,8);

et

           for dY := -1 to 1 do begin

               mY := PosY + dY;
               if (mY < 0) or (mY > HM) then mY := PosY;

               for dX := -1 to 1 do begin
                   mX := PosX + dX;
                   if (mX < 0) or (mX > WM) then mX := PosX;

                   SelPix := ScanSrc[mY,mX];

                   I := IRat[dY,dX];

                   NewR := NewR + SelPix.Red   * Filter[I];
                   NewG := NewG + SelPix.Green * Filter[I];
                   NewB := NewB + SelPix.Blue  * Filter[I];
               end;
           end;

ce qui evite 18 additions et 9 multiplications (donc environ 45 operations CPU en moins)
ça plus la compression des if pour mY et mX avec le deport de mY dans la boucle mY (sinon on la fait inutilement 6 fois)
cette boucle deviens donc plus rapide, puisqu'elle serat executée plusieurs millions de fois selon la taille de l'image.
(1 310 720 fois pour la boucle dY et 3 932 160 pour la boucle dX pour une image en 1280x1024)

l'optimisation est donc cruciale pour un tel process.
deja, ton idée de tableau pour les scanline est pas mal, elle accelere beaucoup le process (mais prend plus de memoire en contrepartie).

signaler à un administrateur
Commentaire de ThWilliam le 12/02/2007 19:44:29

Bien pensé ton array IRat en 2D , et tout marche impeccablement.
Encore merci f0xi.

A +
Thierry

PS
petite distraction :
IRat : array[-1..1,-1..1] of byte = ((0,1,2),(3,4,5),(6,7,8));

signaler à un administrateur
Commentaire de Francky23012301 le 15/02/2007 16:19:42

Salut,

Tres bon code : je suis bleuffé par le rendu.

Dis moi : J'ai cherché sur le net mais j'ai rien trouvé sur les différents filtres qui existent. Un ptit lien serait le bienvenu SVP M'Sieur ;).

@+

signaler à un administrateur
Commentaire de Francky23012301 le 15/02/2007 21:34:52

Juste une remarque :

Je trouve que l'application du filtre met beaucoup de temps. J'ai fais un test juste avec un timer avec pour interval 50ms. Sans filtre l'image est rafraichit toute les 50ms environ, avec le filtre on arrive à la seconde.

signaler à un administrateur
Commentaire de ThWilliam le 16/02/2007 12:35:40

Merci Francky.

D'autres filtres matriciels ? Vu que je cherchais exclusivement un filtre d'accentuation (trouvé en commentaires d'un code C++), je ne peux te répondre. Regarde toujours ceci :
http://www.alvasoft.net/programmation-traitement-d-image-par-filtrage-24-1.html
Programme téléchargeable (pas le code source) qui te permet d'entrer des valeurs sur une matrice 5 x 5.

L'application du filtre met beaucoup de temps ? J'ai placé un chrono et j'obtiens pour l'image de la démo un temps de traitement d' environ 30 ms. (sans l'optimisation de f0xi : environ 47 ms). Mon ordi = P4 3Ghz HT 1Go DDRam 400Mhz.

A +
Thierry        

signaler à un administrateur
Commentaire de cirec le 16/02/2007 14:53:43 administrateur CS

Salut,

Attention en Delphi on travaille en RGB et non en BGR
le Type TPixel de F0xi est déclarer à l'inverse et peut entraîner des résultats erronés

pour mieux s'en rendre compte un petit exemple :
(Vous avez besoin d'un TBoutton et de deux TLabel)

Type
  {La bonne définition}
  TRGBPixel = record
    Red   : Byte;
    Green : Byte;
    Blue  : Byte;
  end;

  TBGRPixel = record
    Blue  : Byte;
    Green : Byte;
    Red   : Byte;
  end;

Var
  RGBColor, BGRColor : TColor;
  RGBPixel : TRGBPixel Absolute RGBColor;
  BGRPixel : TBGRPixel Absolute BGRColor;

procedure TForm1.Button1Click(Sender: TObject);
begin
{Pour bien visualiser la différence j'ai volontairement choisis la même
  couleur de départ pour les deux}
  RGBColor := clRed;
  BGRColor := clRed;
  {Méthode RGB}
  With RGBPixel, Label1 do  Begin
    {Donne un résultat Rouge (ce qui est normal)}
    Font.Color := RGB(Red, Green, Blue);
    Caption := Format('R=%d, G=%d, B=%d', [Red, Green, Blue]);
  End;
  {Méthode BGR}
  With BGRPixel, Label2 do Begin
    {Donne un résultat Bleu (ce qui n'est pas normal)}
    Font.Color := RGB(Red, Green, Blue);
    Caption := Format('R=%d, G=%d, B=%d', [Red, Green, Blue]);
  End;
end;

Et si dans ton code tu n'as pas remaqué de différence c'est normal:
tu récupères les informations dans un ordre:
NewR := NewR + SelPix.Red   * Filter[I];
NewG := NewG + SelPix.Green * Filter[I];
NewB := NewB + SelPix.Blue  * Filter[I];

Et tu les restitues dans le même ordre:
with ScanDest[PosY, PosX] do
begin
    Red   := NewR;
    Green := NewG;
    Blue  := NewB;
end;

Mais comme ceci tu pourrais avoir des surprises :
ScanDest[PosY, PosX] := RGB(Red, Green, Blue);

@+
Cirec

signaler à un administrateur
Commentaire de ThWilliam le 16/02/2007 16:11:05

Salut Cirec,

Dans ma première mise à jour, j'avais déclaré TPixel dans l'ordre : R, G, B.

Mais si tu fais le test suivant sur une image de charte de couleurs :

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  p: pPixelArray;
begin
  p:= image1.picture.bitmap.ScanLine[Y];
  labelRed.caption:= inttostr(P[X].Red);
end;

... LabelRed  => 0 pour un rouge pur !!!
Donc ScanLine renvoie bien les valeurs selon l'ordre B,G,R.

A +
Thierry

signaler à un administrateur
Commentaire de cirec le 16/02/2007 23:28:31 administrateur CS

Oui désolé "j'm'ai trompé" :)

c'est l'utilisation de Absolute qui swap le R avec le B
il n'y a que dans ce cas que le nom correspond à la définition  => RGB -> RGB

sinon c'est BGR (qu'il faut déclarer) pour obtenir un résultat en RGB

c'est perturbant ce machin :)

@+
Cirec

signaler à un administrateur
Commentaire de Francky23012301 le 17/02/2007 19:46:41

Salut,

BOn pour tout te dire, j'ai fais un test ou je capture le flux de la webcam via le presse papier. En voulant appliquer le filtre, je n'ai plus aucune fluidité : en appliquant un intervalle de 50 ms, je vois la nouvelle image au bout d'une seconde.

signaler à un administrateur
Commentaire de ThWilliam le 19/02/2007 18:32:58

Merci Florent.

signaler à un administrateur
Commentaire de cirec le 20/02/2007 14:03:47 administrateur CS

Aie Aie Aie ... maintenent c'est Florenth qui continue à ma perturber ... lol

Bon alors regarde le petit exemple que j'ai donné dans mon premier post.

Je teste une couleur (TColor) en BGR mais celui qui me donne le bon résultat c'est l'ABSOLUTE RGB ????

D'autant plus que tu ne me facilites pas la tâche :
d'abord tu dis :"Si tes octets sont en BGRA comme les TColor ..."
et ensuite tu écris :"TColor: RGBA"

Ah oui aussi : je croyais que les TColors étaient en tripe et non en quad ????

et pour courroner le tout même les déclaration dans Windows.pas ne sont pas très claire :

TRGBTriple est déclaré en BGR
TRGBQuad   est aussi en BGR plus l'alpha chanel

  tagRGBTRIPLE = packed record
    rgbtBlue: Byte;
    rgbtGreen: Byte;
    rgbtRed: Byte;
  end;
  TRGBTriple = tagRGBTRIPLE;

  tagRGBQUAD = packed record
    rgbBlue: Byte;
    rgbGreen: Byte;
    rgbRed: Byte;
    rgbReserved: Byte;
  end;
  TRGBQuad = tagRGBQUAD;

Bon sur ce ... je vais me prendre une aspirine ... lol
@+
Cirec

signaler à un administrateur
Commentaire de cirec le 20/02/2007 17:06:19 administrateur CS

tu parles certainement de ceci:
const
  clSystemColor = $FF000000;

Mais là un autre problème me tracasse ... Sachant que l'interval de TColor est:
  TColor = -$7FFFFFFF-1..$7FFFFFFF;
et que clSystemColor est en dehors de cet interval ...
comment Delphi fait-il pour résoudre ce qui suit :
  clScrollBar = TColor(clSystemColor or COLOR_SCROLLBAR);

ps : moi aussi je pensais avoir saisi la chose ... mais je suis forcé d'avouer que je patauge de plus en plus ...

Et du coup, mon mal de tête ne cesse de s'acroitre ... lol

signaler à un administrateur
Commentaire de ThWilliam le 20/02/2007 19:20:09

@Cirec et Florent : bon, je vous laisse à vos maux de tête (bien que ce ne soit pas sans intérêt).

@Florent : oui, on peut déclarer Filter: array[-1..1, -1..1] of Integer et se passer de la constante IRat. Le traitement serait même apparemment un milli-poil plus rapide.

signaler à un administrateur
Commentaire de Francky23012301 le 20/02/2007 21:31:33

@Florenth : "quelle idée de capturer une webcam à partir du presse-papier".

Réponse : pour éviter de créer un fichier bitmap en dur sur le HDD.

En meme temps ca ne justifie pas que sans le filtre j'ai une totale fluidité alors qu'avec le filtre, le temps global est multiplié par 33.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Graphique sur un TEdit [ par magicvinni ] Bonjour, j'ai un dessin sur la fond de ma fiche et un TEdit dessus mais invisible au debut de l'application. Quand je veux faire un rectangle sur le f Selection graphique [ par jlg75 ] Pb sur mon prog de dessin (DAO). Je souhaite acceder à l'information au niveau pixel pour selectionner l'entite auquel il appartient (cercle,ligne..et Aperçu graphique [ par jlg75 ] ss quelle forme est stocké l'aperçu qui apparait dans la fenetre de dialogue d'ouverture de fichier de Windows? S'agit-t-il d'un bitmap (ou autre form Commande pour obtenir le nom de sa carte graphique et son ? [ par orelien ] Bonjour,J'aimerais connaître la commande pour obtenir le type de carte graphique et son de mon pc...Merci.Orelien. Graphique [ par sergejb ] SergeJbComment écrire un texte vertical (bas vert haut, ou haut vers bas) avec les méthodes textout, sur un canvas, avec ne fonte vectorielle ou non. Graphique [ par Faust ] Quel est le moyen le plus simple sous delphi pour tracer une courbe ou une droite dans un repère, exactement comme avec une calculatrice graphique.Mer Comment faire un graphique [ par Lotusbleu ] Bonsoir,J'ai saisi des données avec la fonction StringGrid et j'aimerai faire la moyenne de ces données et de representer ces données dans un graphiqu Comment faire un graphique [ par Lotusbleu ] Bonjour,J'ai fais un tableu avec StringGrid, avec deux colonnes qui signifi les matières et six lignes qui signifi les noms des élèves et pour chaque composant graphique [ par calou34 ] je voudrais savoir s'il existe un composant Flèche qui aurait les même fonctionnalité que les flèche existant dans le logiciel VISIO, si possible avec Aspect graphique d'un programme... [ par mentral ] Bonjour à tous ! Voilà, j'en ai marre des programmes grisâtres et préformatés Windows, et j'aimerais savoir s'il est possible sou Delphi de mettre une


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,390 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.