Filtres et manipulation d'images en utilisant lockbits et des pointeurs

Soyez le premier à donner votre avis sur cette source.

Vue 15 662 fois - Téléchargée 920 fois


Description

Le but de cet exemple est de montrer comment manipuler une image, en accédant aux données directement en mémoire via la fonction "Lockbits" des Bitmaps.
J'y inclus aussi un filtre d'Eclaircissement (Brightness) comme exemple , à vous de vous servir de votre imagination pour en trouver d'autre ;]
(ou si vous voulez pas chercher envoyez moi un mail ^^")

Source / Exemple :


//namespace
using System.Drawing;
using System.Drawing.Imaging;

//Cette fonction nous retourne une Image eclaircie
private static Image Brightness(Image ImageOrigine)
{
       //On créer donc un nouveau bitmap pour garder notre original intacte
       Bitmap bmp = new Bitmap(ImageOrigine,ImageOrigine.Width,ImageOrigine.Height);
       //C'est dans un BitmapData qu'on utilise Lockbits
       //On fait donc un Lockbits des données de notre Bitmap ....
       BitmapData bmpData = bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
       //Maintenant on collecte certaines informations ...
       int scanline = bmpData.Stride;   //le stride(appelé aussi scanline) est la largeur d'une rangée de pixels dans l'image;
       IntPtr scan0 = bmpData.Scan0; // le Scan0 nous indique où se trouve le 1er pixel en mémoire 

       unsafe // comme on utilise des pointeurs il faut indiquer qu'on code en "unsafe" mode  
       {
                // "p" sera donc notre pointeur 
                byte* p = (byte*)(void*)scan0;
                //on peut aussi écrire  "byte* p = (byte*)scan0.ToPointer();"
                
                //quelques variables nécéssaires
                int val;
                int nOffset = scanline-bmp.Width*3;
                int nWidth = bmp.Width*3;   //*3 parce qu'on travail des couleurs sur3 bytes "RGB"
                
                //C'est durant la prochaine boucle "for" qu'on travail nos pixels
                for(int  y = 0 ; y < bmp.Height ; ++y)
                {
                        for( int x = 0 ; x < nWidth ; ++x)
                        {
                               //on ajoute 50 (par ex.) pour rendre plus claire mais -50 , vous l'aurez deviné rendra l'image plus sombre !
                               val = (int)p[0]+50;
                               //on verifie que les valeurs ne dépasse pas 255 
                               if(val>255)val=255;
                               p[0]=(byte)val;
                               //on a donc augmenté la valeur du premier byte pour ce pixel , on passe au suivant
                               ++p; 
                        }
                         p+=nOffset;
                }
       }
        //notre modif effectuée on "relache" les données
        bmp.UnlockBits(bmpData);

        //On retourne l'image transformée :D
        return (Image)bmp;
}

Conclusion :


note : dans le traitement d'images, la rapidité est très importante , c'est une des raisons pour laquelle les pointeurs sont toujours utilisés dans ce domaine.
(aussi , vous noterez le "++i" au lieu de "i++" , en effet ++i est plus rapide à executer que "i++" en mémoire).

C'est ma premiere source de ce type , il est possible que j'ai fais quelques erreurs , si c'est le cas je m en excuse d'avance !!

Bon courage !

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
3
Alors, les erreurs, il y en a quelques une, en effet, mais rien de bien méchant :

Bitamp bmp = new Bitmap(ImageOrigine,ImageOrigin.Width,ImageOrigin.Height);

on préferrera déclarer un Bitmap plutot qu'un Bitamp et le vairable ImageOrigin n'existe pas, il faut écrire ImageOrigine

Je suppose que tu as voulu écrire ca
int nOffset = scanline-bmp.Width*3;

...à la place de
int nOffset = stride-bmp.Width*3;

Par contre, tu écris aussi ceci :
Image imgOut = Image.FromHBitmap(newBmp.GetHBitmap());
mais mon compilo ne trouve pas les fonction FromHBitmap et GetHBitmap. Est-ce qu'il me manque des using ? Ha non, je viens de voir que FromHbitmap avec un b minuscule fonctionnait, ainsi que GetHbitmap.

D'ailleurs, ce serait pas mal de les indiquer. Il me semble qu'il nous faut ici les using suivants :
using System.Drawing;
using System.Drawing.Imaging;

De plus, il ne me semble jamais avoir entendu que ++x et x++ étaient différents en terme de rapidité, mais la différence, c'est que si j'écris :
x = 3;
Console.WriteLine("" + (x++));
Ca m'affiche 3, puis ca incrémente de 1 la valeur x, alors que si j'écris :
Console.WriteLine("" + (++x));
ben ca incrémente de un la valeur x puis ca affiche 3+1, soit 4.

Bon, passons sur ceci, ce qui m'embète un peu plus, c'est que j'ai testé ce code, et ca me donne une image qui ne contient que des bandes grises et noires, bref, donc voila, heuuu, je crois qu'il y a un bug. En tout cas, c'est tout de même un contribution et ca peut peut-être aider quelqu'un, c'est le point positif de la chose. Mais c'est vrai qu'un petit zip, ca aurait été cool.
cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
3
Ha oui, dernier truc, tu écris ceci dans ton code:
byte* p = (byte*)(void*)scan0;
//on peut aussi écrire "byte* p = (byte*)scan0.ToPointer();"

Ben moi, il y a que
byte* p = (byte*)scan0.ToPointer();
... qui passe à la compilation.
li9
Messages postés
57
Date d'inscription
lundi 23 février 2004
Statut
Membre
Dernière intervention
11 septembre 2008
1
Merci pour ton commentaire.
Effectivement , y avait quelques fautes mdr ....
J'ai tout corrigé (je pense .... ) et j'ai rajouté un zip avec quelques filtres supplémentaires pour me faire pardonner v( ^_^ )v .

J'ai voulu faire le chaud et tout taper de tête en postant ma source , c'est à cause de ça qu'y avait autant de fautes ....j'aurais dû faire un vieux copier/coller xD

C'est vrai que j'aurais dû parler des namespaces ,
Je m'en excuse !!

Pour "++i" ou "i++" t'as peut être raison, je pensait avoir vu ça dans la version de msdn fournit dans vs.net ... à vérifier ...
et pour la déclar. du pointeur moi les 2 passent niquel o_O , mais je me sert que de "(byte*)(void*)scan0"
Réessayes avec la source de mon zip. : /
on sait jamais ...

Ciao
cs_yoannd
Messages postés
305
Date d'inscription
lundi 7 janvier 2002
Statut
Membre
Dernière intervention
10 août 2011
3
Putain là ouais, ca marche, et c'est nikel !
tu viens de donner pas mal de valeur à ta source là, d'un coup ! ben bravo, je trouve ca extra !
cs_galinace
Messages postés
2
Date d'inscription
mardi 15 avril 2003
Statut
Membre
Dernière intervention
11 décembre 2004

Bonjour,

Je viens de lire ton poste et ta methode me parrait effectivement intéressante.

J'aurais aimé avoir une sorte de comparatif ou tout du moins d'ordre d'idée concernant la différence de rapidité d'exécution entre le principe que tu décris (parcourt par pointeur etc) et le fait de rester en mode managé et dessiner la bitmap en passant par un objet "graphics".

Effectivement je ne parle pas là de modification de luminosité ou autre mais bien de dessin à proprement parler d'une bitmap. Je sais que ce n'est pas directement le sujet mais un rapport tout de même étroit m'a poussé a écrire ce poste.

Merci d'avance pour ta réponse

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.