begin process at 2010 02 10 06:39:46
  Trouver un code source :
 
dans
 
Accueil > Forum > 

Delphi

 > 

Système

 > 

Mémoire

 > 

Performances et pointeurs.


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

Performances et pointeurs.

jeudi 29 mai 2008 à 17:46:12 | Performances et pointeurs.

Caribensila

Membre Club

Bonjour M'sieurs'Dames,

Je suis en train d'essayer de combler une de mes nombreuses lacunes en prog' en tentant de dompter les pointeurs sous Delphi.
Pour cela, je fais des tests dans tous les sens.
Voici un de ces tests concernant ScanLine.
Ca marche, mais mon problème est que je ne comprends pas pourquoi.

Ce test ne fait que transformer une image couleur en niveaux de gris :

{Méthode ScanLine "classique".}
procedure TForm1.btnScanLineClick(Sender: TObject);
  type pRGBArray = ^TRGBArray;
       TRGBArray = ARRAY[0..0] OF TRGBTriple;
  var Bmp : TBitMap;
      Row : pRGBArray;
      X,Y : Integer;
      R,G,B,Grey : Byte;
      StartTime, EndTime : Int64;
begin
Bmp := TBitMap.Create;
try
  Bmp.LoadFromFile(ChangeFileExt(Application.ExeName,'.bmp'));
  Image1.Picture.Bitmap.Assign(Bmp);
  QueryPerformanceCounter(StartTime);
  for Y := 0 to Bmp.Height-1 do begin
    Row := Bmp.ScanLine[Y];
    for X := 0 to Bmp.Width-1 do begin
      R := Row[X].rgbtRed;
      G := Row[X].rgbtGreen;
      B := Row[X].rgbtBlue;
      Grey := (R+G+B) div 3;
      Row[X].rgbtRed := Grey;
      Row[X].rgbtGreen := Grey;
      Row[X].rgbtBlue := Grey;
    end;
  end;
  QueryPerformanceCounter(EndTime);//environ 7300 Kticks.
  Image2.Picture.Bitmap.Assign(Bmp);
  Label1.Caption := Format('%.0n KCycles',[(EndTime-StartTime)*0.001]);
finally Bmp.Free; end;
end;


{ScanLine préalable de TOUT le Bitmap dans un tableau de pointeurs.}
procedure TForm1.btnTestAClick(Sender: TObject);
  type pRGBArray = ^TRGBArray;
       TRGBArray = ARRAY[0..0] OF TRGBTriple;
  var Bmp : TBitMap;
      MonTab : Array of pRGBArray;// ça, c'est nouveau!
      X,Y : Integer;
      R,G,B,Grey : Byte;
      StartTime, EndTime : Int64;
begin
Bmp := TBitMap.Create;
try
  Bmp.LoadFromFile(ChangeFileExt(Application.ExeName,'.bmp'));
  QueryPerformanceCounter(StartTime);

  SetLength(MonTab,Bmp.Height); //On remplit d'abord tout le tableau dynamique.
  for Y := 0 to Bmp.Height-1 do MonTab[Y] := Bmp.ScanLine[Y];

  for Y := 0 to Bmp.Height-1 do begin //..puis on accède à chaque pixel par ce tableau.
    for X := 0 to Bmp.Width-1 do begin
      R := MonTab[Y]^[X].rgbtRed; //ou R := MonTab[Y,X].rgbtRed;
      G := MonTab[Y]^[X].rgbtGreen;
      B := MonTab[Y]^[X].rgbtBlue;
      Grey := (R+G+B) div 3;
      MonTab[Y]^[X].rgbtRed := Grey;
      MonTab[Y]^[X].rgbtGreen := Grey;
      MonTab[Y]^[X].rgbtBlue := Grey;
    end;
  end;
  QueryPerformanceCounter(EndTime);//environ 5500 Kticks.
  Image3.Picture.Bitmap.Assign(Bmp);
  Label2.Caption := Format('%.0n KCycles',[(EndTime-StartTime)*0.001]);
finally Bmp.Free; end;
end;

Je ne comprends pas pourquoi ma 2ème méthode est environ 25% plus rapide que la méthode ScanLine classique. En effet, dans les 2 méthodes, on parcourt toutes les lignes du Bmp pour les scanner une à une.
Pourquoi l'accès à chaque pixel est plus rapide en passant par un tableau?
'doit y avoir une histoire de gestion de la mémoire la-dessous, non?

Si une âme charitable pouvait m'allumer la lampe à Eugène ce serait sympa car je sens confusément que je n'ai encore rien compris à ces foutus pointeurs.

jeudi 29 mai 2008 à 18:13:36 | Re : Performances et pointeurs.

f0xi

Membre Club Administrateur CodeS-SourceS
Réponse acceptée !


normal, l'accés a Scanline du Bitmap est assé long...
donc acceder a scanline a chaque boucle est long.

en faisant un tableau de ptr avant, permet donc de gagner un peu de temps


sinon voici les algo que j'utilise :

type
  pScanLine = ^TScanLine;
  TScanLine = array[0..32767] of integer;
  ByteQuad  = array[0..3] of byte;
  ByteTri   = array[0..2] of byte;
  pInt64    = ^Int64;

var
  BmpBuffer : TBitmap;

{ ------------------------------------------------------------------------ }

procedure Max(const p : pByte; const A,B,C : byte);
begin
  if (A > B) and (A > C) then
     p^ := A
  else
  if (B > C) then
     p^ := B
  else
     p^ := C;
end;

procedure Min(const p : pByte; const A,B,C : byte);
begin
  if (A < B) and (A < C) then
     p^ := A
  else
  if (B < C) then
     p^ := B
  else
     p^ := C;
end;

procedure Clamp(const p : pByte; const Val,aMin, aMax : integer);
begin
  if Val < aMin then p^ := aMin else
  if Val > aMax then p^ := aMax else
                     p^ := Val;
end;

{ ------------------------------------------------------------------------ }

procedure GrayByMinMax(src, dest : TBitmap; const pCycles: pInt64 = nil);
var X,Y   : integer;
    PCS,PCE : int64;
    pScan : pScanLine;
    Pix   : ByteQuad;
    Bo,Bm,Bx : byte;
begin
  QueryPerformanceCounter(PCS);
  Src.PixelFormat  := pf32Bit;
  Dest.PixelFormat := pf32Bit;
  Dest.Assign(Src);
  for Y := 0 to Dest.Height-1 do begin
      pScan := Dest.ScanLine[Y];
      for X := 0 to Dest.Width-1 do begin
          Pix := ByteQuad(pScan[X]);
          Max(@Bx,Pix[0],Pix[1],Pix[2]);
          Min(@Bm,Pix[0],Pix[1],Pix[2]);
          Bo := (Bx + Bm) shr 1;
          pScan[X] := (Bo shl 16) or (Bo shl 8) or (Bo);
      end;
  end;
  QueryPerformanceCounter(PCE);
  if pCycles <> nil then
     pCycles^ := PCE-PCS;
end;

{ ------- }

procedure GrayByRGBAverage(src, dest : TBitmap;
const pCycles: pInt64 = nil);
var X,Y   : integer;
    PCS,PCE : int64;
    pScan : pScanLine;
    Pix   : ByteQuad;
    Bo    : byte;
begin
  QueryPerformanceCounter(PCS);
  Src.PixelFormat  := pf32Bit;
  Dest.PixelFormat := pf32Bit;
  Dest.Assign(Src);
  for Y := 0 to Dest.Height-1 do begin
      pScan := Dest.ScanLine[Y];
      for X := 0 to Dest.Width-1 do begin
          Pix := ByteQuad(pScan[X]);
          Bo  := (Pix[0] + Pix[1] + Pix[2]) div 3;
          pScan[X] := (Bo shl 16) or (Bo shl 8) or (Bo);
      end;
  end;
  QueryPerformanceCounter(PCE);
  if pCycles <> nil then
     pCycles^ := PCE-PCS;

end;

{ ------- }

const
  LumRed   = 0.2125;
  LumGreen = 0.7154;
  LumBlue  = 0.0721;

function Lum(const color : integer) : integer;
var
  LC : integer;
begin
  LC := round( (byte(Color)*LumRed) +
               (byte(Color shr 8)*LumGreen) +
               (byte(Color shr 16)*LumBlue)
             );
  if LC > 255 then
    LC := 255
  else
  if LC < 0 then
    LC := 0;
  result := integer(LC or (LC shl 8) or (LC shl 16));
end;

{ ------- }

procedure TrueGrayScale(Src : TBitmap; Dest : TBitmap; 
const pCycles: pInt64 = nil);
var
  PCS,PCE : int64;
  X,Y   : integer;
  pScan : pScanLine;
begin
  QueryPerformanceCounter(PCS);
  Src.PixelFormat := pf32bit;
  Dest.Assign(Src);
  for Y := 0 to Dest.Height-1 do
  begin
    pScan := Dest.ScanLine[Y];
    for X := 0 to Dest.Width-1 do
      pScan[X] := Lum(pScan[X]);
  end;
  QueryPerformanceCounter(PCE);
  if pCycles <> nil then
     pCycles^ := PCE-PCS;

end;







jeudi 29 mai 2008 à 19:22:47 | Re : Performances et pointeurs.

f0xi

Membre Club Administrateur CodeS-SourceS
Réponse acceptée !

en fait, voila le code que l'on appel avec ScanLine :

-> Scanline[Y]
  -> GetScanline
    -> Changing
    -> condition de verification des limites
    -> DibNeeded
    -> GDIFlush
    -> Retour du pointeur





jeudi 29 mai 2008 à 19:23:18 | Re : Performances et pointeurs.

Caribensila

Membre Club
Merci pour les algo, f0xi. Ca va me donner du grain à moudre... 

Cependant, je crois qu'il y a quand même un truc qui nous échappe, là...
Tu dis : « Normal, l'accès a Scanline du Bitmap est assez long... donc acceder a scanline a chaque boucle est long. »

Mais si je fais :

NB: l'image fait 320x240 pixels pour éviter les ajustements de fin de ligne !!!

Row := Bmp.ScanLine[239]; // 1 seul appel à ScanLine au début du Bmp (coin inf. gauche).
for X := 0 to 76799 do begin // 76799 = 320 x 240  -  1
   R := Row[X].rgbtRed;
   G := Row[X].rgbtGreen;
   B := Row[X].rgbtBlue;
   Grey := (R+G+B) div 3;
   Row[X].rgbtRed := Grey;
   Row[X].rgbtGreen := Grey;
   Row[X].rgbtBlue := Grey;
end;

Ca donne les perfs les plus décevantes!
Il n'y a qu'1 seul appel à ScanLine[] et c'est la plus lente de toutes les méthodes ! ! !

J'suis tj dans le brouillard, quoi... 

jeudi 29 mai 2008 à 21:02:03 | Re : Performances et pointeurs.

florenth

Membre Club
Réponse acceptée !
Salut !
As-tu vu mon code source sur le traitement archi-extra-giga-bref-rapide des bitmaps via scanline ?

Le problème du Row[2X], c'est que chaque emploi demande au CPU de faire l'addition (@Row + X * SizeOf(TRGBTriple)) et de renvoyer le résultat. Et tu l'emploie 6 fois par pixel !

Alors qu'en faisant :

var
  Pix: PRGBTriple;
begin
  Pix := Bmp.ScanLine[239];
  for X := 0 to 76799 do
  begin
   Grey := (Pix^.rgbtRed + Pix^.rgbtGreen + Pix^.rgbtBlue) div 3;
   Pix^.rgbtRed := Grey;
   Pix^.rgbtGreen := Grey;
   Pix^.rgbtBlue := Grey;
   Inc(Pix);
  end;
end;

Là, tu as une addition par pixel, au lieu de 6, puisque l'usage d'un pointeur direct sur la mémoire à changer permet d'économiser le temps d'accès que Delphi génère avec ses foutus pseudos-pointeurs-de-tableaux infinis (le array[0..0] est supra lent).
jeudi 29 mai 2008 à 21:05:05 | Re : Performances et pointeurs.

florenth

Membre Club
Réponse acceptée !
Enfin, pour l'exemple complet, voir ici : http://www.delphifr.com/codes/BON-USAGE-SCANLINE_43222.aspx

Pourvu que ça serve !
jeudi 29 mai 2008 à 21:54:55 | Re : Performances et pointeurs.

Caribensila

Membre Club
Salut Flo,

« http://www.delphifr.com/codes/BON-USAGE-SCANLINE_43222.aspx
Pourvu que ça serve !
»

Ton exemple... je l'ai imprimé et, de plus, il trône sur ma table de nuit !  Mais il semble que mon niveau ne me l'a pas fait apprécier à 100%. J'aurais eu besoin d'un "vrai" tuto sur les pointeurs en même temps je crois. Désolé.  

En tout cas, merci à toi et à f0xi pour mes nouvelles connexions neuronales. J'ai eu un brusque éclair de compréhension grâce à vous!  

Y'a plus qu'à attendre la pousse des axones... 

vendredi 30 mai 2008 à 11:40:40 | Re : Performances et pointeurs.

ThWilliam

Membre Club
Réponse acceptée !
Salut.

Tests faits sur gros bitmaps avec le code de Florent en n'appelant qu'1 x Scanline et en incrémentant Pix.
C'est environ 2x plus rapide que la méthode classique (appel à Scanline pour chaque ligne du bitmap).
De plus, pour peindre un bitmap dans une couleur uniforme, c'est tout aussi rapide que Bmp.Canvas.FillRect ! 
Dès lors,  n'a-ton pas atteint l'optimisation maximale sous Delphi ?
vendredi 30 mai 2008 à 13:52:39 | Re : Performances et pointeurs.

Caribensila

Membre Club
Salut,

« Dès lors,  n'a-ton pas atteint l'optimisation maximale sous Delphi ? »
Oui, si on considère que Bmp.Canvas.FillRect est le nec plus ultra en matière d'optimisation.

J'entrevois cependant une posibilité d'encore diminuer le temps de traitement par deux (au moins théoriquement) :

A la condition de disposer d'un Multi Core, c'est de faire une moitié du traitement dans un Thread et l'autre moitié dans un autre Thread.
La difficulté étant de partager un Bmp entre 2 Threads.  Mais ça doit être jouable.
En tout cas, ça vaut le coup d'explorer cette voie car cette technique du multi-threading dans un environnement MultiCore est applicable à tout traitement long.

Mais tout cela m'éloigne de ma préoccupation actuelle que sont les pointeurs et ça ne répond toujours pas à ma première question : « Pourquoi l'accès à chaque pixel est plus rapide en passant par un tableau? ».   

vendredi 30 mai 2008 à 13:55:07 | Re : Performances et pointeurs.

Kenavo

Réponse acceptée !
http://photos.scc.asso.fr/albums/userpics/thumb_1159279319.jpg

Le pointer est assez performant à la chasse, mais ses longues périodes d'arrêt font qu'il n'est pas si rapide que ça ! Finalement !
Tout bien pesé !

Ken@vo

Code, Code, Codec !


1 2 3

Cette discussion est classée dans : end, bmp, row, montab, grey


Répondre à ce message

Sujets en rapport avec ce message

Problème de procedure [ par lapucedu88 ] Voilà je crée une procedure de cette forme : Procedure initordi( chiffre : integer; ordi : TImage; chaine : String );Begin  Case chiffre Of    0 :     Message de sauvegarde [ par cincap ] Bonjour à tous,Est t'il possible de mettre un message d'avertissement au cas ou le fichier bmp ou jpg existerait avant de sauvegarder le nouveau fichi Utiliser un TopenPictureDialog [ par cincap ] Bonjour,Je cale sur une application qui charge des images au format Bmp en créant une liste avec un Tcombobox, avant de pouvoir appliquer un effet, se Envoye d'un BMP par les composants Indy sur un serveur [ par Francky23012301 ] Salut à tous, J'ai un bmp que je souhaite transferer sur un serveur par les composants Indy. Je vous copie ma source : procedure TForm1.sendstr; var Pb de conversion emf vers jpg de grandes images [ par macpc ] Bonsoir à tous,Je suis confronté au problème suivant lors de la conversion de grandes images emf vers jpg, j'obtiens une erreur endofressources:Po [Erreur Composant] [ par Bacterius ] Bonsoir, voici un cas fort interessant ... et bizarre. Je prépare un composant graphique descendant de TGraphicControl, une sorte de progressbar pour Thread [ par barbichette ] Bonjour lecteurs de ce poste J'ai un petit souci avec les threads... J'ai un thread plus que classique avec un traitement d'une image assez long. D'où probleme de skin [ par thone08 ] Bonjour voila j'aimerai realiser un programme ki kand on passe sur le coter gauche sa ouvre un panneau . Pour cela j'ai tester la fonction suivant mai Besoin d'aide sur un pb de débutant. Trouvez les max et le min de 7 entiers [ par patou248 ] Voici mon pb.Parmi 7 entiers: A,B,C,D,E,F,GTrouvez les 6 premiers maximums et le min ou si vous préférez les 7 maximums.J'ai le bout de code suivant p utilisation threads [ par milomax91 ] Bonjour a tous [^^clinoeil1], J'ai un petit problème, je suis sur la création d'un jeux assez simple. Animaux qui ce promène sur un fond d'écran et o


Nos sponsors


Sondage...

CalendriCode

Février 2010
LMMJVSD
1234567
891011121314
15161718192021
22232425262728

Consulter la suite du CalendriCode

 
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

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,874 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales