Analyse d'une zone de l'image [Résolu]

- 17 avril 2006 à 05:58 - Dernière réponse :  Utilisateur anonyme - 19 avril 2006 à 06:27
Bonjour,



Dans mon application, je dois analyser une image et la couleur de ses
pixels, cela est facilement realisable par la methode GetPixel() mais
pour des raisons de rapidite, il est preferable d'utiliser du code
unsafe auquel, je dois le reconnaitre, je n'ai pas tout tout compris.
Mon probleme est que je dois adapter mon code pour laisser la
possibilite a l'utilisateur de n'analyser qu'une partie de l'image et
je n'arrive pas a adapter le code unsafe pour cet emploi, voici le code
:



// Create a new bitmap picture to work on it


Bitmap bmp = new
Bitmap(blackandwhite,blackandwhite.Width,blackandwhite.Height);

// It's in a BitmapData where Lockbits is used


// So we do data Lockbits of our bitmap


System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(newRectangle(0,0,bmp.Width,bmp.Height),System.Drawing.Imaging.ImageLockMode.ReadOnly,System.Drawing.Imaging.PixelFormat.Format24bppRgb);

// Now take some informations


int scanline = bmpData.Stride; // stride (or
scanline) is the widthof a pixels row in this picture


IntPtr scan0 = bmpData.Scan0; // Scan0 indicate
where is the first pixel in the memory



long alpha = 0;




// To be faster, we must use pointers and to use
pointers

// We need to code the program in "unsafe" mode

unsafe

{

// "p" will be the pointer

byte* p = (byte*)(void*)scan0;


// It's also possible to write :
"byte* p = (byte*)scan0.ToPointer();"




int nOffset =
scanline-bmp.Width*3;

int nWidth = bmp.Width*3;

byte r; // red

byte g; // green

byte b; // blue



// For each pixel in the height


for(int y = 0 ; y < Height ;
++y)

{


// For each
pixel in the width


for( int x = 0
; x < nWidth ; ++x)

{



b = p[0];



g = p[1];



r = p[2];



// If the pixel is white



if(r 255 && g 255 & b == 255)



{



++alpha;



}



++p;

}

p+=nOffset;

}

}

// When it's done, slacken data

bmp.UnlockBits(bmpData);

bmp.Dispose();



Si vous pouviez m'indiquer comment modifier le code pour pouvoir
analyser une zone de selection predefinie en expliquant le pourquoi, je
vous en serais tres reconnaissant.
Afficher la suite 

Votre réponse

12 réponses

Meilleure réponse
Messages postés
69
Date d'inscription
jeudi 13 février 2003
Dernière intervention
7 avril 2007
17 avril 2006 à 10:59
3
Merci
Salut,
Essaye ce bout de code :

private void TestFunction (Image SrcImg, Rectangle Zone)
{
// Create a new bitmap picture to work on it
Bitmap bmp = new Bitmap(SrcImg, SrcImg.Width, SrcImg.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height),System.Drawing.Imaging.ImageLockMode.ReadWrite,System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int scanline = bmpData.Stride; // stride (or scanline) is the widthof a pixels row in this picture
IntPtr scan0 = bmpData.Scan0; // Scan0 indicate where is the first pixel in the memory
long alpha = 0;

unsafe
{
// "p" will be the pointer
byte* p = (byte*) scan0.ToPointer();
int nOffset = scanline - 3 * Zone.Width;
byte r; // red
byte g; // green
byte b; // blue
int y, x;

// Point de départ dans le tableau de pixel en fonction de la zone demandée et de la taille de l'image :
p += 3 * (Zone.X + Zone.Y * SrcImg.Width);

for(y = 0 ; y < Zone.Height ; ++y)
{
// For each pixel in the width
for(x = 0 ; x < Zone.Width ; ++x)
{
b = *p++; // Recupère la valeur, puis déplace le pointeur de 1
g = *p++;
r = *p++;
// If the pixel is white if(r 255 && g 255 & b == 255)
{
++alpha;
}
// On incrémente de 3 car on est en Format24bppRgb et on évite les recouvrement entre les points !
// inutile si on définit b = *p++; etc...
// p += 3;
}
p+=nOffset;
}
}

bmp.UnlockBits(bmpData);
bmp.Dispose();
}

Merci bob94700 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 90 internautes ce mois-ci

Commenter la réponse de bob94700
Meilleure réponse
Messages postés
3489
Date d'inscription
lundi 16 octobre 2000
Dernière intervention
30 octobre 2008
17 avril 2006 à 11:10
3
Merci
Oui, voila, plus simplement

Ou alors tu clone ton image

// Pour travailler sur un rectangle de 100 * 100 a partir de la position (0;0)
bmp = bmp.Clone(
new
Rectangle(0, 0, 100, 100),
PixelFormat.Format24bppRgb);



Mx
MVP C#

Merci MorpionMx 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 90 internautes ce mois-ci

Commenter la réponse de MorpionMx
Messages postés
69
Date d'inscription
jeudi 13 février 2003
Dernière intervention
7 avril 2007
17 avril 2006 à 11:04
0
Merci
Je me demande si plus simplement :
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(Zone, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

ne suffirait pas ... et tu travailles sur la totalité de la zone.
Commenter la réponse de bob94700
18 avril 2006 à 04:32
0
Merci
La deuxieme methode est beaucoup plus simple et fonctionne tres bien
quand on a pour pixel de depart le pixel (0,0) par contre, si on veut
selectionner une zone au milieu, par exemple (100,100,200,200), je ne
comprends pas pourquoi mais la fonction de clonage ne se fait pas, le
programme fait une exception "OutOfMemory".
Commenter la réponse de Utilisateur anonyme
18 avril 2006 à 04:57
0
Merci
Merci pour le code et les explications bob94700, mais je ne comprends pas bien le sens de cette ligne de code :



// Point de départ dans le tableau de pixel en fonction de la zone demandée et de la taille de l'image :


p += 3 * (Zone.X + Zone.Y *
SrcImg.Width);



Il est ecrit ce qu'elle fait mais...pourquoi cette addition des
coordonnees et cette multiplication avec la largeur de l'image source ?
Commenter la réponse de Utilisateur anonyme
18 avril 2006 à 05:42
0
Merci
J'ai un autre probleme avec le code fournit, quand j'essaye de lire la
taille de la "Zone" (Zone.Height et Zone.Width) qui un rectangle que je
definie en fonction des choix de l'utilisateur. Si je lis la taille
dans la partie de code unsafe, j'obtiens toujours 0 alors que
si je lis la taille de la zone dans un autre endroit du programme,
j'obtiens bien le bon resultat. Le probleme est donc que le traitement,
qui est dans la partie de code unsafe doit se faire sur une image null donc autant dire que le traitement ne fonctionne pas. Serais je passe a cote de quelque chose ?
Commenter la réponse de Utilisateur anonyme
18 avril 2006 à 07:07
0
Merci
Pour le premier des messages, j'ai compris mon erreur, je definissais
les coordonnes de la fin de ma zone de selection au lieu de definir la
largeur et la longueur (erreur stupide s'il en est). En effet, le code
etait tres simple a modifier, je vous remercie pour votre aide mais je
n'ai pas compris comment cette ligne fonctionne :



p += 3 * (Zone.X + Zone.Y * SrcImg.Width);
Commenter la réponse de Utilisateur anonyme
18 avril 2006 à 09:15
0
Merci
Euh...c'est encore remoi, j'ai un autre probleme



J'execute cette petite partie de code dans un try catch et a chaque
execution, le prog trouve une exception on moment ou on recupere la
valeur et decale le pointeur. L'intitule exacte de l'exception est
Object reference is not set to an instance of an object. Une idee
sur ce que c'est ?
Commenter la réponse de Utilisateur anonyme
Messages postés
69
Date d'inscription
jeudi 13 février 2003
Dernière intervention
7 avril 2007
18 avril 2006 à 18:58
0
Merci
bonjour,
p est intialisé à : (byte*) scan0.ToPointer();
ce qui correspond au début du tableau qui représente l'image (le 1er point en quelque sorte).

Ce tableau contient w * h * 3 éléments (largeur * hauteur * nbre de byte par pixel, soit 3 en rvb24).

Maintenant si on commence au point de coordonnée (x,y) il faut se décaller d'un certains nombre point.
Ce nombre de point est :
le nbre de ligne entière qu'il faut passer, soit : y*w (on est en base 0)
+ le coordonnée x pour la dernière ligne : x
donc un total de : w*y + x
comme on est en rvb24, on multiplie le tout par 3 (byte par pixel). D'où le décalage de p avant la boucle.

L'erreur indique qu'une instance a la valeur "null". Ni ces propriétés, ni ces méthodes ne peuvent être utilisées. Maintenant, comme ça je ne sais pas quelle variable est "null". trace en débug tu devrais le voir très vite.
Commenter la réponse de bob94700
Messages postés
69
Date d'inscription
jeudi 13 février 2003
Dernière intervention
7 avril 2007
18 avril 2006 à 19:01
0
Merci
j'ai qd même un doute sur ton image : es-tu sûr qu'elle n'est pas null ? si c'est le cas, ajoute un
if (SrcImg == null)
return;

en début de la méthode.
Commenter la réponse de bob94700
19 avril 2006 à 04:31
0
Merci
Merci beaucoup pour ces precisions, je suis certain d'avoir compris comment fonctionne le code maintenant.



Pour ce qui est de l'erreur, c'est ma faute, je veux aller trop vite et
j'en oublie, j'ai reussi a la corriger mais seuleument en partie car
elle reapparait certaines fois dans le programme, je ne sais pas ce qui
la declenche mais je vais chercher. Je te remercie pour ta tres
precieuse aide. Merci beaucoup.
Commenter la réponse de Utilisateur anonyme
19 avril 2006 à 06:27
0
Merci
Mais je suis certain que l'image n'est pas null etant donne que l'analyse est OK et que je peux l'afficher.
Commenter la réponse de Utilisateur anonyme

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.