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

Caribensila
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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 !
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 !
|
|
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
Livres en rapport
|
Derniers Blogs
[RIA SERVICES] MAITRE - DéTAIL ET DOMAINDATASOURCE[RIA SERVICES] MAITRE - DéTAIL ET DOMAINDATASOURCE par Audrey
A l'occasion d'un projet client, j'ai utilisé RIA Services avec Silverlight 3 (mais cela fonctionne aussi avec la version 4), et je l'ai utilisé pour une interface façon Maitre / Détail. Voici comment j'ai procédé pour arriver à mes fins. Nous allons pren...
Cliquez pour lire la suite de l'article par Audrey CSDL FUNCTIONCSDL FUNCTION par Matthieu MEZIL
Dans mon post précédent , j'ai utilisé une CSDL Function afin de générer une requête SQL avec un DateDiff utilisant la date courante sur la BD à partir d'une requête LINQ. Dans le cadre de ce post , vous avez probablement remarqué que dans le cadre de plu...
Cliquez pour lire la suite de l'article par Matthieu MEZIL LINQ TO ENTITIESLINQ TO ENTITIES par Matthieu MEZIL
Cette semaine je suis à Montréal en tant que speaker sur Entity Framework pour l'évènement confoo . J'en profite pour remercier les organisateurs de cet évènement de m'avoir fait confiance et Access-IT de m'avoir permis d'y participer. En parallèle, j'ai ...
Cliquez pour lire la suite de l'article par Matthieu MEZIL FAIRE APPARAITRE L'ONGLET 'DéVELOPPEUR' DANS OFFICE 2010FAIRE APPARAITRE L'ONGLET 'DéVELOPPEUR' DANS OFFICE 2010 par neodante
La nouvelle interface d'Office 2010 à amener quelques modifications par rapport à celle de 2007. Certes mineures, ces modifications ont fait disparaître la case à cocher de l'onglet 'Développeur' en première page du panneau du 'bouton Office' (dans Office...
Cliquez pour lire la suite de l'article par neodante [ASTUCE] PATCH POUR MICROSOFT FORUMS NNTP BRIDGE V1[ASTUCE] PATCH POUR MICROSOFT FORUMS NNTP BRIDGE V1 par pierre
Si vous avez téléchargé comme moi Microsoft Forums NNTP Bridge V1 avant le 11 mars 2010 (voir [Astuce] Disponibilité de Microsoft Forum NNTP Bridge Version 1.0), un problème de date localisée pour les non anglais était présent. Un patch est disponibl...
Cliquez pour lire la suite de l'article par pierre
Forum
RE : APPLICATIONSRE : APPLICATIONS par aminazineb
Cliquez pour lire la suite par aminazineb
Logiciels
Xilisoft Convertisseur Vidéo Ultimate (5.1.39.0305)XILISOFT CONVERTISSEUR VIDéO ULTIMATE (5.1.39.0305)Xilisoft Convertisseur Vidéo Ultimate est un outil puissant de conversion vidéo, facile à utilise... Cliquez pour télécharger Xilisoft Convertisseur Vidéo Ultimate Xilisoft DVD Ripper Ultimate (5.0.64.0304)XILISOFT DVD RIPPER ULTIMATE (5.0.64.0304)Xilisoft DVD Ripper Ultimate est un logiciel excellent pour copier et convertir DVD vers presque ... Cliquez pour télécharger Xilisoft DVD Ripper Ultimate Rigs of Rods (63.3)RIGS OF RODS (63.3)c'est un jeu de multi-simulation camions,autobus voitures, avions, bateaux, hélicoptère avec défo... Cliquez pour télécharger Rigs of Rods Konvertor (4.00)KONVERTOR (4.00)Le logiciel est un gestionnaire multimedia affichant, jouant et convertissant plus de 2000 format... Cliquez pour télécharger Konvertor
|