AUSSI PRATIQUE QUE CANVAS.PIXELS[ ] MAIS JUSQU'À 450 FOIS PLUS RAPIDE (GRÂCE À S

Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 - 11 août 2010 à 11:58
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013 - 1 sept. 2010 à 12:49
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/52162-aussi-pratique-que-canvas-pixels-mais-jusqu-a-450-fois-plus-rapide-grace-a-scanline

blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
1 sept. 2010 à 12:49
L'histoire du TThread : c'est une idée pour ceux qui aiment l'animation graphique...puisque cela mets le même temps d'éxécution....

Quand à pourquoi des sources, des sources et d'autres sources ?

1) mieux vaut des bombes que des sources ?
2) on apprends tous les jours que le Seigneur fait
3) la gestion (le pascal) à beaucoup à apprendre de Windows (les messages/Delphi) !

:)
cs_LePetitCurieux Messages postés 7 Date d'inscription jeudi 29 octobre 2009 Statut Membre Dernière intervention 23 novembre 2010
1 sept. 2010 à 04:57
Finalement je doit être comme tu la mentionné un peut borderline.
Mais fait gaffe à l'adiction :) c'est un des symptomes.
Je me suis emporté je pense après coups.
Je vous respectes plus loin que mes paroles.
Mais dès fois fo remuer le truc pour savoir.

A Bientôt.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
1 sept. 2010 à 04:22
Moi, je vais développer.

je suis revenu à la programmation sur le tard, avec Java, en tant qu'opticien.
J'ai tout de suite participé à un projet énorme ( http://antares.in2p3.fr/Apercu/index_fr.html ). Les universitaires ne jurent que par Java (j'ai pas encore compris pourquoi).

Malgré cela, je n'ai jamais trouvé une communauté de programmeurs plus "partageuse" et "efficace" que celle du Pascal et de Delphi. J'ai tout de suite abandonné Java pour Delphi, et j'ai tout appris sur ce site.

Maintenant que j'en sais un peu plus, j'essaie de partager. D'autres l'ont fait avant moi, delphiprog, nono40, etc...

Avec Cirec, Bacterius, et bien d'autres on fait de notre mieux et je trouve injuste de dire qu'on enterre Delphi.

Pour moi, Delphi est actuellement victime de son efficacité et de sa simplicité pour développer des BDD par des pollueurs sauvages qui n'ont aucune notion de la logique.

J'espère simplement que ce ne seront pas eux qui feront oublier les vertus du Pascal et la fraternité de notre communauté.
cs_LePetitCurieux Messages postés 7 Date d'inscription jeudi 29 octobre 2009 Statut Membre Dernière intervention 23 novembre 2010
1 sept. 2010 à 03:06
@Caribensila :01:38:54
Oki, mais il existe aussi les Anti-borderline.
Faute de piles dans mon key sans fil (et c'est vrai). Je n'ai pas eu la possibilité de dire que :
Mr Caribensila and Mr cirec OKI vous êtes pas mes cibles.

Mon débat etait plus sur... Oki les sources , mais pour qui et pour quoi ?
Le débat sur la source... Pour qui et pour quoi ?
Je pense que vous vous mettez sous terre, que vous mettez le pascal sous terre, voila.
C'est ma pensée, je ne dit pas que cela est la véritée.
Mais je constaste :
1 - Pascal ou Delphi. Bof pas de fréquentation.
2 - Les gars qui viennent, ben c'est juste du tech, du DUT d'la recherche.
3 - Le pascal ben on a l'impression que c'est un langage juste de test.
.....

je vais pas développer.

Amicalement
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
1 sept. 2010 à 02:07
Pour ce qui concerne mes motivations (bien que ça ne regarde que moi, et certainement pas le dernier excité venu), je précise que ce source sert à compléter ce tuto qui, perso, me semble très didactique mais cependant incomplet :

http://nono40.developpez.com/tutoriel/delphi/efg/scanline/#LV-A
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
1 sept. 2010 à 01:38
cs_LePetitCurieux Messages postés 7 Date d'inscription jeudi 29 octobre 2009 Statut Membre Dernière intervention 23 novembre 2010
1 sept. 2010 à 01:14
Et le Inline ???
et pquoi pas l'assembleur ???
Dommage que bacterius participe pas. On aurait été jusqu'a la lune.
Le Inline ben nan on s'ecarte trop hein...
L'assembleur ben nan c'est pas du pascal hein...
Pour le Bacterius ben non, lui c'est les chiffres...
Ya bien Mauri qui quand il n'améliore pas ses composants type led qui clignotent coopt au débats.

Ce source il sert à coa???
Il sert a coa: à promouvoir delphi? Il sert a coa : à promouvoir la prog ???

Rien de tout cela, il sert a promouvoir la personne...

Deception, désastre, honte. Oui j'ai honte d'avoir soutenu ce site delphi.fr. Honte d'avoir cru que ce language était didactique. Honte et décu.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
31 août 2010 à 21:59
Ouais. C'est bien ce qu'il me semblait. Merci Cirec.

D'autre part il y a un très gros écueil à éviter lorsqu'on threade une application à tire-larigot, c'est l'atterrissage des Threads dans le process principal qu'il faut à tout prix sécuriser (même quand ils n'ont pas besoin d'être synchronisés). Et nous en avons un très bon exemple ici. En effet, rien n'empêche un autre Thread d'avoir redimensionné le Bitmap entre temps ou même pire, de l'avoir supprimé. Si c'est pas prévu, ça peut faire mal. Et tout prévoir c'est gourmand (si jamais c'est possible!). ;)
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
31 août 2010 à 19:56
"C'est le contraire : le temps d'éxécution du thread est amputé sur celui de Windows"
oui je me suis mal exprimé ... çe que je veux dire c'est que ce temps n'est pas exponentiel il dépend du nombre de Thread déjà crées et de leurs priorités donc plus il y a de Threads moins il reste de temps système disponible à partager.

bon sinon, j'ai mis le code dans un Thread et comme il n'y a qu'un affichage à la fin du traitement pas besoin de synchroniser :

pour 10 000 itérations:
on enregistre les mêmes variations pour les deux
testé en Priority: tpNormal, tpHigher, tpHighest, tpTimeCritical

peu importe la priorité le temps d'exécution reste le même que le code soit dans le Thread principale de l'application où dans un Thread à part !!
et c'est logique .. le Thread ne peut pas accélérer l'exécution du code quand il est unique ... pour que l'utilisation d'un Thread soit justifié et visible il faudrait au moins avoir à faire deux traitements simultanément.
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
31 août 2010 à 19:55
"L'algorithme ci-dessous qui n'utilise qu'une fois Scanline par Bitmap a été trouvé sur un site américain il y a 3 ans :"
ça ça n'a rien de nouveau !!

par contre le code que tu proposes n'est pas optimisé ... du tout(trop de calcules inutiles dans les boucles) à chaque passage tu recalcules la position de chaque pixels "DeltaLigne + (x * 4 + 0)" !!
l'astuce du code de Caribensila réside dans l'utilisation et l'incrémentation de l'adresse pointeur(donc un entier) de la valeur de "BytesPerPix" ... une simple addition ... rien que ça te ralenti l'exécution du code ...
pour s'en rendre compte il suffit d'appliquer le même traitement à l'image que celui de l'exemple, le même nombre de fois et de comparer les résultats

autre "problème" le code que tu proposes ne traite que le 32bit
dans le code de Caribensila le format de départ de l'image est conservé qu'il soit en 24 où 32bit son format ne change pas. Dans ton code si je donne un Bmp 32bit en entrée je récupère un 24Bit en sortie !! :(
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
31 août 2010 à 16:17
Je m'aperçois que les variables globales ne sont pas une bonne idée :s
Il faudrait les rafraîchir de temps en temps car le tampon mémoire n'est pas garanti comme étant cohérent.
Mais ce n'est qu'un exemple...
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
31 août 2010 à 16:08
@media38
C'est bien plus vieux que ça ! :)
La technique a été développée par Danny Thorpe (Borland R&D) lors de l'écriture de la classe TJPEGImage et que je cite dans mon intro.
Pour ceux que ça intéresse, voir le très instructif tuto en français de nono40 :
http://nono40.developpez.com/tutoriel/delphi/efg/scanline/#LV-A


Mais il semble que vous ayez tous perdu de vue le principal avantage de mon algo. C'est qu'il travaille sur un pixel donné et pas forcément sur toute la surface du Bitmap (pour faire ça, j'aurais employé une autre technique).
Mon post est sans doute trompeur de ce point de vue, mais il fallait bien faire un test de comparaison de perf'. En fait, le plus souvent, il n'est même pas nécessaire de créer un Bitmap de travail.

Voici un exemple opérationnel et très simple (une fiche, un TImage et un TButton). Un clic sur le bouton dessine un pixel aléatoire directement sur l'image, et pas besoin de Bitmap de travail :


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Image1 : TImage;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
end;

var
Form1: TForm1;

implementation
{$R *.dfm}

var
gScan0 : Integer; //Valeur, en Integer, de la 1ère adresse de ScanLine.
gMemLineSize : Integer; //Taille d'une ligne de pixels en mémoire (en octets).
gBytesPerPix : Integer; //Format des pixels (en octets).

procedure TForm1.FormCreate(Sender: TObject);
begin
with Image1.Picture.Bitmap.Create do begin
Width := Image1.Width;
Height := Image1.Height;
PixelFormat:= pf24bit;
end;
Image1.Refresh;
gScan0 := Integer(Form1.Image1.Picture.Bitmap.ScanLine[0]);
gMemLineSize := Integer(Form1.Image1.Picture.Bitmap.ScanLine[1])-gScan0;
gBytesPerPix := Abs(gMemLineSize div Form1.Image1.Width);
end;

procedure GetpPix(aX,aY,aScan0,Col: Integer);
begin
Inc(aScan0, aY * gMemLineSize);
Inc(aScan0, aX * gBytesPerPix);
with pRGBQuad( aScan0 )^ do begin
rgbRed := GetRValue(Col);
rgbGreen := GetGValue(Col);
rgbBlue := GetBValue(Col);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
GetpPix(Random(Image1.Width),Random(Image1.Height),gScan0,clFuchsia);
Form1.Image1.Refresh;
end;

END.
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
31 août 2010 à 13:14
>>"par contre si tu mets ça dans un Thread l'application n'est plus figée, elle répond à nouveau aux messages système "
>> "et ce temps là est pris sur le temps d'exécution du Thread"
C'est le contraire : le temps d'éxécution du thread est amputé sur celui de Windows

>>ce qui revient à faire un "Application.ProcessMessages" dans la procédure actuelle.
Pas vraiment...le thread n'a pas de file de message à proprement parler...ainsi aucun "autre" message ne sera traité avant l'ordre qui lui est donné...

>>Et pour finir peu importe la méthode utilisée dans le Thread l'affichage doit être synchronisé avec le Thread principal de l'application.
Cela devient donc un problème d'affichage !
media38 Messages postés 1 Date d'inscription samedi 6 janvier 2007 Statut Membre Dernière intervention 31 août 2010
31 août 2010 à 09:43
L'algorithme ci-dessous qui n'utilise qu'une fois Scanline par Bitmap a été trouvé sur un site américain il y a 3 ans :
procedure ExecTransfert(BmpSrc : TBitmap) ;
{---------=============-------------------}
Var
p0, p1: pbytearray;
lImage : TBitmap ;
r, g, b, x, y: Integer;
DeltaLigne : integer ;
Begin
Screen.Cursor := crHourGlass;
lImage := TBitmap.Create ;
// Forçage 32 bits pour alignement automatique des lignes sur adresse paire
lImage.PixelFormat := pf32bit;
BmpSrc.PixelFormat := pf32bit;
lImage.Width := BmpSrc.Width ;
lImage.Height := BmpSrc.Height ;
p1 := lImage.ScanLine[BmpSrc.Height - 1] ;
p0 := BmpSrc.scanline[BmpSrc.Height - 1] ;
For y := 0 To BmpSrc.Height - 1 Do
Begin
DeltaLigne :((BmpSrc.Height-y-1) * BmpSrc.width) * 4 ; // Delta Numéro ligne * taille ligne * RGB
For x := 0 To BmpSrc.Width - 1 Do
Begin
b := p0[DeltaLigne + (x * 4 + 0)];
g := p0[DeltaLigne + (x * 4 + 1)];
r := p0[DeltaLigne + (x * 4 + 2)];
// ... Application de la transformation sohaitée sur R-G-B
p1[DeltaLigne + (x * 4 + 0)] := b ;
p1[DeltaLigne + (x * 4 + 1)] := g ;
p1[DeltaLigne + (x * 4 + 2)] := r ;
End;
End;
BmpSrc.Assign(lImage);
BmpSrc.PixelFormat := pf24bit;
lImage.Destroy ;
Screen.Cursor := crDefault;
end ;
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
31 août 2010 à 01:28
a mon avis ça n'apportera rien de plus.

dans le cas présent la procédure est réduite au maximum ... de son entré à sa sortie les opérations se passent à la suite les messages système ne sont pas traités dans ce laps de temps (l'application est figée) on est dans une boucle "unique"

par contre si tu mets ça dans un Thread l'application n'est plus figée, elle répond à nouveau aux messages système et ce temps là est pris sur le temps d'exécution du Thread ce qui revient à faire un "Application.ProcessMessages" dans la procédure actuelle. Et pour finir peu importe la méthode utilisée dans le Thread l'affichage doit être synchronisé avec le Thread principal de l'application.

Un Tread n'est utile que si l'application doit continuer à réagir aux messages système et/où si l'application doit faire d'autres calcules, animations et affichages simultanément .. ce qui n'est pas le cas ici
où encore dans le cas ou la procédure utilise d'autres procédures et fonctions externes ... ce qui n'est plus le cas ici

à mon avis on risque de perdre quelques cycles en mettant cette procédure dans un Thread ... mais je ne demande qu'à voir :D
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
31 août 2010 à 00:11
Ok.
On va dire qu'on ne s'occupe pas de la mémoire consommée pour le moment :)

Je vais essayer d'essayer ta proposition dès que je peux car ça m'intrigue cette histoire de Thread. Et j'avoue que ça ne me serait jamais venu à l'esprit.
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
30 août 2010 à 23:51
Il faut bien sûr un thread adapté :

* un TBitmap de travail,
* un TBitmap de diffusion,
* et une mini-gestion des tirages : soit toutes les 33 milliseconds, soit à la demande (Suspend.Resume)...

Alors, aucun lock n'interfère, et le traiement du TBitmap se faisant en interne par le TThread, il n'y a aucune interférence dûe à l'OS...

Du côté mémoire, par contre, il se peut que se soit plus gourmand...

>> Thread est du genre "neutre" en anglais...<<
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
30 août 2010 à 15:12
En admettant que tu aies raison, BluePerfect, il faudrait gérer la synchronisation du Thread car il n'est pas question de faire un traitement dans la zone mémoire du Bitmap en même temps qu'un redimensionnement de celui-ci, par exemple. Il faudrait donc "locker" le Canvas.
Et je cite l'Aide Delphi :
« Comme Lock empêche les autres threads de s'exécuter, elle peut avoir un effet négatif sur les performances. N'appelez Lock que s'il y a un risque qu'une autre thread interfère avec l'utilisation du canevas. »

( Et c'est là que je m'aperçois que "Thread" est du féminin... ;)
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
30 août 2010 à 14:38
CARIBENSILA>>
Votre histoire de procédure "éloignée", et de gain de temps quand aux appels inter- ou intra- process, ça vous en fait gagner du temps ? Bah faire le tout dans un pending Thread aussi !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
30 août 2010 à 03:03
J'oubliais... Merci à toi, WINGEO. ;)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
30 août 2010 à 02:49
Faire mieux avec un Thread ???

Je serais curieux de voir la bête car je ne vois pas ce que peut apporter un Thread, en temps d'exécution, dans cet exemple. Et si c'est pour utiliser les possibilités d'un multicore... c'est hors sujet.
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
25 août 2010 à 10:59
On peut faire mieux en utilisant un thread... :)
wingeo Messages postés 4 Date d'inscription jeudi 1 février 2007 Statut Membre Dernière intervention 12 janvier 2011
18 août 2010 à 18:17
Bonjour

Un grand merci pour votre contribution bien utile et surtout pour le commentaire

Cordialement
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 20:31
Oui, je connais QueryPerformanceCounter.
Mais j'ai lu qu'il ne fallait pas l'utiliser pour mesurer des périodes de plus d'une seconde (sans plus d'explication).

Maintenant, j'ai lu ça dans un bouquin paru en 1999 et ce n'est peut-être plus d'actualité...
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 20:17
"Ca dépend peut-être du Delphi utilisé... "
c'est bien possible oui.

sinon pour avoir des résultats plus fins je te conseille de remplacer tous les appels à "GetTickCount" par "MyGetTickCount"

Function MyGetTickCount: Int64;
Var
lpPerformanceCount,
lpFrequency : Int64;
Begin
If Not QueryPerformanceCounter(lpPerformanceCount) Then
lpPerformanceCount := GetTickCount Else
Begin
QueryPerformanceFrequency(lpFrequency);
lpPerformanceCount := (lpPerformanceCount * 1000) Div lpFrequency
End;

result := lpPerformanceCount;
End;

ce qui permet un résultat bien plus précis ... sur 40 itérations "GetTickCount" me donne 0ms et "MyGetTickCount" donne 2ms

pour plus d'informations voir l'aide à propos de "QueryPerformanceCounter", "QueryPerformanceFrequency" & "High-Resolution Timer"
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 16:58
Il va donc falloir que je fasse des tests car j'étais persuadé que l'appel d'une méthode imbriquée était plus rapide...

Ca dépend peut-être du Delphi utilisé...

'vais tester tout ça dès que possible. C'est vrai que cette appli s'y prête bien.
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 16:33
attention ... que la procédure/fonction soit externe où interne(imbriqué) le cout est le même ... c'est l'appel à la procédure/fonction qui est couteuse.

vous pouvez aussi faire les tests le code s'y prête bien ;)

si on veut gagner en temps il faut supprimer les procédures et fonctions au maximum pour les intégrer au code. Je suis d'accord ça ne facilite pas toujours la lecture du code mais quand on a besoin de performances il y a cout à payer ... :D
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 16:17
Oups, on s'est croisé.

Bein... Une procédure c'est déjà un pointeur...
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 16:14
Voilà ! :)

Je précise que, comme toujours en matière d'optimisation, le réintégration n'est valable que dans des boucles assez longues. Sinon le gain est négligeable et ça nuit à la lisibilité...
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
12 août 2010 à 16:13
Ouhhhh laaaaa ...
divisé par 2 ça fait pas mal de temps gagné tout ça!
En effet, j' ai déjà utilisé le fait de créer une procédure dans une procédure des milliers de fois sans savoir que finalement je gagnais en temps d' exécution!

Une question con (peut être): n' y a t-il pas moyen dŽ être aussi rapide avec la procédure GetPix() sur une autre unité en utilisant un pointeur sur cette procédure (pointeur attribué dès le début de la fonction appelante et pas dans les for oú on ne fait que l'utiliser ...) ou autre?

A+
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 16:04
hahahaha :D

voici le code modifié:
{Routine utilisant le nouvel algorithme (intégré) et transformant l'image source en niveaux de gris.}

procedure PracticalTestGetpPix(Sender: TObject);
var
Start: Cardinal;
Ticks: Cardinal;
BMP: TBitmap;
Scan0: Integer; //Valeur, en Integer, de la 1ère adresse de ScanLine.
MemLineSize: Integer; //Taille d'une ligne de pixels en mémoire (en octets).
BytesPerPix: Integer; //Format des pixels (en octets).
i: Integer;
X, Y: Integer;
Grey: Integer;
// Ajout de currentScan comme valeur de pointeur courrant
CurrentScan: Integer;
begin
Screen.Cursor := crHourGlass;
BMP := TBitmap.Create;
try
BMP.Assign(Form1.imgSource.Picture.Graphic); //On travaille en mémoire.
{Initialisation des paramètres de GetpPix().}
Scan0 := Integer(BMP.ScanLine[0]); //Pointe sur la 1ère ligne du Bitmap.
MemLineSize := Integer(BMP.ScanLine[1]) - Scan0;
//MemLineSize sera le plus souvent <0 permettant ainsi de décrémenter l'adresse du pointeur de ligne-mémoire (Y).
BytesPerPix := Abs(MemLineSize div BMP.Width);
//BytesPerPix permettra d'incrémenter l'adresse du pointeur pRGBTriple en fonction de sa position dans la ligne (X).

Start := GetTickCount;
for i := 1 to LoopsCount do
begin
for Y := 0 to BMP.Height - 1 do
begin
// on se place en début de ligne
CurrentScan := Scan0 + Y * MemLineSize;
for X := 0 to BMP.Width - 1 do
begin
with PRGBQuad(CurrentScan)^ do
begin
Grey := ((rgbRed shl 1) + (rgbGreen * 5) + rgbBlue) shr 3;
rgbRed := Grey;
rgbGreen := Grey;
rgbBlue := Grey;
end;
// on incrémente de BytesPerPixel pour passer à la valeur suivante
Inc(CurrentScan, BytesPerPix);
end;
end;
end;
Ticks := GetTickCount - Start;

Form1.imgGetpPix.Picture.Graphic := BMP;
if Integer(Ticks) < Form1.btnTestGetpPix.Tag
{//On change l'affichage des résultats si nécessaire.} then
DisplayTime(Ticks, Form1.lblTimeGetpPix, Form1.shpGetpPixBar,
Form1.btnTestGetpPix);
finally BMP.Free;
end;
Screen.Cursor := crDefault;
end;

@Mauricio:

le simple fait de prendre une procédure d'en sortir une partie du code pour en faire une fonction (le tout dans la même unité) et d'y faire appel depuis la procédure augmente le temps d'exécution de cette dernière.

dans l'exemple donné ici j'ai remis la fonction "GetPix" à l'intérieur de "PracticalTestGetpPix" et rien que ça divise le temps par deux

@++
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 16:00
Oui, Mauricio.
Plus la portée est éloignée, plus c'est long.
La meilleure perf' est obtenue quand tu peux mettre la fonction appelée dans l'espace de la fonction appelante. Mais elle ne pourra bien sûr plus être appelée par d'autres routines que celle qui la contient.

Mais je crois que c'est une technique que tu as déjà employée dans un de tes codes publiés ici.

Quant au temps gagné, Cirec vient de nous montrer qu'il n'est pas négligeable.
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
12 août 2010 à 15:46
Salut à tous les 2,
désolé de m' incruster alors que je n' ai pas toujours regardé le code mais j' ai une question à propos de vos commentaires:
le fait d' appeler une fonction sur une autre unité (= fonction extérieure dans vos commentaires) prends beaucoup plus de temps que si elle était dans la même unité?
Merci de m' éclaircir sur ce point.

Maurício
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 15:24
Je savais que l'appel d'une fonction extérieure coûtait pas mal de temps... Mais, franchement, je n'imaginais pas autant.
Merci de l'avoir souligné, Cirec.
D'autant que ça ne fait que réintégrer 2 lignes de code, ce qui ne complique pas la lisibilité.

Et même plus besoin d'envisager une classe ou une unité ! :D

Ce qui a de bien avec l'optimisation, c'est que c'est jamais vraiment fini et qu'il reste toujours du grain à moudre, à condition de montrer son code aux collègues. ;)
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 15:04
oups parti trop vite,

c'est pas négligeable quand même .. non ?

petite précision : le message "Le temps écoulé (=0) n'est pas significatif ... " je l'ai avec moins de 120 itérations à partir de 120 il prend ;)
@++
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 15:00
juste pour le fun,
j'ai testé la réintégration de "GetPix" et le gain est de 50% donc deux fois plus rapide

et si j'applique cette réintégration au test optimale j'obtiens ceci:
---------------------------
Getppix
---------------------------
Le temps écoulé (=0) n'est pas significatif.
Il est conseillé d'augmenter le Nbre d'itérations par test.
---------------------------
OK
---------------------------

ce qui démontre le poids de l'appel extérieur

le but c'est pas de rester correcte vis-à-vis de Canvas.Pixel :p
mais bien la facilité et la rapidité d'accès grace à 1 seul appel à ScanLine

moi j'ai rapport de (Test1 / Test2) de 1011 pour 120 itérations !!
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
12 août 2010 à 13:07
C'est une question de principe. Un test ça coûte toujours quelque chose.
Un sou, c't'un sou. Une ms, c'est une ms (t'as qu'à demander aux coureurs de 100 mètre). lol

Tu as raison, il faudrait mieux réintégrer la fonction.
Cependant, dans le test présenté ici, ce n'aurait pas été honnête vis-à-vis de Canvas.Pixels.

Radin, mais loyal le Cari ! ;)
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
12 août 2010 à 12:18
"Par contre le test est inutile ( j'en ai déjà assez bavé pour éliminer tous les tests de cet algo à cause des perf' pour en ajouter de nouveaux! lol )"

euh ... 31ms pour 40 itérations avec où sans le test !!

si tu veux encore gagner un peu de temps il faudrait réintégrer la fonction "GetPix" à la procédure de transformation ... les appels à une fonction extérieur coutent beaucoup plus cher en temps que ce petit test !! ;)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
11 août 2010 à 18:44
Oui. Nous arrivons à la même méthode :)

Par contre le test est inutile ( j'en ai déjà assez bavé pour éliminer tous les tests de cet algo à cause des perf' pour en ajouter de nouveaux! lol )

Pourquoi ?
- Parce que si le programmeur veut utiliser le rgbReserved, il devra de toute façon s'assurer que le Bitmap est un 32 bits; et s'il ne l'est pas faire la conversion vers pf32bit (donc pas de problème).
Et s'il ne veut pas utiliser le canal, il ne travaillera que sur les 3 couleurs (que ce soit 24 ou 32 bits), donc il ignorera le rgbReserved.
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
11 août 2010 à 17:42
"Y'a un autre truc qui peut être un peu embêtant, c'est de ne pas avoir accès au canal alpha pour les 32 bits. Je vais essayer de rectifier le tir sans perdre trop de perf'."

passe donc tout de suite par un pointeur sur RGBQuad !!!

function GetpPix(aX, aY, aBytesPerPix, aMemLineSize, aScan0: Integer): pRGBQuad;
begin
Inc( aScan0, aY * aMemLineSize ); //Incrémente aScan0 du nombre d'octets d'une ligne-mémoire * Y (NB: aMemLineSize est en fait le plus souvent négatif(Bottom-Up DIB)).
Inc( aScan0, aX * aBytesPerPix ); //Incrémente aScan0 du nombre d'octets d'un pixel * X.
Result := pRGBQuad( aScan0 );//Transtype aScan0 en pRGBTriple pour avoir accès aux composantes-couleur.
end;

et en utilisation:

with GetpPix(X, Y, BytesPerPix, MemLineSize, Scan0)^ do begin //Renvoie un pointeur pRGBTriple.
Grey := (rgbRed shl 1 + rgbGreen * 5 + rgbBlue) shr 3; //(R*2 + G*5 + B) div 8 (gris avec correction de luminance optimisée).
rgbRed := Grey;
rgbGreen := Grey;
rgbBlue := Grey;
if BytesPerPix = 4 then
rgbReserved := 0;
end;

il faut juste penser a tester "BytesPerPix = 4" avant d'utiliser "rgbReserved" où carrément l'ignorer
mais si tu l'utilises avec "BytesPerPix = 3", tel que dans l'exemple, l'image sera noir ;)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
11 août 2010 à 13:57
Pour le pf16bit, ça ne doit pas poser de problème. Par contre, pour les formats palettisés, je sais pas... J'ai jamais compris grand'chose au système de palettes Windows. Mais c'est peut-être l'occasion de m'y mettre si je trouve un bon tuto... Mais, de toute façon, je ne suis pas partisan d'y parvenir en faisant une simple conversion.
Y'a un autre truc qui peut être un peu embêtant, c'est de ne pas avoir accès au canal alpha pour les 32 bits. Je vais essayer de rectifier le tir sans perdre trop de perf'.
Si je me sors de tout ça, on pourra en effet envisager une classe ( mais y'a encore du boulot :)
cs_MAURICIO Messages postés 2106 Date d'inscription mardi 10 décembre 2002 Statut Modérateur Dernière intervention 15 décembre 2014 5
11 août 2010 à 12:54
Sisi, j' avais remarqué!

j' ai pas encore commenté car je n' ai pas encore eu le temps de tester ...
Je suis assez d' accord avec toi: une unité/class réutilisable serait la bien venue.
Le fait de ne pas pouvoir utiliser des images autre que 24/32bits (il suffit de faire la conversion) m' embête un peu.

A+
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
11 août 2010 à 11:58
Vu / téléchargé :162 / 24

et personne n'a remarqué que le lien MSDN n'était pas bon !!!
http://msdn.microsoft.com/en-us/library/dd40721 2(VS.85).aspx

devient:

http://msdn.microsoft.com/en-us/library/dd407212(VS.85).aspx

le seul regret est que le code ne soit pas réutilisable tel quel.
on aurait pu, par exemple, surcharger TBitmap pour lui apporter cette méthode !!
Rejoignez-nous