Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

FILTRES ET MANIPULATION D'IMAGES EN UTILISANT LOCKBITS ET DES POINTEURS


Information sur la source

Catégorie :Graphique Source .NET ( DotNet ) Classé sous : filtre, image, lockbit, pointeur Niveau : Initié Date de création : 09/12/2004 Date de mise à jour : 11/12/2004 09:43:40 Vu / téléchargé: 9 846 / 644

Note :
7,67 / 10 - par 3 personnes
7,67 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (15)
Ajouter un commentaire et/ou une note

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

  • //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;
  • }
//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 !
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

09 décembre 2004 20:58:12 :
Ajout d'un zip et quelques corrections ^^
11 décembre 2004 09:43:40 :
Ajout des namespaces (et ui ça peut être utile ^^)

Commentaires et avis

signaler à un administrateur
Commentaire de yoannd le 09/12/2004 18:47:56

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.

signaler à un administrateur
Commentaire de yoannd le 09/12/2004 18:52:31

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.

signaler à un administrateur
Commentaire de li9 le 09/12/2004 21:18:05

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

signaler à un administrateur
Commentaire de yoannd le 10/12/2004 09:32:02

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 !

signaler à un administrateur
Commentaire de galinace le 11/12/2004 00:15:00

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

signaler à un administrateur
Commentaire de galinace le 11/12/2004 00:53:23

Re ....

Je viens de réaliser quelques tests entre ta methode et celle consistant à extraire le graphics du bitmap et travailler directement dessus.

Je me suis permis de modifier un peu ton source afin de laisser la possibilité d'importer une image et par suite remplacer celle par défaut. J'importe une bitmap de taille importante (105 Mo) afin de voir les temps de calculs et la mémoire prise (je suis sur un XP2000+ à 512 DDR).

L'application d'un filtre selon ta methode prend environ 6 à 7 secondes à pleine puissance (je parle ici de travail sans effet mémoire pour la possibilité d'annulation afin de ne pas être inflencé par des éventuel swappages).

La même opération effectuée sur une bitmap par extraction du graphics prends exactement le même temps.

Tout ceci pour pauser la question de l'utilité du mode "unsafe". C'est effectivement une question qui me tracasse pas mal car d'une part, le mode managé permet une certaine "sécurité" du code mais est sensé ralentir quelque peut l'exécution. Malheureusement pour moi, chaque exemple que je peux tester ne me permet pas réellement de trancher sur un mode plutôt que l'autre.

Pourrais tu m'éclarrer sur ton choix (travail en mode unsafe) et ton avis général sur la question ???

D'avance encore merci

signaler à un administrateur
Commentaire de li9 le 11/12/2004 09:41:43

Salut galinace,
on peut aussi utiliser les fonction "GetPixel()" et "SetPixel()" de la classe Bitmap pour travailler les pixels.
mais ces méthodes sont "très" lentes par rapport à l'utilisation de pointeurs.
Sur MSDN il y a un article interressant là dessus.
l'auteur y écrit qu'en Managed Code (getpixel,setpixel) son filtre Grayscale s'applique en 14sec. (enormement long mdr) , en Unmanaged (pointeurs) : 0.52sec  ; )

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp11152001.asp

par contre je vois pas trop ce que tu as fais pour ton test entre Managed et Unmanaged , tu extraits ton bitmap de 2 manieres differente et tu lui appliques mon filtre ? o_o

Sinon mon avis général sur la question c'est que l'étude des pointeurs va me permettre beaucoup de choses impossible à faire en managed code ^^"

wallou

++

signaler à un administrateur
Commentaire de kamal101 le 17/11/2005 21:44:16

Est-ce qu'il y a quelqu'un qui sait comment faire en c# la reconnaissance de forme. Je veux trouver des mini-cercles ronds dans une image et les mettre par exemple en noir. Est-ce qu'il y a une librairie pour ça ?

signaler à un administrateur
Commentaire de Warny le 26/03/2006 18:00:48

pour le fonction(i++) et le fonction(++i) le dotnet le compile en...
fonction(i); i = i+1;
et
i=i+1; fonction(i);
respectivement,
donc pour la vitesse, j'ai un doute ;)

signaler à un administrateur
Commentaire de Warny le 26/03/2006 19:20:54

Salut à nouveau,
Je me suis inspiré de ton code pour optimiser une déformation d'image (pour faire de l'assemblage horizontal de photo). C'est vrai que c'est nettement plus efficace. Merci beaucoup.

signaler à un administrateur
Commentaire de Equinox84 le 21/07/2006 10:33:25

Salut !

Merci pour ton code, il m'a permis d'inverser la couleur de mes graphiques avant l'impression, c'est tres pratique pour économiser le noir !

signaler à un administrateur
Commentaire de farias46 le 13/02/2007 10:37:24

Monstrueusement efficace !!! J'ai commencé le C# il y a 2 semaines environ et j'ai été très déçu par les performances de celui-ci sur les traitements d'images. En effet j'utilisais la méthode "managed" c'est-à-dire avec les GetPixel et SetPixel. J'arrivais à plus de 14sec pour parcourir une image de 800x600... celà uniquement pour passer celle-ci en négatif!
Avec le mode "unsafe", sur une belle image de la lune avec une petite résolution de 5900x3100 siouplé :-) tous mes filtres prennent maxi 3sec !
Un grand merci à toi pour ce joli code qui m'a fait découvrir la puissance des pointeurs ;-)!

signaler à un administrateur
Commentaire de olixelle le 13/12/2007 13:04:45

Salut,

je ne connaissais le mode unsage qu'en théorie, j'en ai eu besoin récement donc je me suis très largement inspiré de ton code pour comprendre le principe et le mettre en application donc merci :)

Remarque: Si vous souahitez gérer la transparence des png, passez en Format32bppARgb et remplacez les 3 par des 4 lors de la copie des pixels (une constante aurait été bienvenue)

en tout cas merci :)

signaler à un administrateur
Commentaire de phoenikz le 05/03/2008 08:37:57 10/10

J'ai réalisé un programme de traitement d'image à partir d'une webcam et ton code m'a énormément aidé pour passer en noir et blanc et compté les pixels de certaines couleurs, bref un grand merci  (enfin bon là j'ai 4 ans de retard mais c'est pas grave)

signaler à un administrateur
Commentaire de billegate2006 le 01/04/2008 16:31:34

Bonjour,
Je veux juste vous poser une question concernant le traitement d'images, bon je veux mettre une bar de zoom sur une image mais il faut quelle soit transparente comme la boussole du google earth, merci de votre reponse.

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Filtre imagelist [ par Monico9385 ] Bonjour tout le monde, j'ai un soucis sur le filtrage d'image. En fait, j'ai un ImageList associ&#233; &#224; un ListView, et j'aimerai lister que l Perte de référence dans fichier de ressource VS2003 [ par fregolo52 ] Bonjour, J'ai créé une appli avec des controles utilisateurs. Ils ont des bouton avec des images. Pour avoir un projet plus propre, j'ai créé des sou Image GIF [ par julbuttt ] Bonjour, j'aimerai charger une image GIF dans un tabPage afin de dessiner des lignes dessus comme dans le Graphe réseau dugestionnaire de taches de wi Faire un dispose de mon propre composant [ par fcolo ] Bonjour,j'ai r&#233;alis&#233; un composant personnel.Ce composant ne d&#233;rive pas de Form.J'ai cr&#233;er une classe vide pour le faire.Ce composa Suppression d'image [ par nico4nicolas ] Bonjour, Mon probleme est de supprimer une image, pour cela j'ai essaye trois methodes toutes aussi infructueuses, les voici : File.Delete(@"C:\TEMP Insérer un text dans une image BMP (C#) [ par Hammings ] Bonjour, Je souhaite ins&#233;rer un texte dans une image BMP, en consultant la doc C#, j'ai essay&#233; de proc&#233;d&#233; ainsi (mais malheureuse Inserer une image dans un fichier Excel [ par Tuizi ] Bonjour, Voila je viens de passer sous C# et donc j'ai un petit probl&#232;me avec Excel, en effet sous VB.NET j'arrive &#224; &#233;crire dans une ce enregistrement ASF fichier [ par gwenp68 ] Bonjours a tous. Je suis en train de faire un ptit programme de prévisualisation de caméra IP, qui tourne parfaitement. J'aimerais ajouter une option PictureBox sur Pocket PC [ par wald39 ] Bjr &#224; tous.J'aimerais afficher une image ronde avec les tours transparents dans une picturebox, je pense qu'il faut redessiner l'image sur la pic Obtenir la résolution d'une image et plus ... [ par Sloadfr ] Bonjour &#224; tous !Je cherche un moyen d'obtenir la r&#233;solution d'une image.De plus j'ai cru comprendre en recherchant des infos la dessus qu'il


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,406 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.