Frédéric Mélantois
Manipulation d'images en VB.NET et C#
Nous étudierons les différentes manières d'accéder rapidement aux pixels d'une image, aussi bien en C# qu'en VB.NET. Un passage en revue des principaux formats d'images vous sera proposé.
Par Frédéric Mélantois publié le 18/10/2006 à 22:27, lu 14932 fois, 9 pages
 3 | L'accès au pixel en VB.NET
Le langage VB.NET ne possède malheureusement pas de pointeurs. Il faut donc trouver une autre manière d'accéder aux données non managées de l'image. L'utilisation de la classe Marshall va nous permettre de palier à ce problème. Celle-ci se trouve dans l'espace de noms « System.Runtime.InteropServices ». Voici un exemple d'utilisation :

Dim width As Integer = bitmap.Width

        Dim height As Integer = bitmap.Height

 

        Dim bmpData As BitmapData = bitmap.LockBits(New Rectangle(0, 0, width, height) _

            , System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)

 

        Marshal.WriteByte(bmpData.Scan0, bmpData.Stride, 255)

        Marshal.WriteByte(bmpData.Scan0, bmpData.Stride + 4, 0)

 

        bitmap.UnlockBits(bmpData)

Dans le code précédent, nous avons modifié le premier octet en portant sa valeur à 255 puis nous affectons la valeur 0 au cinquième octet. Cette manière de procéder bien que plus rapide que l'utilisation de la méthode « SetPixel » de la classe Bitmap montre très vite ses limites par rapport au langage C#. Voici un exemple de code permettant d'inverser les composantes Rouge et Verte d'une image :

Dim width As Integer = bitmap.Width

        Dim height As Integer = bitmap.Height

 

        Dim bmpData As BitmapData = bitmap.LockBits(New Rectangle(0, 0, width, height) _

        , System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)

 

        Dim swap As Byte

 

        For y = 0 To height - 1

 

            For x = 0 To width - 1

 

                swap = Marshal.ReadByte(bmpData.Scan0, (bmpData.Stride * y) + (4 * x) + 2)

 

                Marshal.WriteByte(bmpData.Scan0, (bmpData.Stride * y) + (4 * x) + 2 _

                , Marshal.ReadByte(bmpData.Scan0, (bmpData.Stride * y) + (4 * x) + 1))

 

                Marshal.WriteByte(bmpData.Scan0, (bmpData.Stride * y) + (4 * x) + 1, swap)

            Next

 

        Next

 

        bitmap.UnlockBits(bmpData)

Vous pouvez comparer par rapport à l'équivalent C# un peu plus loin dans cet article. Le temps de traitement est catastrophique.Essayons de voir comment nous pourrions améliorer les performances. Ce qui coûte c'est de faire du marshalling byte à byte. Il nous faut trouver un moyen d'extraire des blocs d'octets comme nous pouvons le faire avec d'autres langages ne faisant pas partie de la plateforme .NET. En fait, la classe « Marshal » possède une méthode permettant de copier un ensemble d'octets. Mettons en pratique en modifiant le code précédent.

Dim x As Integer

        Dim y As Integer

 

        Dim width As Integer = bitmap.Width

        Dim height As Integer = bitmap.Height

 

        Dim bmpData As BitmapData = bitmap.LockBits(New Rectangle(0, 0, width, height) _

        , System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)

 

        Dim newPixel(width * height * 4 - 1) As Byte

 

        Marshal.Copy(bmpData.Scan0, newPixel, 0, newPixel.Length)

 

        Dim swap As Byte

 

        For y = 0 To height - 1

 

            For x = 0 To width - 1

 

                swap = newPixel((width * y + x) * 4 + 2)

 

                newPixel((width * y + x) * 4 + 2) _

                  = newPixel((width * y + x) * 4 + 1)

 

                newPixel((width * y + x) * 4 + 1) = swap

 

            Next

 

        Next

 

        Marshal.Copy(newPixel, 0, bmpData.Scan0, newPixel.Length)

 

        bitmap.UnlockBits(bmpData)

Le principe est simple. On définit un tableau d'octets que l'on remplit par la méthode « Copy » de la classe « Marshal ». On travaille en contexte managé sur les octets du tableau puis une fois les modifications apportées, par la méthode « Copy », on copie le tableau d'octet vers l'emplacement mémoire initial puisque celui-ci est fixe dans le contexte non-managé.
Avec ce procédé, il faut bien faire attention à ne pas charger de trop grosses images. En terme de performance, écrire en C# permet d'obtenir de meilleurs résultats qu'en VB.NET. Mais le développeur VB.NET doit savoir mesurer l'importance de cette performance par rapport à l'application qu'il développe, tout comme le développeur C# doit le faire par rapport au développement en C à l'ancienne. En effet, si votre application est un logiciel de traitement d'images qui doit répondre à de grandes exigeances de performance, vous ne développerez pas sous la plateforme .NET. Si vous développez simplement une fonction de transformation d'images occassionnelle, un développement VB.NET peut s'avérer amplement suffisant.
 
» Démarrer une discussion
 
Discussion démarée par vattic le 11/04/2011 à 11:02, 1 commentaire(s).
Discussion démarée par olibara le 18/08/2008 à 00:12, 2 commentaire(s).