Modification rapide d'un Bitmap
Les méthodes GetPixel et SetPixel de l'objet Bitmap ont la particularité d'être à la fois très simples d'utilisation, et très lentes. Voici donc une petite classe qui encapsule un Bitmap pour optimiser tout ça.
|
|
Vu
2872
fois
|
Le principe de fonctionnement
Il existe une méthode de l'objet Bitmap appelée LockBits, qui permet de récupérer un objet BitmapData, lequel est d'un formalisme très simple. Il se présente ainsi :

Pour travailler l'image, il nous suffit donc d'aller lire et écrire dans cette matrice. Pour ce faire, nous allons créer un objet BitmapRapide implémentant les méthodes suivantes :
- Un constructeur prenant en paramètre un Bitmap
- Des méthodes GetPixel et SetPixel identiques à celles de l'objet Bitmap
- Un accesseur Image renvoyant un objet Bitmap
Construction de l'objet BitmapRapide
Le principe est ici de récupérer et de stocker la matrice correspondant au Bitmap passé en paramètre du constructeur :
private int largeur = 0; private int decalage = 0; private int hauteur = 0; private byte[] matrice;
public BitmapRapide(Bitmap image) { this.largeur = image.Width; this.decalage = (this.largeur * 3) + this.largeur%4; this.hauteur = image.Height; Rectangle bounds = new Rectangle(0, 0, this.largeur, this.hauteur); BitmapData bitmapData = image.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
this.matrice = new byte[this.hauteur * bitmapData.Stride]; System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, matrice, 0, matrice.Length - 1); image.UnlockBits(bitmapData); } |
La variable "decalage" va permettre de passer d'une ligne à l'autre, en tenant compte des éventuels octets inutilisés en fin de ligne.
Récupération et mise à jour des Pixels
L'objet Bitmap est à présent conservé dans notre matrice, et c'est donc sur cette matrice que nous allons travailler directement.
Récupération de la couleur d'un Pixel dans la matrice :
public Color GetPixel(int x, int y) { byte bleu = matrice[(x * 3) + (y * this.decalage)]; byte vert = matrice[((x * 3) + 1) + (y * this.decalage)]; byte rouge = matrice[((x * 3) + 2) + (y * this.decalage)];
return Color.FromArgb(rouge, vert, bleu); } |
Mise à jour de la couleur d'un pixel dans la matrice :
public void SetPixel(int x, int y, Color couleur) { matrice[(x * 3) + (y * this.decalage)] = couleur.B; matrice[((x * 3) + 1) + (y * this.decalage)] = couleur.G; matrice[((x * 3) + 2) + (y * this.decalage)] = couleur.R; } |
Reconstruction du Bitmap
Et pour finir, il nous faut un accesseur sur notre objet Bitmap modifié. Il suffit pour cela de reconvertir notre BitmapData en Bitmap :
public Bitmap Image { get { Bitmap image = new Bitmap(this.largeur, this.hauteur, PixelFormat.Format24bppRgb);
Rectangle bounds = new Rectangle(0, 0, this.largeur, this.hauteur); BitmapData bitmapData = image.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
System.Runtime.InteropServices.Marshal.Copy(matrice, 0, bitmapData.Scan0, matrice.Length - 1); image.UnlockBits(bitmapData); return image; } } |
Comparaison des performances
Pour comparer les performances, nous allons effectuer des copies intégrales de Bitmaps de différentes tailles. Le temps de construction de l'objet BitmapRapide et de reconstruction de l'objet Bitmap est évidemment à prendre en compte.

On constate que BitmapRapide permet de modifier les objets Bitmap environ 3,5 fois plus vite qu'en utilisant l'objet Bitmap standard, et ce quelque soit la taille de l'image.
On constate également qu'une durée de plus de 6 secondes pour le traitement d'une image complète de 10 millions de Pixel implique de toujours utiliser ces méthodes avec parcimonie.
|