Utilisateur anonyme
-
17 avril 2006 à 05:58
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);
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.
bob94700
Messages postés69Date d'inscriptionjeudi 13 février 2003StatutMembreDernière intervention 7 avril 20074 17 avril 2006 à 10:59
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;
}
}
MorpionMx
Messages postés3466Date d'inscriptionlundi 16 octobre 2000StatutMembreDernière intervention30 octobre 200857 17 avril 2006 à 11:10
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);
bob94700
Messages postés69Date d'inscriptionjeudi 13 février 2003StatutMembreDernière intervention 7 avril 20074 17 avril 2006 à 11:04
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.
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".
Vous n’avez pas trouvé la réponse que vous recherchez ?
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 ?
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 :
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 ?
bob94700
Messages postés69Date d'inscriptionjeudi 13 février 2003StatutMembreDernière intervention 7 avril 20074 18 avril 2006 à 18:58
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.
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.