DOWNSAMPLING OU COMMENT BIEN OPTIMISER LE CODE

Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 - 9 avril 2011 à 18:47
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 12 avril 2011 à 22:03
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/53046-downsampling-ou-comment-bien-optimiser-le-code

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
12 avril 2011 à 22:03
Salut ManChesTer, en fait seul la partie qui prend du temps est optimisée. Le reste comme le chargement de l'image ... bon. Mais on peut cdertainement l'optimiser, en effet comme tu le montres dans ton commentaire.

Et un try, oui, ça en a pas l'air mais ça ne prend pas plus de temps d'exécuter du code protégé par un try - il y a juste un flag quelque part qui dit au compilateur que tel code doit s'éxécuter à tout prix ou que telle exception doit être redirigée.

Cordialement, Bacterius !
cs_ManChesTer Messages postés 374 Date d'inscription vendredi 20 octobre 2000 Statut Modérateur Dernière intervention 15 janvier 2021
11 avril 2011 à 15:11
Salut Bacterius,

Bon code mais il est encore possible de l'optimisée

par exemple dans main :
# JPG := TJPEGImage.Create;
# JPG.LoadFromFile('Image.jpg');
# Bmp := TBitmap.Create;
# Bmp.Assign(JPG);
# Bmp.PixelFormat := pf32bit;
# Bmp2 := TBitmap.Create;
# JPG.Free;
me fais des frissons dans le dos,
un with TJPEGImage.Create do
...

dans la lib le try , c'est optimisé ca un try ?

Bon Coding...

ManChesTer.
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 avril 2011 à 22:57
Admettons :p

"Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol"
Eh oui, je sais même pas quoi faire des mes 4Go, j'ai l'impression de gaspiller :(

Cordialement, Bacterius !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
10 avril 2011 à 22:53
Quand tu programmeras un dessin animé avec quelques milliers de Bitmaps, tu changeras peut-être d'avis. :)

Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 avril 2011 à 22:47
Merci, ça sera bien utile pour le pf24bit ! :) Mais bon il reste un petit problème - les PC d'aujourd'hui sont tellement rapides que la différence entre 24 et 32 bits est négligeable - en fait le 32 bits irait plus vite à cause justement de l'alignement mémoire.

Je vais l'ajouter comme exercice et pour compatibilité, mais ça n'a que peu d'intérêt au niveau pratique (tous les bitmaps sont en 32 bits de nos jours).

Cordialement, Bacterius !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
10 avril 2011 à 22:38
Si tu te lances dans le pf24bit, je te file un petit truc qui te sera bien utile.
Ca calcule le nombre de Bytes par ligne de mémoire :

MemBytePerLine := (((BMP.Width * BytePerPix shl 3) + 31) and -31) shr 3;

« ...Et c'est la classe d'appeller VirtualAlloc »
Oui , c'est sûr ! :)
Tu me tentes...
Je vais me lancer ! ;)
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 avril 2011 à 22:19
"Et ton algo, en fin de ligne, ajoutera 18 aux Pointeurs pour sauter 1 ligne ( Inc(S1, W); Inc(S2, W); ) alors qu'il devrait ajouter 20 ==> foutoir assuré !"
C'est vrai. Il y a moyen de corriger ça en remplacant les Inc plus haut par des incrémentations arithmétiques prenant en compte l'alignement mémoire (à coup de mod - enfin de and pour la performance). Je vais creuser ça.

"Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)"
Ah ?? Ca ce n'est pas normal, je vais regarder ça, merci Cari :p

"Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar."
C'est pourtant bien utile quand on travaille avec des fichiers sans passer par le cache système :'( Et c'est la classe d'appeller VirtualAlloc :p

"J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)"
Héhé oui, il est vrai que la fonction PTR_Downsample pourrait être rendue plus complexe pour gérer les réductions par 2, 4, 8, etc... en un seul coup. Mais bon, je préférais laisser le code simple pour bien qu'on comprenne le truc des pointeurs.

Cordialement, Bacterius !
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
10 avril 2011 à 19:14
J'oubliais...
« Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. »

J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
10 avril 2011 à 18:54
« Pour le pf24bit, ce n'est pas vraiment un problème... »
Ce ne sera pas un problème à condition que tu ajoutes une nouvelle limitation. C'est à dire qu'il faudra des bitmaps dont la largeur est multiple de 4, sinon tu auras des problèmes d'alignement de fin de ligne.
Un petit exemple pour te faire comprendre :
Soit un pf24bit de 6 pixels de large.
Il a besoin de 3x6 = 18 Bytes par ligne pour coder ses 6 TRGBTriples.
Or la mémoire est alignée sur des Longwords de 4 bytes.
En mémoire, ce Bitmap occupera donc une largeur de 5 Longwords, soit 20 Bytes (et non pas 18 !).
Et ton algo, en fin de ligne, ajoutera 18 aux Pointeurs pour sauter 1 ligne ( Inc(S1, W); Inc(S2, W); ) alors qu'il devrait ajouter 20 ==> foutoir assuré !

« En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels... »
Au temps pour moi. Tu as raison, ton algo est de meilleur qualité.

« C'est normal pour TrackbarChange... »
Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)

« Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique... »
Le problème est qu'il n'existe pas de fonctions Stretch avec autant de limitations. Une "vraie" comparaison est donc impossible.
Quant à comparer la méthode des pointeur avec Get/SetDIBits, ça a déjà été fait et la palme revient à la méthode des pointeurs.

« saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc... »
Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar.
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 avril 2011 à 02:44
@Beckerich : super ! j'étais pas sûr avec tous ces pointeurs ...

@Caribensila : c'est vrai. Pour le pf24bit, ce n'est pas vraiment un problème à vrai dire, il suffit de changer le contenu des pointeurs et les mathématiques dans la boucle. Il n'y aurait pas de différence de performance importante.

Pour agrandir, c'est vrai, mais il ne faut pas oublier que les fonctions citées plus haut prennent un temps négligeable pour décider si il faut agrandir ou non, donc niveau performances ça n'a aucune importance. Niveau fonctionnalité, je te l'accorde. Pour tous les facteurs, effectivement, je te l'accorde, c'était un peu bas de ma part.

En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels, il prend simplement le pixel le plus proche. Donc si tu essayes de faire ça, dans les mêmes conditions, avec le Stretch de Delphi, tu verras que ça sera pas la même qualité (en tout cas dans Delphi 6 et 7, ça a peut-être changé dans les versions ultérieures).

C'est normal pour TrackbarChange, Downsample réduit l'image d'un facteur de deux, on l'appelle plusieurs fois pour obtenir une réduction plus importante. C'est voulu. Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. Si ça avait été 4 fois plus lent j'aurai fait différemment.

Et oui je reconnais que ma clause try/except n'est pas terrible :( Mais bon, qui a des erreurs EOutOfMemory de nos jours :p

Merci pour tes remarques. Je vais particulièrement me pencher sur le problème du GetMem afin de corriger ça.

Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique, avec les mêmes conditions, mais utilisant Pixels par exemple ou Get/SetDIBits ? Ce serait alors honnête (je crois)

Cordialement, Bacterius !

PS : saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc avec MEM_COMMIT ne libère pas la mémoire correctement ? J'avais en tête d'utiliser ces fonctions pour obtenir une plage mémoire alignée pour que le CopyMemory aille plus vite, mais la mémoire ne se libérait pas proprement.
beckerich Messages postés 302 Date d'inscription jeudi 29 septembre 2005 Statut Membre Dernière intervention 17 septembre 2013 2
9 avril 2011 à 20:12
Bonsoir,

le code fonctionne sans modif sous delphi2010. Luc.
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
9 avril 2011 à 18:47
Salut,

Ton bench n'est pas très honnête car tu compares ta fonction à des fonctions qui font bien plus de choses. C'est heureux que tu sois plus rapide dans ces conditions !

Si ta fonction devait aussi pouvoir
- agrandir
- traiter le pf24bit et autres formats
- accepter n'importe quelles largeurs de bitmap
- s'adapter à tous les facteurs d'agrandissement, même non entiers
- et j'en passe,
je te fiche mon billet que tu n'obtiendrais pas le même classement de performances.

Quand à la qualité, essaie d'utiliser le simple Stretch de Delphi dans les mêmes conditions, c'est à dire 1 bitmaps pf32bit de largeur et hauteur paires et avec un facteur de réduction de 4, 16, 64, etc... , je serais étonné que tu n'obtiennes pas exactement la même qualité.

TrackbarChange appelle 4 fois la fonction Downsample pour une réduction. Y'a quelque chose qui ne colle pas.

Ton GetMem(D, Q) est placé après le try. Si ton GetMem échoue, FreeMem est quand même appelé !

Sinon, c'est pas mal pour montrer l'utilisation des pointeurs.
Rejoignez-nous